package com.tofly.auth.oauth;

import com.tofly.common.core.constant.CommonConstants;
import com.tofly.common.core.constant.SecurityConstants;
import com.tofly.common.core.util.IpUtil;
import com.tofly.common.core.util.SpringContextHolder;
import com.tofly.common.core.util.StringUtil;
import com.tofly.common.oauth.auth.ToflyUser;
import com.tofly.entity.pojo.User;
import lombok.AllArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import com.tofly.auth.util.RSAUtils;
import org.springframework.cache.Cache;
import org.springframework.cache.CacheManager;
import org.springframework.security.authentication.AuthenticationProvider;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
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.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.oauth2.provider.token.TokenStore;
import org.springframework.stereotype.Component;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;

import javax.servlet.http.HttpServletRequest;
import java.util.Objects;

@Component
@AllArgsConstructor
@Slf4j
public class ToflyAuthenticationProvider implements AuthenticationProvider {

    private final UserDetailsService userDetailService;
    private final CacheManager cacheManager;

    /**
     * 进行身份认证
     */
    @Override
    public Authentication authenticate(Authentication authentication) throws AuthenticationException {
        log.info("身份认证开始");
        // 获取用户输入的用户名和密码
        String username = authentication.getName();
        if (StringUtil.isEmpty(username)) {
            throw new MyAuthenticationException("用户名不能为空");
        }
        String password = (String) authentication.getCredentials();
        if (StringUtil.isEmpty(password)) {
            throw new MyAuthenticationException("密码不能为空");
        }
        // 获取封装用户信息的对象
        UserDetails userDetails = userDetailService.loadUserByUsername(username);
        // 进行密码的比对
        HttpServletRequest request = ((ServletRequestAttributes) Objects
                .requireNonNull(RequestContextHolder.getRequestAttributes())).getRequest();
        log.info("ip:{}", IpUtil.getIpAddr(request));
        log.info("界面传过来的password:{}", password);
        log.info("数据库查询出来的password:{}", userDetails.getPassword());
        try {
            password = RSAUtils.priKeyDecryption(password);
        } catch (Exception exception) {
            exception.printStackTrace();
        }

        // 防止前端空串加密
        if (StringUtil.isEmpty(password)) {
            throw new MyAuthenticationException("密码不能为空");
        }

        BCryptPasswordEncoder bCryptPasswordEncoder = new BCryptPasswordEncoder();

        log.info("用{}加密后的密码为：{}", SecurityConstants.BCRYPT + password, bCryptPasswordEncoder.encode(SecurityConstants.BCRYPT + password));
        boolean flag = bCryptPasswordEncoder.matches(SecurityConstants.BCRYPT + password, userDetails.getPassword());

        ToflyUser toflyUser = null;
        Cache cache = cacheManager.getCache("user_details");
        if (cache != null && cache.get(username) != null && cache.get(username).get() != null) {
            toflyUser = (ToflyUser) cache.get(username).get();
        }

        User sysUser = new User();
        sysUser.setId(toflyUser.getUserid());
        Short pwdt = toflyUser.getPwderrtimes();
        if (pwdt == null) {
            pwdt = Short.valueOf("0");
        }

        if (pwdt >= 5 && !CommonConstants.SUPER_ADMIN_ULEVEL.equals(toflyUser.getUserLevel())) {
            //未登陆成功，清楚缓存，避免下次已经解锁登录时还是锁定状态
            cache.put(username, null);
            throw new MyAuthenticationException("账户已经被锁定，请联系管理人员");
        }

        // 校验通过
        if (flag) {
            sysUser.setPwderrtimes(Short.valueOf("0"));
            sysUser.setLastIp(IpUtil.getIpAddr(request));
            SpringContextHolder.publishEvent(new UserLoginEvent(sysUser));
            //如果密码错误次数不为0，则将缓存中的次数修改为0
            if (pwdt != 0) {
                ToflyUser toflyUser1 = new ToflyUser(Short.valueOf("0"), toflyUser.getParentCompanyId(), toflyUser.getParentCompanyName(), toflyUser.getCompanyId(), toflyUser.getCompanyName(), toflyUser.getUserid(), toflyUser.getDepartmentId(), toflyUser.getUserLevel(),
                        toflyUser.getRealName(), toflyUser.getDepartemntName(), toflyUser.getAvatar(),
                        toflyUser.getUsername(),/*SecurityConstants.BCRYPT+*/toflyUser.getPassword(),
                        true, true,
                        true, true, toflyUser.getAuthorities());
                cache.put(username, toflyUser1);
            }
            //将权限信息也封装进去
            return new UsernamePasswordAuthenticationToken(userDetails, password, userDetails.getAuthorities());
        }


        pwdt++;
        sysUser.setPwderrtimes(pwdt);
        if (pwdt >= 5) {
            sysUser.setLockFlag(CommonConstants.USER_LOCK_LOCKED);
        }

        SpringContextHolder.publishEvent(new UserLoginEvent(sysUser));
        cache.put(username, null);
        String message = pwdt < 5 ? "密码错误。当前密码错误次数是：" + pwdt + ",密码错误5次账户将会被锁定" :
                "账户已经被锁定，请联系管理人员";
        throw new MyAuthenticationException(message);
    }

    /**
     * 这个方法 确保返回 true 即可，
     *
     * @param aClass
     * @return
     */
    @Override
    public boolean supports(Class<?> aClass) {
        return true;
    }

    class MyAuthenticationException extends AuthenticationException {

        public MyAuthenticationException(String msg, Throwable t) {
            super(msg, t);
        }

        public MyAuthenticationException(String msg) {
            super(msg);
        }
    }
}