package cn.hanghui.outapi.platform.common.config;

import cn.hanghui.outapi.platform.common.filter.JwtAuthorizationFilter;
import cn.hanghui.outapi.platform.common.handler.AuthorizedFailedHandler;
import cn.hanghui.outapi.platform.common.handler.LoginAuthorizedHandler;
import cn.hanghui.outapi.platform.common.service.LoginService;
import cn.hutool.core.util.ArrayUtil;
import lombok.AllArgsConstructor;
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.Configuration;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.builders.WebSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.config.http.SessionCreationPolicy;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.web.servlet.config.annotation.CorsRegistry;
import org.springframework.web.servlet.config.annotation.ResourceHandlerRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;

import javax.annotation.Resource;
import java.util.ArrayList;
import java.util.List;

@Configuration
@EnableWebSecurity
public class WebSecurityConfig extends WebSecurityConfigurerAdapter implements WebMvcConfigurer {

    @Resource
    private LoginService loginService;
    @Resource
    private AuthorizedFailedHandler authorizedFailedHandler;
    @Resource
    private LoginAuthorizedHandler loginAuthorizedHandler;

    /**
     * 上传地址
     */
    @Value("${file.upload.path}")
    private String filePath;

    @Value("${file.upload.picPath}")
    private String picPath;

    /**
     * 显示相对地址
     */
    @Value("${file.upload.path.relative}")
    private String fileRelativePath;


    @Override
    public void addResourceHandlers(ResourceHandlerRegistry registry) {
        registry.addResourceHandler(fileRelativePath).addResourceLocations("file:" + filePath);
        registry.addResourceHandler("file/upload/pic/**").addResourceLocations("file:" + picPath);
    }

    @Bean
    public BCryptPasswordEncoder bCryptPasswordEncoder() {
        return new BCryptPasswordEncoder();
    }

    @Bean
    @Override
    public AuthenticationManager authenticationManagerBean() throws Exception {
        return super.authenticationManagerBean();
    }

    @Override
    protected void configure(AuthenticationManagerBuilder auth) throws Exception {
        auth.authenticationProvider(loginAuthorizedHandler)
                .userDetailsService(loginService)
                .passwordEncoder(bCryptPasswordEncoder());
    }

    @Override
    public void configure(WebSecurity web) {
        web.ignoring().antMatchers(excludeUrl());
    }

    @Override
    protected void configure(HttpSecurity httpSecurity) throws Exception {
        httpSecurity.cors().and().csrf().disable()
                .formLogin().disable()
                // 认证失败处理类
                .exceptionHandling().authenticationEntryPoint(authorizedFailedHandler)
                .and()
                .authorizeRequests()
                // 对于登录login允许匿名访问
                .antMatchers(excludeUrl()).anonymous()
                .anyRequest().authenticated()
                .and()
                .addFilter(new JwtAuthorizationFilter(authenticationManager()))
                // 不需要session
                .sessionManagement()
                .sessionCreationPolicy(SessionCreationPolicy.STATELESS);
    }

    @Override
    public void addCorsMappings(CorsRegistry registry) {
        registry.addMapping("/**")
                .allowedOriginPatterns("*")
                .allowedMethods("GET", "POST", "OPTIONS", "DELETE", "PUT")
                .allowedHeaders("*")
                .exposedHeaders("Access-Control-Allow-Headers",
                        "Access-Control-Allow-Methods",
                        "Access-Control-Allow-Origin",
                        "Access-Control-Max-Age",
                        "X-Frame-Options")
                .allowCredentials(false)
                .maxAge(3600);
    }

    private String[] excludeUrl() {
        List<String> excludeList = new ArrayList<>();
        excludeList.add("/**/login");
        excludeList.add("/**/doc.html/**");
        excludeList.add("/**/dist/**");
        excludeList.add("/**/*.js");
        excludeList.add("/**/*.css");
        excludeList.add("/**/favicon.ico");
        excludeList.add("/**/*swagger*");
        excludeList.add("/**/api-docs*");
        excludeList.add("/**/error");
        excludeList.add("/**/xinghuoApi/**");
        excludeList.add("/**/alipayApi/**");
        excludeList.add("/**/pushPersonInfo");
        excludeList.add("/**/api/v1/tenant/list");
        excludeList.add("/**/api/v1/tenant/sn/op/config");
        excludeList.add("/**/api/v1/tenant/sn/deviceWhiteList");
        excludeList.add("/**/api/v1/tenant/inner/list");
        excludeList.add("/**/api/v1/alipay/**");
        excludeList.add("/**/alipay/api/v1/open/**");
        excludeList.add("/**/static/*.docx");
        excludeList.add("/**/*.xlsx");
        excludeList.add("/**/*.xls");
        excludeList.add("/**/*.pdf");
        excludeList.add("/**/static/**");
        excludeList.add("/**/api/v1/upload/**");
        excludeList.add("/**/api/v1/app/log/add");
        excludeList.add("/**/file/**");
        excludeList.add("/**/api/v1/app/task/query");
        excludeList.add("/**/api/v1/app/task/completed/tracking");
        excludeList.add("/api/v1/iot/device/config/sn/config");
        excludeList.add("/api/v1/iot/device/config/sn/updateConfig");
        excludeList.add("/api/v1/provisional/proof/sn/**");
        excludeList.add("/api/v1/provisional/proof/sns/**");
        excludeList.add("/api/v1/risk/**");
        excludeList.add("/api/v1/open/**");
        excludeList.add("/api/v1/fkj/device/sn/**");
        excludeList.add("/api/v1/hh/culture/device/sn/**");
        excludeList.add("/api/v1/hh/local/device/sn/**");
        excludeList.add("/api/v1/hh/omc/device/config/**");
        excludeList.add("/pc/getCode");

        excludeList.add("/**/v1/proof/**");
        return ArrayUtil.toArray(excludeList, String.class);
    }

    public static void main(String[] args) {
        System.out.println(new BCryptPasswordEncoder().encode("Nqj##117521"));
    }
}
