package com.sf.vertx;

import java.util.concurrent.atomic.AtomicReference;

import org.junit.Test;

import com.alibaba.fastjson2.JSONObject;
import com.sf.vertx.handle.ProxyHandlerImpl;
import com.sf.vertx.security.MainSecurity;

import io.vertx.core.AsyncResult;
import io.vertx.core.Future;
import io.vertx.core.Vertx;
import io.vertx.core.VertxOptions;
import io.vertx.core.buffer.Buffer;
import io.vertx.core.eventbus.EventBus;
import io.vertx.core.eventbus.MessageConsumer;
import io.vertx.core.http.HttpClient;
import io.vertx.core.http.HttpClientOptions;
import io.vertx.core.http.HttpServer;
import io.vertx.core.http.HttpServerRequest;
import io.vertx.core.json.JsonObject;
import io.vertx.core.net.SocketAddress;
import io.vertx.ext.web.Router;
import io.vertx.ext.web.client.WebClient;
import io.vertx.ext.web.handler.BodyHandler;
import io.vertx.ext.web.proxy.handler.ProxyHandler;
import io.vertx.httpproxy.Body;
import io.vertx.httpproxy.HttpProxy;
import io.vertx.httpproxy.ProxyContext;
import io.vertx.httpproxy.ProxyInterceptor;
import io.vertx.httpproxy.ProxyRequest;
import io.vertx.httpproxy.ProxyResponse;
import lombok.extern.slf4j.Slf4j;

@Slf4j
public class TestProxy {
	public static void main(String[] args) {
		// promiseTest();
		routeUrilRewrite();
	}

	public static void eventBus() {
		// 创建vertx服务
		Vertx VERTX = Vertx.vertx(new VertxOptions().setWorkerPoolSize(100));
		EventBus eb = VERTX.eventBus();
		MessageConsumer<String> consumer = eb.consumer("news.uk.sport");
		consumer.handler(message -> {
		  System.out.println("I have received a message: " + message.body());
		});
	}

	/***
	 * 测试url重写, 入口/appCode/xxxx/xxx, 转换为/xxxx/xxx
	 */
	@Test
	public static void routeUrilRewrite() {
		// 创建vertx服务
		Vertx VERTX = Vertx.vertx(new VertxOptions().setWorkerPoolSize(100));
		// 创建HTTP监听
		HttpServer server = VERTX.createHttpServer();
		Router mainHttpRouter = Router.router(VERTX);
		server.requestHandler(mainHttpRouter).listen(7788, h -> {
			if (h.succeeded()) {
				log.info("HTTP端口监听成功");
			} else {
				log.error("HTTP端口监听失败");
			}
		});
		
		

		HttpClientOptions clientOptions = new HttpClientOptions();
		clientOptions.setMaxPoolSize(20); // 最大连接池大小
		clientOptions.setConnectTimeout(5000); // 连接超时 毫秒
		clientOptions.setHttp2KeepAliveTimeout(1);
		clientOptions.setIdleTimeout(1000); // 连接空闲超时 毫秒
		HttpClient proxyClient = VERTX.createHttpClient(clientOptions);
		HttpProxy proxy = HttpProxy.reverseProxy(proxyClient);

		proxy.originSelector(request -> Future.succeededFuture(resolveOriginAddress(request)));
		ProxyHandler sfProxyHandler = ProxyHandler.create(proxy);
		WebClient mainWebClient = WebClient.create(VERTX);
		proxy.addInterceptor(new ProxyInterceptor() {
//			@Override
//			public Future<ProxyResponse> handleProxyRequest(ProxyContext context) {
//				ProxyHandlerImpl sfProxyHandlerImpl = (ProxyHandlerImpl) sfProxyHandler;
				// String body = sfProxyHandlerImpl.getCtx().getBodyAsString();
				// log.info("ctx.getBodyAsJson():{}", body);
				//JsonObject bodyJson = sfProxyHandlerImpl.getCtx().getBodyAsJson();
				//HttpServerRequest HttpServerRequest = context.request().proxiedRequest();
				// 解密
				//String data = MainSecurity.aesDecrypt(bodyJson.getString("data"), "dadddsdfadfadsfa33323223");
				//bodyJson.put("data", data);
				// end解密
				// uri重写
				// context.request().setURI("/vertx/body");
//				return Future.future(p -> {
//					mainWebClient.postAbs("http://localhost:9198/vertx/body").sendJson(bodyJson.toString(), h -> {
//						if (h.succeeded()) {
//							ProxyRequest proxyRequest = context.request();
//							// 释放资源
//							proxyRequest.release();
//							JsonObject responseData = h.result().bodyAsJsonObject();
//							// responseData.toBuffer()
//							// 加密
//							String dataStr = MainSecurity.aesEncrypt(responseData.toString(),
//									"dadddsdfadfadsfa33323223");
//							log.info("dataStr:{}", dataStr);
//							Buffer buffer = Buffer.buffer(dataStr);
//							// end 加密
//							ProxyResponse proxyResponse = proxyRequest.response().setStatusCode(200)
//									.putHeader("content-type", "application/json").setBody(Body.body(buffer));
//							p.complete(proxyResponse);
//						} else {
//							p.fail(h.cause());
//						}
//					});
//				});
//			}
		});
		// mainHttpRouter.route().handler(sfProxyHandler);
		mainHttpRouter.route().handler(BodyHandler.create()).handler(sfProxyHandler);
	}

	@Test
	public static void promiseTest() {
		System.out.println("sddfs");
		// 从redis读取所有数据初始化动态代理
		// 创建vertx服务
		log.info("thread:{}", Thread.currentThread().getName());
		Vertx vertx = Vertx.vertx(new VertxOptions().setWorkerPoolSize(100));
		vertx.executeBlocking(promise -> {
			// 调用阻塞的、需要消耗显著执行时间的API
			String result = "fdfadsfsddf";
			log.info("The result is:{}", result);
			log.info("thread1:{}", Thread.currentThread().getName());
			promise.complete(result);
		}, res -> {
			log.info("The result res is:{}", res.result());
			log.info("thread2:{}", Thread.currentThread().getName());
		});
		log.info("end");
		log.info("thread3:{}", Thread.currentThread().getName());
	}

	/***
	 * 从redis读取所有数据初始化动态代理
	 */
	public void startLoadData() {
		// 从redis读取所有数据初始化动态代理
		// 创建vertx服务
		Vertx VERTX = Vertx.vertx(new VertxOptions().setWorkerPoolSize(100));
		// 创建HTTP监听
		HttpServer server = VERTX.createHttpServer();
		Router mainHttpRouter = Router.router(VERTX);

		server.requestHandler(mainHttpRouter).listen(7788, h -> {
			if (h.succeeded()) {
				log.info("HTTP端口监听成功");
			} else {
				log.error("HTTP端口监听失败");
			}
		});
		// 放最后, 不匹配. 反向代理, 透传
		HttpClientOptions clientOptions = new HttpClientOptions();
		clientOptions.setMaxPoolSize(20); // 最大连接池大小
		clientOptions.setConnectTimeout(5000); // 连接超时 毫秒
		clientOptions.setHttp2KeepAliveTimeout(1);
		clientOptions.setIdleTimeout(1000); // 连接空闲超时 毫秒
		HttpClient proxyClient = VERTX.createHttpClient(clientOptions);
		HttpProxy proxy = HttpProxy.reverseProxy(proxyClient);
		proxy.originSelector(request -> Future.succeededFuture(resolveOriginAddress(request)));
		// mock数据
				proxy.addInterceptor(new ProxyInterceptor() {
					@Override
					public Future<ProxyResponse> handleProxyRequest(ProxyContext context) {
						ProxyRequest proxyRequest = context.request();
						// 释放资源
						proxyRequest.release();
						// 创建一个响应并设置参数
						ProxyResponse proxyResponse = proxyRequest.response().setStatusCode(200)
								.putHeader("content-type", "text/plain").setBody(Body.body(Buffer.buffer("Hello World")));
						return Future.succeededFuture(proxyResponse);
					}
				});
		proxy.addInterceptor(new ProxyInterceptor() {
			@Override
			public Future<ProxyResponse> handleProxyRequest(ProxyContext context) {

				ProxyRequest request = context.request();
				request.proxiedRequest().headers().forEach(header -> {
					String name = header.getKey();
					String value = header.getValue();
					System.out.println("name:" + name + ";value:" + value);
				});
				// mockBody(request);
				// readBody(context, request);
				AtomicReference<String> reference = new AtomicReference<>();
//			    CompletableFuture<Void> future = VertxCompletableFuture.runBlockingAsync(VERTX, () ->
//			        reference.set(Thread.currentThread().getName()));
				// CompletableFuture<Void> future =
				// VertxCompletableFuture.runBlockingAsync(VERTX, () ->

//				VertxCompletableFuture<Integer> bodyFuture = new VertxCompletableFuture<>(VERTX);
//				Thread thread = Thread.currentThread();
//				log.info("VERTX thread:{}", thread.getName());
//				//VERTX.runOnContext(action -> {
//					log.info("thread:{}", Thread.currentThread().getName());
//					request.proxiedRequest().bodyHandler(buff -> {
//					      JsonObject jsonObject = buff.toJsonObject();
//					      log.info("body:{}", jsonObject.toString());
//					      log.info("thread1:{}", Thread.currentThread().getName());
//					      bodyFuture.complete(1);
//					});
//					VertxCompletableFuture.allOf(VERTX, bodyFuture).thenApply(v -> bodyFuture.join())
//			        .thenAccept(i -> {
//			          System.out.println("bodyFuture.isDone():"+bodyFuture.isDone());
//			          log.info("thread2:{}", Thread.currentThread().getName());
//			        }).whenCompleteAsync((res, err) -> {
//			        	log.info("thread3:{}", Thread.currentThread().getName());
//			        	log.info("VERTX thread:{}", thread.getName());
//			        	thread.notify();
//			        });
				// });

				log.info("VERTX thread4:{}", Thread.currentThread().getName());
				log.info("=====end:{}");
				return context.sendRequest();
			}

			@Override
			public Future<Void> handleProxyResponse(ProxyContext context) {
				// ProxyResponse proxyResponse = context.response();
				// Body body = proxyResponse.getBody();
				// 继续拦截链
				return context.sendResponse();
			}
		});
		 mainHttpRouter.route().handler(BodyHandler.create()).handler(ProxyHandler.create(proxy));
		mainHttpRouter.route().handler(ProxyHandler.create(proxy));
		// mainHttpRouter.route().blockingHandler(ProxyHandler.create(proxy));
		// mainHttpRouter.routeWithRegex("\\/vertx/*").handler(ProxyHandler.create(proxy));
	}

	/***
	 * 不行, 解析body未完成,body已经发送
	 * 
	 * @param context
	 * @param request
	 */
	private static void readBody(ProxyContext context, ProxyRequest request, AtomicReference<String> reference) {
		Future<Buffer> future = request.proxiedRequest().body();
		future.onComplete((AsyncResult<Buffer> ar) -> {
			if (ar.succeeded()) {
				Buffer buffer = ar.result();
				System.out.println("buffer = " + buffer.toString());
				// 加解密----------------------------------
				JSONObject bodyJson = JSONObject.parseObject(buffer.toString());
				String dataStr = null;
				// 参数解密
				String data = MainSecurity.aesDecrypt(bodyJson.getString("data"), "dadddsdfadfadsfa33323223");
				bodyJson.put("data", data);
				System.out.println("参数解密 data.toString():" + data.toString());
				dataStr = data;
				byte[] srtbyte = dataStr.getBytes();
				System.out.println("modify init byte len: " + srtbyte.length);
				Buffer bodyBuffer = Buffer.buffer();
				bodyBuffer.appendBytes(srtbyte);
				request.setBody(Body.body(bodyBuffer));
				request.proxiedRequest().headers().remove("Content-Length");
				request.proxiedRequest().headers().add("Content-Length", String.valueOf(srtbyte.length));
			} else {
				System.out.println("Failure: " + ar.cause().getMessage());
			}
			System.out.println("bodyFuture.complete = ");
		}).onSuccess(msg -> {
			reference.set(Thread.currentThread().getName());
			reference.notifyAll();
		});
	}

	public static SocketAddress resolveOriginAddress(HttpServerRequest request) {
		SocketAddress socketAddress = SocketAddress.inetSocketAddress(9198, "127.0.0.1");
		System.out.println("负载均衡跳转地址:" + socketAddress.host() + ";" + socketAddress.port());
		return socketAddress;
	}

	private static void mockBody(ProxyRequest request) {
		Buffer expected = Buffer.buffer();
		expected.appendString("{\n" + "    \"errorCode\": \"test\",\n" + "    \"result\": 10,\n" + "    \"data\": {\n"
				+ "        \"username\" : \"test\"\n" + "    }\n" + "}");
		request.setBody(Body.body(expected));
	}
}
