package com.xkrs.common.account;

import com.xkrs.common.encapsulation.OutputEncapsulation;
import com.xkrs.common.encapsulation.PromptMessageEnum;
import com.xkrs.model.vo.SysUserVo;
import com.xkrs.service.SysUserService;
import com.xkrs.utils.IpUtil;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.context.i18n.LocaleContextHolder;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.authentication.BadCredentialsException;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.AuthenticationException;
import org.springframework.security.web.authentication.AbstractAuthenticationProcessingFilter;
import org.springframework.security.web.util.matcher.AntPathRequestMatcher;
import org.springframework.web.context.WebApplicationContext;
import org.springframework.web.context.support.WebApplicationContextUtils;

import javax.annotation.Resource;
import javax.servlet.FilterChain;
import javax.servlet.ServletContext;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.PrintWriter;
import java.io.UnsupportedEncodingException;
import java.util.Locale;

/**
 * jwt登录过滤器
 * @author tajochen
 */
public class JwtLoginFilter extends AbstractAuthenticationProcessingFilter {

    private static final Logger logger = LoggerFactory.getLogger(JwtLoginFilter.class);


    @Resource
    private SysUserService sysUserService;

    public JwtLoginFilter(String url, AuthenticationManager authManager) {
        super(new AntPathRequestMatcher(url));
        setAuthenticationManager(authManager);
    }

    /**
     * 登录时验证
     * @param req
     * @param res
     * @return
     */
    @Override
    public Authentication attemptAuthentication(HttpServletRequest req, HttpServletResponse res) throws UnsupportedEncodingException {
        req.setCharacterEncoding("UTF-8");
        res.setHeader("Access-Control-Allow-Origin","*");
        res.setHeader("Access-Control-Allow-Credentials", "false");
        AccountCredentials creds = new AccountCredentials();
        //获取表单数据
        String userName = req.getParameter("userName");
        String password = req.getParameter("password");
        String rememberMe = req.getParameter("remember");
        //如果用户名密码为空
        if(userName == null||password == null|| userName.trim().isEmpty()||password.trim().isEmpty()){
            throw new BadCredentialsException("user or password is null");
        }
        if(rememberMe == null||rememberMe.isEmpty()){
            rememberMe = "false";
        }
        creds.setUserName(userName.trim());
        creds.setPassword(password.trim());
        creds.setRemember(Boolean.parseBoolean(rememberMe));
        // 返回一个验证令牌
        return getAuthenticationManager().authenticate(
            new UsernamePasswordAuthenticationToken(
                    creds.getUserName(),
                    creds.getPassword()
            )
        );
    }

    /**
     * 验证成功后调用
     * @param req
     * @param response
     * @param chain
     * @param auth
     * @throws IOException
     * @throws ServletException
     */
    @Override
    protected void successfulAuthentication(
            HttpServletRequest req, HttpServletResponse response, FilterChain chain, Authentication auth) {
        if(sysUserService==null){
            ServletContext servletContext = req.getServletContext();
            WebApplicationContext webApplicationContext = WebApplicationContextUtils.getWebApplicationContext(servletContext);
            sysUserService = webApplicationContext.getBean(SysUserService.class);
        }
        //更新用户登录信息
        sysUserService.updateSysUserLogin(auth.getName(), IpUtil.getIpAddr(req));
        SysUserVo sysUserVo = sysUserService.selectUserByUserName(auth.getName());
        response.setHeader("Access-Control-Allow-Origin", "*");
        response.setHeader("Access-Control-Allow-Credentials", "false");
        response.setContentType("application/json");
        response.setCharacterEncoding("UTF-8");
        TokenAuthenticationService.addAuthentication(response, auth.getName(),auth.getAuthorities(),sysUserVo);
    }

    /**
     * 验证失败后调用
     * @param request
     * @param response
     * @param failed
     * @throws IOException
     */
    @Override
    protected void unsuccessfulAuthentication(HttpServletRequest request,
                                              HttpServletResponse response,
                                              AuthenticationException failed) throws IOException {
        Locale locale = LocaleContextHolder.getLocale();
        response.setHeader("Access-Control-Allow-Origin", "*");
        response.setHeader("Access-Control-Allow-Credentials", "false");
        response.setContentType("application/json");
        response.setCharacterEncoding("UTF-8");
        // 将 JWT 写入 body
        PrintWriter out = response.getWriter();
        out.append(OutputEncapsulation.outputEncapsulationObject(PromptMessageEnum.DATA_WRONG, failed.getLocalizedMessage(), locale));
        response.setStatus(HttpServletResponse.SC_OK);
    }
}
