package com.style24.scm.support.config;

import java.nio.charset.Charset;
import java.util.Iterator;
import java.util.List;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.web.servlet.FilterRegistrationBean;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.http.MediaType;
import org.springframework.http.client.HttpComponentsClientHttpRequestFactory;
import org.springframework.http.converter.HttpMessageConverter;
import org.springframework.http.converter.StringHttpMessageConverter;
import org.springframework.http.converter.json.MappingJackson2HttpMessageConverter;
import org.springframework.web.client.RestTemplate;
import org.springframework.web.multipart.support.MultipartFilter;
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;

import com.fasterxml.jackson.databind.DeserializationFeature;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.style24.core.support.text.TscHtmlCharacterEscapes;
import com.style24.scm.support.interceptor.TssDefaultInterceptor;

import com.gagaframework.web.core.filter.GagaXssServletFilter;
import com.gagaframework.web.rest.client.GagaRequestStringTrim;

/**
 * Web MVC Configuration
 *
 * @author gagamel
 * @since 2020. 10. 19
 */
@Configuration
public class TssWebMvcConfig implements WebMvcConfigurer {

	@Autowired
	private TssDefaultInterceptor defaultInterceptor;

	@Override
	public void addInterceptors(InterceptorRegistry registry) {
		final String[] excludePathPatterns = new String[] {
			"/", "/index", "/signin", "/image/**", "/ux/**", "/smartEditor/**", "/favicon.ico",
			"/error/**", "/data/**", "/login", "/logout",
			"/delivery/sweettracker/response"
		};

		registry.addInterceptor(defaultInterceptor)
			.addPathPatterns("/**/*")
			.excludePathPatterns(excludePathPatterns);
	}

	/**
	 * @RequestBody annotation 이용 시 json data 형식의 모든 문자열의 앞, 뒤 공백을 제거
	 */
	@Bean
	public GagaRequestStringTrim stringTrim() {
		return new GagaRequestStringTrim();
	}

	/**
	 * XSS(Cross Site Script) Prevention Filter
	 *
	 * @return
	 */
	@SuppressWarnings({"rawtypes", "unchecked"})
	@Bean
	public FilterRegistrationBean xssFilterRegistrationBean() {
		FilterRegistrationBean bean = new FilterRegistrationBean();
		bean.setFilter(new GagaXssServletFilter());
		bean.setOrder(2);
		bean.addUrlPatterns("/*");
		return bean;
	}

	/**
	 * Multipart Filter
	 * 파일 업로드 구현 시 MultipartRequest를 처리함에 따라 해당 부분은 불필요 하나,
	 * com.oreilly.servlet.MultipartRequest 같은 걸 이용 시
	 * "Corrupt form data: premature ending" exception이 발생한다.
	 * 이를 해결하고자 Filter를 구성
	 *
	 * @return
	 */
	@SuppressWarnings({"rawtypes", "unchecked"})
	@Bean
	public FilterRegistrationBean springMultipartRegistrationBean() {
		FilterRegistrationBean bean = new FilterRegistrationBean();
		bean.setName("springMultipartResolver");
		bean.setFilter(new MultipartFilter());
		bean.setOrder(1);
		bean.addUrlPatterns(new String[] {
			"/common/file/upload/**",
			"/common/files/upload/**"
		});
		return bean;
	}

	/**
	 * MappingJackson2HttpMessageConverter가 여러 개일 경우 내가 추가한 것이 선택되지 않을 수 있음
	 * 그러므로 application/json으로 선택되는 converter를 덮어 써야 함
	 */
	@SuppressWarnings("rawtypes")
	@Override
	public void configureMessageConverters(List<HttpMessageConverter<?>> converters) {
		// Replace MessageConverter from default WebMvcConfigurer
		Iterator<HttpMessageConverter<?>> converterIterator = converters.iterator();
		while (converterIterator.hasNext()) {
			// Do not add new one, must replace
			HttpMessageConverter converter = converterIterator.next();
			if (converter.getSupportedMediaTypes().contains(MediaType.APPLICATION_JSON)) {
				converterIterator.remove();
			}
		}
		converters.add(jsonEscapeConverter());
	}

	/**
	 * XSS(Cross Site Script) Prevention
	 * 		@ResponseBody로 전달되는 JSON에 대한 처리
	 * @return
	 */
	@Bean
	public MappingJackson2HttpMessageConverter jsonEscapeConverter() {
		ObjectMapper objectMapper = new ObjectMapper();
		objectMapper.getFactory().setCharacterEscapes(new TscHtmlCharacterEscapes());

		// 도메인이 정의되지 않은 경우 JsonMappingException 발생 처리 안 하도록
		objectMapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);

		return new MappingJackson2HttpMessageConverter(objectMapper);
	}

	/**
	 * API 호출을 위한 RestTemplate 설정
	 *
	 * @return
	 */
	@Bean
	public RestTemplate restTemplate() {
		HttpComponentsClientHttpRequestFactory factory = new HttpComponentsClientHttpRequestFactory();
		factory.setConnectTimeout(300000);
		factory.setReadTimeout(300000);

		RestTemplate restTemplate = new RestTemplate(factory);

		// Convert the message to UTF-8
		restTemplate.getMessageConverters().add(0, new StringHttpMessageConverter(Charset.forName("UTF-8")));

		return restTemplate;
	}

}
