package incheon.com.config;

import com.fasterxml.jackson.databind.ObjectMapper;
import incheon.com.cmm.interceptor.RequestContextInterceptor;
import incheon.com.cmm.interceptor.WebLogInterceptor;
import incheon.com.security.CustomAuthenticationPrincipalResolver;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.FilterType;
import org.springframework.http.converter.HttpMessageConverter;
import org.springframework.http.converter.json.MappingJackson2HttpMessageConverter;
import org.springframework.stereotype.Repository;
import org.springframework.stereotype.Service;
import org.springframework.web.method.support.HandlerMethodArgumentResolver;
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
import org.springframework.web.servlet.config.annotation.ResourceHandlerRegistry;
import org.springframework.web.servlet.config.annotation.ViewControllerRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;

import java.util.List;

/**
 * @ClassName : EgovConfigWebDispatcherServlet.java
 * @Description : DispatcherServlet 설정
 *
 * @author : 윤주호
 * @since  : 2021. 7. 20
 * @version : 1.0
 *
 * <pre>
 * << 개정이력(Modification Information) >>
 *
 *   수정일              수정자               수정내용
 *  -------------  ------------   ---------------------
 *   2021. 7. 20    윤주호               최초 생성
 * </pre>
 *
 */
@Configuration
@ComponentScan(basePackages = "incheon", excludeFilters = {
		@ComponentScan.Filter(type = FilterType.ANNOTATION, value = Service.class),
		@ComponentScan.Filter(type = FilterType.ANNOTATION, value = Repository.class),
		@ComponentScan.Filter(type = FilterType.ANNOTATION, value = Configuration.class)
})
public class EgovConfigWebDispatcherServlet implements WebMvcConfigurer {
	@Autowired
	private WebLogInterceptor webLogInterceptor;

	@Autowired
	private RequestContextInterceptor requestContextInterceptor;

	@Autowired
	private ObjectMapper objectMapper;

	/**
	 * 외부 리소스 경로 (환경별 설정)
	 */
	@Value("${Globals.resources.path}")
	private String resourcesPath;
	// =====================================================================
	// RequestMappingHandlerMapping 설정
	// =====================================================================
	// -------------------------------------------------------------
	// RequestMappingHandlerMapping 설정 - Interceptor 추가
	//
	// 실행 순서 (명시적 order 지정):
	// 1. RequestContextInterceptor (order=0) - 메뉴/컨텍스트 정보 보강 (최우선)
	// 2. WebLogInterceptor (order=100) - 로그 수집 (컨텍스트 정보 활용)
	// -------------------------------------------------------------
	@Override
	public void addInterceptors(InterceptorRegistry registry) {
		// 1. RequestContext 인터셉터 (메뉴/권한 등 컨텍스트 정보 보강) - 최우선 실행
		registry.addInterceptor(requestContextInterceptor)
				.addPathPatterns("/**")  // 전체 적용 (API 포함)
				.excludePathPatterns(
						"/static/**",   // 정적 리소스
						"/resources/**", // 외부 리소스
						"/css/**",
						"/js/**",
						"/images/**",
						"/error",       // 에러 페이지
						"/favicon.ico",
						"/.well-known/**"  // 브라우저 자동 요청
				)
				.order(0);  // 최우선 실행

		// 2. WebLog 인터셉터 (로그 수집 - RequestContext 정보 활용)
		registry.addInterceptor(webLogInterceptor)
				.addPathPatterns("/**")  // 전체 URI 감시
				.excludePathPatterns(
						"/css/**",
						"/js/**",
						"/images/**",
						"/static/**",
						"/resources/**",
						"/favicon.ico",
						"/.well-known/**"
				)
				.order(100);  // RequestContextInterceptor 이후 실행
	}

    // -------------------------------------------------------------
    // Static Resource Handler 추가 (외부 경로 매핑)
    // ResourceController에서 처리하도록 변경 (한글 파일명 지원)
    // -------------------------------------------------------------
    @Override
    public void addResourceHandlers(ResourceHandlerRegistry registry) {
        // /resources/** 경로로 들어오는 요청을 외부 리소스 경로에서 찾도록 설정
        // 상대 경로(..)가 포함된 경우 file: 프로토콜에서 문제가 발생할 수 있으므로 절대 경로 URI로 변환
        String resourceLocation = java.nio.file.Paths.get(resourcesPath).toAbsolutePath().normalize().toUri().toString();

        registry.addResourceHandler("/resources/**")
                .addResourceLocations(resourceLocation)
                .setCacheControl(org.springframework.http.CacheControl.empty().cachePublic());
    }

	// -------------------------------------------------------------
	// RequestMappingHandlerMapping 설정 View Controller 추가
	// -------------------------------------------------------------
	@Override
	public void addViewControllers(ViewControllerRegistry registry) {
		registry.addViewController("/cmmn/validator.do")
				.setViewName("cmmn/validator");
		registry.addViewController("/").setViewName("index");
	}

	// -------------------------------------------------------------
	// ArgumentResolver 추가 (WebMvcConfig에서 통합)
	// -------------------------------------------------------------
	@Override
	public void addArgumentResolvers(List<HandlerMethodArgumentResolver> argumentResolvers) {
		argumentResolvers.add(new CustomAuthenticationPrincipalResolver());
	}

	// -------------------------------------------------------------
	// HTML Escaping Converter Bean (WebMvcConfig에서 통합)
	// -------------------------------------------------------------
	@Bean
	public HttpMessageConverter<?> htmlEscapingConverter() {
		ObjectMapper copy = objectMapper.copy();
		copy.getFactory().setCharacterEscapes(new HtmlCharacterEscapes());
		return new MappingJackson2HttpMessageConverter(copy);
	}
}
