package com.artfess.assembly.conf;

import com.artfess.assembly.feign.impl.FeignClientInvocationHandler;
import com.artfess.base.feign.ApplicationFeignService;
import com.artfess.base.feign.BizFeignService;
import com.artfess.base.feign.FormFeignService;
import com.artfess.base.feign.SystemConfigFeignService;
import com.artfess.base.feign.UCFeignService;
import com.artfess.base.feign.WorkflowFeignService;
import com.artfess.base.jwt.JwtTokenHandler;
import com.artfess.base.util.HttpUtil;
import com.artfess.base.util.StringUtil;
import org.apache.http.client.HttpClient;
import org.apache.http.client.config.RequestConfig;
import org.apache.http.config.Registry;
import org.apache.http.config.RegistryBuilder;
import org.apache.http.conn.socket.ConnectionSocketFactory;
import org.apache.http.conn.socket.PlainConnectionSocketFactory;
import org.apache.http.conn.ssl.SSLConnectionSocketFactory;
import org.apache.http.impl.client.HttpClientBuilder;
import org.apache.http.impl.conn.PoolingHttpClientConnectionManager;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Primary;
import org.springframework.http.HttpRequest;
import org.springframework.http.client.ClientHttpRequestExecution;
import org.springframework.http.client.ClientHttpRequestFactory;
import org.springframework.http.client.ClientHttpRequestInterceptor;
import org.springframework.http.client.ClientHttpResponse;
import org.springframework.http.client.HttpComponentsClientHttpRequestFactory;
import org.springframework.web.client.RestTemplate;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import java.io.IOException;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Proxy;

@Configuration
public class AssemblyFeignServiceConfig {

	@Resource
	JwtTokenHandler jwtTokenHandler;
	@Value("${server.port}")
	public String applicationPort;

	@Value("${assembly.readtime:60001}")
	public Integer readTime ;

	@Value("${assembly.connecttime:60001}")
	public Integer connectTime;

	@Value("${assembly.maxTotal:4000}")
	public Integer maxTotal;

	@Value("${assembly.maxPerRoute:1000}")
	public Integer maxPerRoute;

	@Bean
	public RestTemplate restTemplate(){
		RestTemplate restTemplate = new RestTemplate(simpleClientHttpRequestFactory());
		restTemplate.getInterceptors().add(new ClientHttpRequestInterceptor() {
			@Override
			public ClientHttpResponse intercept(HttpRequest request, byte[] body, ClientHttpRequestExecution execution)
					throws IOException {
				String token = "";
				HttpServletRequest orginRequest = HttpUtil.getRequest();
				if(orginRequest!=null) {
					request.getHeaders().add("User-Agent", orginRequest.getHeader("User-Agent"));
				}
				String proxyToken = "Bearer " + jwtTokenHandler.generateFeignToken();
				// 标记该请求是通过feign过来的
				request.getHeaders().add("Proxy-Authorization", proxyToken);
				try {
					token = HttpUtil.getRequest().getHeader("Authorization");
				} catch (Exception e) {
				}
				// 1.优先复制原请求中的token
				if (StringUtil.isNotEmpty(token)) {
					request.getHeaders().add("Authorization", token);
				}
				// 2.没有时使用通用token
				else{
					request.getHeaders().add("Authorization", proxyToken);
				}
				return execution.execute(request, body);
			}
		});
		return restTemplate;
	}

	@Bean
	public ClientHttpRequestFactory simpleClientHttpRequestFactory(){
		HttpComponentsClientHttpRequestFactory clientHttpRequestFactory = new HttpComponentsClientHttpRequestFactory(httpClient());
		return clientHttpRequestFactory;
	}


	@Bean
	FeignClientInvocationHandler getFeignClientInvocationHandler(RestTemplate restTemplate) {
		FeignClientInvocationHandler handler = new FeignClientInvocationHandler();
		handler.setRestTemplate(restTemplate);
		handler.setRootUrl("http://localhost:" + applicationPort);
		return handler;
	}

	@Bean
	@Primary
	BizFeignService getBizFeignService(FeignClientInvocationHandler handler) {
		return generateProxy(BizFeignService.class, handler);
	}


	@Bean
	@Primary
	ApplicationFeignService getApplicationFeignService(FeignClientInvocationHandler handler) {
		return generateProxy(ApplicationFeignService.class, handler);
	}

	/*@Bean
	@Primary
	BpmModelFeignService getBpmModelFeignService(FeignClientInvocationHandler handler) {
		return generateProxy(BpmModelFeignService.class, handler);
	}

	@Bean
	@Primary
	BpmRuntimeFeignService getBpmRuntimeFeignService(FeignClientInvocationHandler handler) {
		return generateProxy(BpmRuntimeFeignService.class, handler);
	}*/

	@Bean
	@Primary
	WorkflowFeignService getWorkflowFeignService(FeignClientInvocationHandler handler) {
		return generateProxy(WorkflowFeignService.class, handler);
	}

	@Bean
	@Primary
	FormFeignService getFormFeignService(FeignClientInvocationHandler handler) {
		return generateProxy(FormFeignService.class, handler);
	}

	@Bean
	@Primary
    SystemConfigFeignService getSystemConfigFeignService(FeignClientInvocationHandler handler) {
		return generateProxy(SystemConfigFeignService.class, handler);
	}

	@Bean
	@Primary
	UCFeignService getUCFeignService(FeignClientInvocationHandler handler) {
		return generateProxy(UCFeignService.class, handler);
	}


	@SuppressWarnings("unchecked")
	private <T> T generateProxy(Class<T> clientInterface, InvocationHandler handler) {
		return (T) Proxy.newProxyInstance(getClass().getClassLoader(), new Class[] { clientInterface },
				handler);
	}

	@Bean(name = "myHttpClient")
	public HttpClient httpClient() {
		Registry<ConnectionSocketFactory> registry = RegistryBuilder.<ConnectionSocketFactory>create()
				.register("http", PlainConnectionSocketFactory.getSocketFactory())
				.register("https", SSLConnectionSocketFactory.getSocketFactory())
				.build();
		PoolingHttpClientConnectionManager connectionManager = new PoolingHttpClientConnectionManager(registry);
		//设置整个连接池最大连接数
		connectionManager.setMaxTotal(maxTotal);

		//路由是对maxTotal的细分
		connectionManager.setDefaultMaxPerRoute(maxPerRoute);
		RequestConfig requestConfig = RequestConfig.custom()
				.setSocketTimeout(readTime)  //返回数据的超时时间
				.setConnectTimeout(connectTime) //连接上服务器的超时时间
				.setConnectionRequestTimeout(connectTime) //从连接池中获取连接的超时时间
				.build();
		return HttpClientBuilder.create()
				.setDefaultRequestConfig(requestConfig)
				.setConnectionManager(connectionManager)
				.build();
	}
}
