package cc.smtweb.framework.core.mvc.config;

import cc.smtweb.framework.core.CoreInterceptor;
import cc.smtweb.framework.core.cache.CacheManager;
import cc.smtweb.framework.core.cache.redis.RedisManager;
import cc.smtweb.framework.core.db.jdbc.IdGenerator;
import cc.smtweb.framework.core.mvc.controller.ApiConfigBean;
import cc.smtweb.framework.core.mvc.controller.MethodAccessManager;
import cc.smtweb.framework.core.session.SessionManager;
import cc.smtweb.framework.core.session.UserSessionArgumentResolver;
import cc.smtweb.framework.core.util.JsonUtil;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.autoconfigure.http.HttpMessageConverters;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Primary;
import org.springframework.http.MediaType;
import org.springframework.http.converter.json.MappingJackson2HttpMessageConverter;
import org.springframework.web.method.support.HandlerMethodArgumentResolver;
import org.springframework.web.servlet.config.annotation.*;

import java.util.List;

/**
 * @author kevin
 */
@Configuration
@Slf4j
public class WebMvcConfig implements WebMvcConfigurer {
    private static final String PATTERN_FILES = "/files/**";
    private static final String PATTERN_STATIC = "/static/**";

    @Value("${smtweb.file.local-path}")
    private String fileLocalPath;

    @Value("${smtweb.static.local-path:}")
    private String staticLocalPath;

//    @Value("${smtweb.api.json-full:}")
//    private String apiJsonFull;

    @Autowired
    private ApiConfigBean apiConfigBean;

    private static final String TRUE_VALUE = "true";

    @Bean
    public SessionManager sessionManager(RedisManager redisManager, IdGenerator idGenerator) {
        return new SessionManager(redisManager, idGenerator);
    }

    @Bean
    public CacheManager cacheManager() {
        return new CacheManager();
    }

    @Bean
    public MethodAccessManager methodAccessManager(CacheManager cacheManager) {
        return new MethodAccessManager(cacheManager);
    }

    @Override
    public void addInterceptors(InterceptorRegistry registry) {
        registry.addInterceptor(new CoreInterceptor());
    }

    @Override
    public void addCorsMappings(CorsRegistry registry) {
        // 2.4 以前使用 .allowedOrigins("*")
        registry.addMapping("/**")
                .allowedOriginPatterns("*")
                .allowedMethods("*")
                .maxAge(3600)
                .allowCredentials(true);
    }

    @Bean
    @Primary
    public HttpMessageConverters customConverters() {
        MappingJackson2HttpMessageConverter messageConverter = new MappingJackson2HttpMessageConverter();
        if (apiConfigBean.isJsonFull()) {
            // 输出所有空属性
            messageConverter.setObjectMapper(JsonUtil.API_OBJECT_MAPPER);
        } else {
            messageConverter.setObjectMapper(JsonUtil.OBJECT_MAPPER);
        }

        // 将转换器添加到converters中
        return new HttpMessageConverters(messageConverter);
    }

    @Override
    public void addArgumentResolvers(List<HandlerMethodArgumentResolver> argumentResolvers) {
        argumentResolvers.add(new UserSessionArgumentResolver());
    }

    @Override
    public void addResourceHandlers(ResourceHandlerRegistry registry) {
        // 静态资源文件
        if (!registry.hasMappingForPattern(PATTERN_STATIC)) {
            if (StringUtils.isBlank(staticLocalPath)) {
                registry.addResourceHandler(PATTERN_STATIC).addResourceLocations("classpath:/static/");
            } else if (staticLocalPath.endsWith("/")) {
                // staticLocalPath 必须 / 结束
                registry.addResourceHandler(PATTERN_STATIC).addResourceLocations("classpath:/static/",
                        "file:" + staticLocalPath);
                log.info("'/static/**' => file:" + staticLocalPath);
            } else {
                log.error("'smtweb.static.local-path' 必须用'/'结尾: " + staticLocalPath);
            }
        } else {
            log.error("'/static/**' 已经被注册");
        }

        // 动态用户文件
        if (!registry.hasMappingForPattern(PATTERN_FILES)) {
            registry.addResourceHandler(PATTERN_FILES).addResourceLocations("file:" + fileLocalPath);
            log.info("'/files/**' => file:" + fileLocalPath);
        } else {
            log.error("'/files/**' 已经被注册");
        }
    }

    // 所有返回接口Content-Type默认都返回application/json
    @Override
    public void configureContentNegotiation(ContentNegotiationConfigurer configurer) {
        configurer.defaultContentType(MediaType.APPLICATION_JSON);
    }
}
