package com.xkrs.common.account;

import com.xkrs.model.entity.SysAuthorityEntity;
import com.xkrs.model.entity.SysUserEntity;
import com.xkrs.service.SysAuthorityService;
import com.xkrs.service.SysRoleService;
import com.xkrs.service.SysUserService;
import org.springframework.security.authentication.AuthenticationProvider;
import org.springframework.security.authentication.BadCredentialsException;
import org.springframework.security.authentication.DisabledException;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.AuthenticationException;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.stereotype.Component;

import javax.annotation.PostConstruct;
import javax.annotation.Resource;
import java.util.ArrayList;
import java.util.List;

import static com.xkrs.utils.EncryptDecryptUtil.encry256;

/**
 * 自定义认证Provider
 * @author tajochen
 */
@Component
public class CustomAuthenticationProvider implements AuthenticationProvider {

    @Resource
    private SysUserService sysUserService;

    @Resource
    private SysRoleService sysRoleService;

    @Resource
    private SysAuthorityService sysAuthorityService;

    /**
     * 初使化时将已静态化的Service实例化
     */
    protected static CustomAuthenticationProvider customAuthenticationProvider;

    /**
     * 通过@PostConstruct实现初始化bean之前进行的操作
     */
    @PostConstruct
    public void init() {
        customAuthenticationProvider = this;
        customAuthenticationProvider.sysUserService = this.sysUserService;
        customAuthenticationProvider.sysRoleService = this.sysRoleService;
        customAuthenticationProvider.sysAuthorityService = this.sysAuthorityService;
    }

    /**
     * 用户认证授权
     * @param authentication
     * @return
     * @throws AuthenticationException
     */
    @Override
    public Authentication authenticate(Authentication authentication) throws AuthenticationException {
        // 获取认证的用户名 & 密码
        String userName = authentication.getName();
        String password = authentication.getCredentials().toString();

        SysUserEntity userEntity = customAuthenticationProvider.sysUserService.getSysUserByUserName(userName);

        // 检查用户是否存在
        if(userEntity == null){
            throw new BadCredentialsException("user don't exist");
        }

        // 检查用户是否激活
        if(userEntity.getActiveFlag().intValue() != 0){
            throw new DisabledException("user not activated");
        }

        //检查用户状态是否正常
        if(userEntity.getStatusCode() != 0){
            throw new DisabledException("user state exception");
        }
        // 认证逻辑
        String encryptPassword = encry256(password + userEntity.getSalt());
        if (encryptPassword.equals(userEntity.getPassword())) {
            // 设置权限列表
            ArrayList<GrantedAuthority> permissions = new ArrayList<>();
            List<Integer> integers = customAuthenticationProvider.sysAuthorityService.selectAuthorityByUserId(userEntity.getId());
            List<SysAuthorityEntity> permissionList = customAuthenticationProvider.sysAuthorityService.findAllByIdIn(integers);
            for(SysAuthorityEntity sysAuthorityEntity : permissionList) {
                permissions.add(new GrantedAuthorityImpl(sysAuthorityEntity.getAuthorityName()));
            }
            // 生成令牌
            Authentication authToken = new UsernamePasswordAuthenticationToken(userName, encryptPassword, permissions);
            return authToken;
        }else if(password.equals(userEntity.getPassword())){
            // 设置权限列表
            ArrayList<GrantedAuthority> permissions = new ArrayList<>();
            List<Integer> integers = customAuthenticationProvider.sysAuthorityService.selectAuthorityByUserId(userEntity.getId());
            List<SysAuthorityEntity> permissionList = customAuthenticationProvider.sysAuthorityService.findAllByIdIn(integers);
            for(SysAuthorityEntity sysAuthorityEntity : permissionList) {
                permissions.add(new GrantedAuthorityImpl(sysAuthorityEntity.getAuthorityName()));
            }
            // 生成令牌
            Authentication authToken = new UsernamePasswordAuthenticationToken(userName, encryptPassword, permissions);
            return authToken;
        }
        else {
            throw new BadCredentialsException("user password error");
        }
    }

    /**
     * 是否可以提供输入类型的认证服务
     * @param authentication
     * @return
     */
    @Override
    public boolean supports(Class<?> authentication) {
        return authentication.equals(UsernamePasswordAuthenticationToken.class);
    }
}
