package cn.org.easysite.spring.boot.autoconfigure;


import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.boot.autoconfigure.http.HttpMessageConverters;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.boot.web.servlet.FilterRegistrationBean;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.EnableAspectJAutoProxy;
import org.springframework.http.client.ClientHttpRequestFactory;
import org.springframework.http.client.ClientHttpRequestInterceptor;
import org.springframework.http.client.SimpleClientHttpRequestFactory;
import org.springframework.http.converter.StringHttpMessageConverter;
import org.springframework.http.converter.json.MappingJackson2HttpMessageConverter;
import org.springframework.web.client.RestTemplate;

import java.nio.charset.StandardCharsets;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import javax.servlet.DispatcherType;

import cn.org.easysite.framework.utils.SpringApplicationUtils;
import cn.org.easysite.spring.boot.configuration.GlobalReturnValuePathProperties;
import cn.org.easysite.spring.boot.configuration.HttpConnectionProperties;
import cn.org.easysite.spring.boot.configuration.XssFilterProperties;
import cn.org.easysite.spring.boot.converter.GlobalMessageConverter;
import cn.org.easysite.spring.boot.converter.TextPlainMappingJackson2HttpMessageConverter;
import cn.org.easysite.spring.boot.filters.xss.XssFilter;
import cn.org.easysite.spring.boot.http.HttpRequestTemplate;
import cn.org.easysite.spring.boot.interceptor.ClientHttpRequestInterceptorImpl;
import cn.org.easysite.spring.boot.interceptor.DefaultExceptionHandler;
import cn.org.easysite.spring.boot.interceptor.ResponseBodyWrapFactoryBean;
import cn.org.easysite.spring.boot.interceptor.ValidateInterceptor;

import static cn.org.easysite.spring.boot.filters.xss.XssFilter.XSS_FILTER_ENABLED;
import static cn.org.easysite.spring.boot.filters.xss.XssFilter.XSS_FILTER_URL_EXCLUDES;

/**
 * Spring MVC 配置
 *
 * @author trang
 */
@Configuration
@EnableAspectJAutoProxy
@EnableConfigurationProperties({GlobalReturnValuePathProperties.class, HttpConnectionProperties.class, XssFilterProperties.class})
public class SpringMvcConfiguration {

    @ConditionalOnMissingBean
    @Bean
    ClientHttpRequestFactory clientHttpRequestFactory(HttpConnectionProperties httpConnectionProperties) {
        SimpleClientHttpRequestFactory requestFactory = new SimpleClientHttpRequestFactory();
        requestFactory.setConnectTimeout(httpConnectionProperties.getConnectionTimeOut());
        requestFactory.setReadTimeout(httpConnectionProperties.getReadTimeOut());
        return requestFactory;
    }

    @ConditionalOnMissingBean
    @Bean
    RestTemplate restTemplate(ClientHttpRequestFactory clientHttpRequestFactory) {
        RestTemplate restTemplate = new RestTemplate(clientHttpRequestFactory);
        restTemplate.getMessageConverters().set(1, new StringHttpMessageConverter(StandardCharsets.UTF_8));
        restTemplate.getMessageConverters().add(new TextPlainMappingJackson2HttpMessageConverter());
        List<ClientHttpRequestInterceptor> interceptors=new ArrayList<>();
        interceptors.add(new ClientHttpRequestInterceptorImpl());
        restTemplate.setInterceptors(interceptors);
        return restTemplate;
    }

    @Bean
    @ConditionalOnMissingBean
    HttpRequestTemplate httpRequestTemplate(@Autowired RestTemplate restTemplate) {
        return new HttpRequestTemplate(restTemplate);
    }

    @Bean
    @ConditionalOnMissingBean
    public HttpMessageConverters fastJsonHttpMessageConverters() {
        return new HttpMessageConverters(converter());
    }

    @Bean
    @ConditionalOnMissingBean
    public MappingJackson2HttpMessageConverter converter() {
        return new GlobalMessageConverter();
    }

    @Bean
    public SpringApplicationUtils springUtils() {
        return new SpringApplicationUtils();
    }

    @ConditionalOnMissingBean
    @Bean
    public DefaultExceptionHandler defaultExceptionHandler() {
        return new DefaultExceptionHandler();
    }

    @Bean
    public FilterRegistrationBean xssFilter(XssFilterProperties properties) {
        FilterRegistrationBean registration = new FilterRegistrationBean();
        registration.setDispatcherTypes(DispatcherType.REQUEST);
        registration.setFilter(new XssFilter());
        registration.addUrlPatterns(StringUtils.split(properties.getUrlPatterns(), ","));
        registration.setName("xssFilter");
        registration.setOrder(Integer.MAX_VALUE);
        Map<String, String> initParameters = new HashMap<String, String>();
        initParameters.put(XSS_FILTER_URL_EXCLUDES, properties.getUrlExcludes());
        initParameters.put(XSS_FILTER_ENABLED, properties.getEnabled());
        registration.setInitParameters(initParameters);
        return registration;
    }

    @Bean
    @ConditionalOnProperty(prefix = "easy.global.json.return.value", name = "enable", matchIfMissing = true, havingValue = "true")
    public ResponseBodyWrapFactoryBean responseBodyWrapFactoryBean() {
        return new ResponseBodyWrapFactoryBean();
    }

    @Bean
    @ConditionalOnMissingBean
    public ValidateInterceptor validateInterceptor() {
        return new ValidateInterceptor();
    }

}
