package com.samsung.config;

import com.samsung.approval.interceptor.ApprovalInterceptor;
import com.samsung.approval.interceptor.ApprovalInterceptorExecutor;
import com.samsung.interceptor.*;
import com.samsung.sample.approval.internal.interceptor.InternalApprovalSampleInterceptor;
import com.samsung.sample.approval.knox.interceptor.KnoxApprovalSampleInterceptor;
import com.samsung.user.interceptor.LoginInterceptor;
import com.samsung.user.interceptor.LoginInterceptorExecutor;
import jakarta.servlet.MultipartConfigElement;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.web.servlet.MultipartConfigFactory;
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.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.stereotype.Controller;
import org.springframework.util.unit.DataSize;
import org.springframework.web.multipart.MultipartResolver;
import org.springframework.web.multipart.support.StandardServletMultipartResolver;
import org.springframework.web.servlet.config.annotation.*;

import java.util.ArrayList;
import java.util.List;

@Configuration
@EnableWebMvc
@ComponentScan(basePackages = "com.samsung", useDefaultFilters = false, includeFilters = {@ComponentScan.Filter(type = FilterType.ANNOTATION, value = Controller.class)})
public class SpringWebConfig implements WebMvcConfigurer {
    /**
     * Access Timeout 체크
     */
    @Value("${security.check.access.timeout:false}")
    private boolean checkTimeout;

    @Value("${security.authentication.exclude-path}")
    private List<String> authExcludePathList;

    @Value("${access-log.exclude-path}")
    private List<String> accessLogExcludePathList;

    @Value("${common.upload.max-request-size:-1}")
    private long maxRequestSize;
    @Value("${common.upload.max-file-size:-1}")
    private long maxFileSize;
    @Value("${common.upload.default-encoding:UTF-8}")
    private String defaultEncoding;

    @Value("${web-resource-root}")
    private String webResourceRoot;

    @Override
    public void addInterceptors(InterceptorRegistry registry) {
        registry.addInterceptor(authenticationInterceptor()).addPathPatterns("/**")
                .excludePathPatterns(authExcludePathList);
        if (checkTimeout) {
            registry.addInterceptor(timeoutCheckInterceptor()).addPathPatterns("/**")
                    .excludePathPatterns(authExcludePathList);
        }
        registry.addInterceptor(authorizationInterceptor()).addPathPatterns("/**")
                .excludePathPatterns(authExcludePathList);
        registry.addInterceptor(privacyPolicyInterceptor()).addPathPatterns("/**")
                .excludePathPatterns(authExcludePathList);
        registry.addInterceptor(uploadFileExtensionCheckInterceptor()).addPathPatterns("/**");
        registry.addInterceptor(loggingInterceptor()).addPathPatterns("/**").
                excludePathPatterns(accessLogExcludePathList);
    }

    @Bean
    public AuthenticationInterceptor authenticationInterceptor() {
        return new AuthenticationInterceptor();
    }

    @Bean
    public TimeoutCheckInterceptor timeoutCheckInterceptor() {
        return new TimeoutCheckInterceptor();
    }

    @Bean
    public PrivacyPolicyInterceptor privacyPolicyInterceptor() {
        return new PrivacyPolicyInterceptor();
    }

    @Bean
    public AuthorizationInterceptor authorizationInterceptor() {
        return new AuthorizationInterceptor();
    }

    @Bean
    public LoggingInterceptor loggingInterceptor() {
        return new LoggingInterceptor();
    }

    @Bean
    public UploadFileExtensionCheckInterceptor uploadFileExtensionCheckInterceptor() {
        return new UploadFileExtensionCheckInterceptor();
    }

    @Bean
    public MultipartResolver multipartResolver() {
        return new StandardServletMultipartResolver();
    }

    @Bean
    public MultipartConfigElement multipartConfigElement() {
        MultipartConfigFactory factory = new MultipartConfigFactory();
        factory.setMaxRequestSize(DataSize.ofBytes(maxRequestSize));
        factory.setMaxFileSize(DataSize.ofBytes(maxFileSize));

        return factory.createMultipartConfig();
    }

    @Bean
    public InternalApprovalSampleInterceptor internalApprovalSampleInterceptor() {
        return new InternalApprovalSampleInterceptor();
    }

    @Bean
    public KnoxApprovalSampleInterceptor knoxApprovalSampleInterceptor() {
        return new KnoxApprovalSampleInterceptor();
    }

    @Bean
    public ApprovalInterceptorExecutor approvalInterceptorExecutor() {
        List<ApprovalInterceptor> approvalInterceptorList = new ArrayList<>();
        approvalInterceptorList.add(internalApprovalSampleInterceptor());
        approvalInterceptorList.add(knoxApprovalSampleInterceptor());
        return new ApprovalInterceptorExecutor(approvalInterceptorList);
    }

    // 로그인 관련 Interceptor
    @Bean
    public UserUpdateInterceptor userUpdateInterceptor() {
        return new UserUpdateInterceptor();
    }

    @Bean
    public LoginOutLogInterceptor loginOutLogInterceptor() {
        return new LoginOutLogInterceptor();
    }

    @Bean
    public LoginInterceptorExecutor loginInterceptorExecutor() {
        List<LoginInterceptor> loginInterceptorList = new ArrayList<>();
        loginInterceptorList.add(userUpdateInterceptor());
        loginInterceptorList.add(loginOutLogInterceptor());
        return new LoginInterceptorExecutor(loginInterceptorList);
    }

    @Override
    public void addResourceHandlers(ResourceHandlerRegistry registry) {
        registry.addResourceHandler("index.html").
                addResourceLocations(webResourceRoot);
        registry.addResourceHandler("favicon.ico").
                addResourceLocations(webResourceRoot + "static/");
        registry.addResourceHandler("static/**")
                .addResourceLocations(webResourceRoot + "static/");
        registry.addResourceHandler("assets/**")
                .addResourceLocations(webResourceRoot + "assets/");
    }

    @Override
    public void addViewControllers(ViewControllerRegistry registry) {
        registry.addViewController("/").setViewName("forward:/index.html");
    }

    @Bean
    public PasswordEncoder passwordEncoder(){
        return new BCryptPasswordEncoder();
    }
}