package com.simuwang.base.config;

import cn.hutool.core.map.MapUtil;
import com.simuwang.base.components.ShiroLoginAuthAdapter;
import com.simuwang.base.components.ShiroRsaCredentialsMatcher;
import com.simuwang.base.components.UserAuthService;
import com.simuwang.shiro.core.ShiroDbRealm;
import com.simuwang.shiro.core.adapter.LoginAuthAdapter;
import com.simuwang.shiro.core.bridge.AuthBridgeService;
import com.simuwang.shiro.core.ShiroDbRealmImpl;
import com.simuwang.shiro.core.jwt.JwtContext;
import com.simuwang.shiro.core.jwt.JwtFilter;
import jakarta.servlet.Filter;
import org.apache.shiro.authc.credential.CredentialsMatcher;
import org.apache.shiro.spring.LifecycleBeanPostProcessor;
import org.apache.shiro.spring.security.interceptor.AuthorizationAttributeSourceAdvisor;
import org.apache.shiro.spring.web.ShiroFilterFactoryBean;
import org.apache.shiro.web.mgt.DefaultWebSecurityManager;
import org.apache.shiro.web.servlet.SimpleCookie;
import org.apache.shiro.web.session.mgt.DefaultWebSessionManager;
import org.springframework.aop.framework.autoproxy.DefaultAdvisorAutoProxyCreator;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.DependsOn;

import java.util.HashMap;
import java.util.Map;

@Configuration
public class ShiroConfig {
    private final JwtContext jwtContext;
    private final DaqProperties properties;
    private final UserAuthService userAuthService;

    public ShiroConfig(JwtContext jwtContext, DaqProperties properties, UserAuthService userAuthService) {
        this.jwtContext = jwtContext;
        this.properties = properties;
        this.userAuthService = userAuthService;
    }

    /**
     * 保证实现了Shiro内部lifecycle函数的bean执行
     */
    @Bean(name = "lifecycleBeanPostProcessor")
    public static LifecycleBeanPostProcessor getLifecycleBeanPostProcessor() {
        return new LifecycleBeanPostProcessor();
    }

    /**
     * 注册的登录认证适配器，实际场景中需要自定义实现
     *
     * @return /
     */
    @Bean
    public LoginAuthAdapter authAdapter() {
//        return new SimpleLoginAuthAdapter();
        return new ShiroLoginAuthAdapter(this.userAuthService);
    }

    @Bean
    public AuthBridgeService authBridgeService() {
        return new AuthBridgeService(this.authAdapter());
    }

    /**
     * 创建cookie对象
     */
    @Bean(name = "sessionIdCookie")
    public SimpleCookie simpleCookie() {
        SimpleCookie simpleCookie = new SimpleCookie();
        simpleCookie.setName("ShiroSession");
        return simpleCookie;
    }

    /**
     * 权限管理器
     */
    @Bean(name = "securityManager")
    public DefaultWebSecurityManager defaultWebSecurityManager() {
        DefaultWebSecurityManager securityManager = new DefaultWebSecurityManager();
        securityManager.setRealm(shiroDbRealm());
        securityManager.setSessionManager(shiroSessionManager());
        return securityManager;
    }

    /**
     * 自定义的密码匹配器，rsa
     *
     * @return /
     */
    @Bean
    public CredentialsMatcher credentialsMatcher() {
//        HashedCredentialsMatcher matcher = new HashedCredentialsMatcher();
//        matcher.setHashAlgorithmName("SHA-256");
//        matcher.setHashIterations(1000);
//        matcher.setStoredCredentialsHexEncoded(true);
//        return matcher;
        return new ShiroRsaCredentialsMatcher(this.properties);
    }

    /**
     * 自定义RealmImpl
     */
    @Bean(name = "shiroDbRealm")
    public ShiroDbRealm shiroDbRealm() {
        return new ShiroDbRealmImpl(this.authBridgeService(), this.credentialsMatcher());
    }

    /**
     * 会话管理器
     */
    @Bean(name = "sessionManager")
    public DefaultWebSessionManager shiroSessionManager() {
        DefaultWebSessionManager sessionManager = new DefaultWebSessionManager();
        sessionManager.setSessionValidationSchedulerEnabled(false);
        sessionManager.setSessionIdCookieEnabled(true);
        sessionManager.setSessionIdCookie(simpleCookie());
        sessionManager.setGlobalSessionTimeout(3600000);
        return sessionManager;
    }

    /**
     * AOP式方法级权限检查
     */
    @Bean
    @DependsOn("lifecycleBeanPostProcessor")
    public DefaultAdvisorAutoProxyCreator getDefaultAdvisorAutoProxyCreator() {
        DefaultAdvisorAutoProxyCreator defaultAdvisorAutoProxyCreator = new DefaultAdvisorAutoProxyCreator();
        defaultAdvisorAutoProxyCreator.setProxyTargetClass(true);
        return defaultAdvisorAutoProxyCreator;
    }

    /**
     * 配合DefaultAdvisorAutoProxyCreator事项注解权限校验
     */
    @Bean
    public AuthorizationAttributeSourceAdvisor getAuthorizationAttributeSourceAdvisor() {
        AuthorizationAttributeSourceAdvisor aasa = new AuthorizationAttributeSourceAdvisor();
        aasa.setSecurityManager(defaultWebSecurityManager());
        return new AuthorizationAttributeSourceAdvisor();
    }

    /**
     * 过滤器链
     */
    private Map<String, String> filterChainDefinition() {
        Map<String, String> map = MapUtil.newHashMap(20, true);
        map.put("/static/**", "anon");
        map.put("/v1/login", "anon");
        map.put("/v1/rsa-key", "anon");
        map.put("/test/**", "anon");
        map.put("/v1/**", "anon");
        map.put("/**", "anon");
        return map;
    }

//    @Bean
//    public JwtContext jwtUtil() {
//        return new JwtContext(this.properties);
//    }

    private Map<String, Filter> filterMap() {
        HashMap<String, Filter> map = MapUtil.newHashMap();
        map.put("jwt", new JwtFilter(this.properties, this.jwtContext));
        return map;
    }

    /**
     * Shiro过滤器
     */
    @Bean("shiroFilter")
    public ShiroFilterFactoryBean shiroFilterFactoryBean() {
        ShiroFilterFactoryBean shiroFilter = new ShiroFilterFactoryBean();
        shiroFilter.setSecurityManager(this.defaultWebSecurityManager());
        shiroFilter.setFilters(this.filterMap());
        shiroFilter.setFilterChainDefinitionMap(this.filterChainDefinition());
        // 去掉，防止404路由自动跳转到登录请求
//        shiroFilter.setLoginUrl("/v1/login");
//        shiroFilter.setUnauthorizedUrl("/v1/login");
        return shiroFilter;
    }
}
