package com.winsun.item.config.web;

import com.winsun.auth.core.config.properties.WinsunProperties;
import com.winsun.item.config.SessionDaoConfig;
import com.winsun.item.config.ShiroRedisCacheManager;
import com.winsun.item.core.intercept.GunsUserFilter;
import com.winsun.item.core.shiro.MyWebSessionManager;
import com.winsun.item.core.shiro.ShiroDbRealm;
import org.apache.shiro.cache.CacheManager;
import org.apache.shiro.cache.ehcache.EhCacheManager;
import org.apache.shiro.codec.Base64;
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.CookieRememberMeManager;
import org.apache.shiro.web.mgt.DefaultWebSecurityManager;
import org.apache.shiro.web.servlet.Cookie;
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.beans.factory.annotation.Value;
import org.springframework.beans.factory.config.MethodInvokingFactoryBean;
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.cache.ehcache.EhCacheManagerFactoryBean;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.redis.core.RedisTemplate;

import javax.crypto.KeyGenerator;
import javax.crypto.SecretKey;
import javax.servlet.Filter;
import java.security.NoSuchAlgorithmException;
import java.util.Arrays;
import java.util.HashMap;
import java.util.LinkedHashMap;
import java.util.Map;

@Configuration
@EnableAutoConfiguration
public class ShiroConfig {
    public ShiroConfig() {
    }

    @Bean
    public DefaultWebSecurityManager securityManager(CookieRememberMeManager rememberMeManager, CacheManager cacheShiroManager, RedisTemplate<Object, Object> redisTemplate, @Value("${winsun.redis-session-expire}") String expire, @Value("${winsun.spring-session-open}") boolean redisSessionOpen) {
        DefaultWebSecurityManager securityManager = new DefaultWebSecurityManager();
        securityManager.setRealm(this.shiroDbRealm());
        securityManager.setCacheManager(cacheShiroManager);
        securityManager.setRememberMeManager(rememberMeManager);
        if (redisSessionOpen) {
            securityManager.setSessionManager(this.servletContainerSessionManager(redisTemplate, expire));
        } else {
            MyWebSessionManager webSessionManager = new MyWebSessionManager();
            webSessionManager.setSessionValidationInterval(900000L);
            webSessionManager.setGlobalSessionTimeout(1800000L);
            securityManager.setSessionManager(webSessionManager);
        }

        return securityManager;
    }

    @Bean
    @ConditionalOnProperty(
            prefix = "winsun",
            name = {"spring-session-open"},
            havingValue = "true"
    )
    public MyWebSessionManager servletContainerSessionManager(RedisTemplate<Object, Object> redisTemplate, String expire) {
        MyWebSessionManager webSessionManager = new MyWebSessionManager();
        webSessionManager.setSessionDAO(new SessionDaoConfig(redisTemplate, expire));
        webSessionManager.setCacheManager(new ShiroRedisCacheManager(redisTemplate, expire));
        webSessionManager.setSessionValidationInterval((long) (Integer.valueOf(expire) * 1000));
        webSessionManager.setGlobalSessionTimeout((long) (Integer.valueOf(expire) * 1000));
        return webSessionManager;
    }

    @Bean
    @ConditionalOnProperty(
            prefix = "winsun",
            name = {"spring-session-open"},
            havingValue = "false"
    )
    public DefaultWebSessionManager defaultWebSessionManager(CacheManager cacheShiroManager, WinsunProperties winsunProperties) {
        DefaultWebSessionManager sessionManager = new DefaultWebSessionManager();
        sessionManager.setCacheManager(cacheShiroManager);
        sessionManager.setSessionValidationInterval((long) (winsunProperties.getSessionValidationInterval() * 1000));
        sessionManager.setGlobalSessionTimeout((long) (winsunProperties.getSessionInvalidateTime() * 1000));
        sessionManager.setDeleteInvalidSessions(true);
        sessionManager.setSessionValidationSchedulerEnabled(true);
        Cookie cookie = new SimpleCookie("JSESSIONID");
        cookie.setName("shiroCookie");
        cookie.setHttpOnly(true);
        sessionManager.setSessionIdCookie(cookie);
        return sessionManager;
    }

    @Bean
    public CacheManager getCacheShiroManager(EhCacheManagerFactoryBean ehcache) {
        EhCacheManager ehCacheManager = new EhCacheManager();
        ehCacheManager.setCacheManager(ehcache.getObject());
        return ehCacheManager;
    }

    @Bean
    public ShiroDbRealm shiroDbRealm() {
        return new ShiroDbRealm();
    }

    @Bean
    public CookieRememberMeManager rememberMeManager(SimpleCookie rememberMeCookie) {
        try {
            KeyGenerator keygen = KeyGenerator.getInstance("AES");
            SecretKey deskey = keygen.generateKey();
            CookieRememberMeManager manager = new CookieRememberMeManager();
            manager.setCipherKey(Base64.decode(deskey.getEncoded()));
            manager.setCookie(rememberMeCookie);
            return manager;
        } catch (NoSuchAlgorithmException e) {
            e.printStackTrace();
            return null;
        }
    }

    @Bean
    public SimpleCookie rememberMeCookie() {
        SimpleCookie simpleCookie = new SimpleCookie("rememberMe");
        simpleCookie.setHttpOnly(true);
        simpleCookie.setMaxAge(604800);
        return simpleCookie;
    }

    @Bean
    public ShiroFilterFactoryBean shiroFilter(DefaultWebSecurityManager securityManager) {
        ShiroFilterFactoryBean shiroFilter = new ShiroFilterFactoryBean();
        shiroFilter.setSecurityManager(securityManager);
        shiroFilter.setLoginUrl("/login");
        shiroFilter.setSuccessUrl("/");
        shiroFilter.setUnauthorizedUrl("/global/error");
        HashMap<String, Filter> myFilters = new HashMap();
        myFilters.put("user", new GunsUserFilter());
        shiroFilter.setFilters(myFilters);
        Map<String, String> hashMap = new LinkedHashMap();
        String ANON = "anon";
        String USER = "user";
        String AUTHC = "authc";
        Arrays.asList("/kaptcha", "/kaptcha/*", "/login", "/getPhoneCode", "/getPhoneCodeY", "/mgr/getU", "/acclogin", "/anonyMous", "/token", "/tourist", "/accSendSms", "/version/update", "/version/getVersion", "/forgerpw/*").forEach((data) -> {
            String var10000 = (String) hashMap.put(data, "anon");
        });
        Arrays.asList("/**").forEach((data) -> {
            String var10000 = (String) hashMap.put(data, "user");
        });
        shiroFilter.setFilterChainDefinitionMap(hashMap);
        return shiroFilter;
    }

    @Bean
    public MethodInvokingFactoryBean methodInvokingFactoryBean(DefaultWebSecurityManager securityManager) {
        MethodInvokingFactoryBean bean = new MethodInvokingFactoryBean();
        bean.setStaticMethod("org.apache.shiro.SecurityUtils.setSecurityManager");
        bean.setArguments(new Object[]{securityManager});
        return bean;
    }

    @Bean
    public LifecycleBeanPostProcessor lifecycleBeanPostProcessor() {
        return new LifecycleBeanPostProcessor();
    }

    @Bean
    public DefaultAdvisorAutoProxyCreator advisorAutoProxyCreator() {
        DefaultAdvisorAutoProxyCreator advisorAutoProxyCreator = new DefaultAdvisorAutoProxyCreator();
        advisorAutoProxyCreator.setProxyTargetClass(true);
        return advisorAutoProxyCreator;
    }

    @Bean
    public AuthorizationAttributeSourceAdvisor authorizationAttributeSourceAdvisor(DefaultWebSecurityManager securityManager) {
        AuthorizationAttributeSourceAdvisor authorizationAttributeSourceAdvisor = new AuthorizationAttributeSourceAdvisor();
        authorizationAttributeSourceAdvisor.setSecurityManager(securityManager);
        return authorizationAttributeSourceAdvisor;
    }

}