package com.imooc.config;

import com.imooc.intercepter.PassportInterceptor;
import com.imooc.intercepter.UserTokenInterceptor;
import java.security.KeyManagementException;
import java.security.KeyStoreException;
import java.security.NoSuchAlgorithmException;
import java.util.Arrays;
import javax.net.ssl.SSLContext;
import org.apache.http.conn.ssl.NoopHostnameVerifier;
import org.apache.http.conn.ssl.SSLConnectionSocketFactory;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.impl.conn.PoolingHttpClientConnectionManager;
import org.apache.http.ssl.SSLContexts;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Primary;
import org.springframework.core.Ordered;
import org.springframework.core.annotation.Order;
import org.springframework.http.HttpMethod;
import org.springframework.http.client.HttpComponentsClientHttpRequestFactory;
import org.springframework.web.client.RestTemplate;
import org.springframework.web.cors.CorsConfiguration;
import org.springframework.web.cors.UrlBasedCorsConfigurationSource;
import org.springframework.web.filter.CorsFilter;
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;

@Configuration
public class InterceptorConfig implements WebMvcConfigurer {

	private String[] CORS_HTTP_METHODS = { HttpMethod.HEAD.name(), HttpMethod.GET.name(), HttpMethod.POST.name(),
			HttpMethod.PUT.name(), HttpMethod.DELETE.name(), HttpMethod.OPTIONS.name(), HttpMethod.PATCH.name() };

	private static final long CORS_MAX_AGE = 30 * 24 * 60 * 60;

	@Bean
	public PassportInterceptor passportInterceptor() {
		return new PassportInterceptor();
	}

	@Bean
	public UserTokenInterceptor userTokenInterceptor() {
		return new UserTokenInterceptor();
	}

	@Override
	public void addInterceptors(InterceptorRegistry registry) {
		registry.addInterceptor(passportInterceptor()).addPathPatterns("/passport/getSMSCode");

		registry.addInterceptor(userTokenInterceptor()).addPathPatterns("/userInfo/modifyUserInfo")
				.addPathPatterns("/userInfo/modifyImage");
	}

	@Order(Ordered.HIGHEST_PRECEDENCE)
	@Bean
	public CorsFilter corsFilter() {
		// 添加跨域配置信息
		CorsConfiguration config = new CorsConfiguration();
		// 设置访问源地址
		config.addAllowedOriginPattern("*");
		// 设置访问源请求头
		config.addAllowedHeader("*");
		// 设置是否发送Cookie信息
		config.setAllowCredentials(true);
		// 设置访问源请求方法
		Arrays.stream(CORS_HTTP_METHODS).forEach(method -> config.addAllowedMethod(method));
		// 设置请求最大有效时长
		config.setMaxAge(CORS_MAX_AGE);
		UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
		// 配置跨域
		source.registerCorsConfiguration("/**", config);
		return new CorsFilter(source);
	}

	@Primary
	@Bean
	public RestTemplate restTemplate() {
		PoolingHttpClientConnectionManager connManager = new PoolingHttpClientConnectionManager();
		// 连接池最大连接数
		connManager.setMaxTotal(1000);
		// 每个主机的并发
		connManager.setDefaultMaxPerRoute(500);

		CloseableHttpClient httpClient = HttpClients.custom()//
				.setConnectionManager(connManager)// 设置HTTP连接管理器
				.build();
		return buildRestTemplate(httpClient);
	}

	@Bean
	public RestTemplate restTemplateIgnoreSSL()
			throws KeyManagementException, NoSuchAlgorithmException, KeyStoreException {
		SSLContext sslContext = SSLContexts.custom().loadTrustMaterial(null, (chain, authType) -> true).build();
		SSLConnectionSocketFactory sslSocketFactory = new SSLConnectionSocketFactory(sslContext,
				NoopHostnameVerifier.INSTANCE);

		CloseableHttpClient httpClient = HttpClients.custom()//
				.setSSLSocketFactory(sslSocketFactory)//
				.build();
		return buildRestTemplate(httpClient);
	}

	private RestTemplate buildRestTemplate(CloseableHttpClient httpClient) {
		HttpComponentsClientHttpRequestFactory httpRequestFactory = new HttpComponentsClientHttpRequestFactory(
				httpClient);
		// 获取链接超时时间
		httpRequestFactory.setConnectionRequestTimeout(3000);
		// 指客户端和服务器建立连接的timeout
		httpRequestFactory.setConnectTimeout(3000);
		// 读取数据的超时时间
		httpRequestFactory.setReadTimeout(120000);
		return new RestTemplate(httpRequestFactory);
	}
}
