package com.sysu.admin.support.shiro;

import com.google.common.collect.Lists;
import com.sysu.admin.support.system.organ.OrganRepository;
import com.sysu.admin.support.system.role.SRole;
import com.sysu.admin.support.system.role.SRoleRepository;
import com.sysu.admin.support.system.role_permission.RolePermission;
import com.sysu.admin.support.system.role_permission.RolePermissionRepository;
import com.sysu.admin.support.system.user.User;
import com.sysu.admin.support.system.user.UserRepository;
import com.sysu.admin.support.system.user_role.UserRole;
import com.sysu.admin.support.system.user_role.UserRoleRepository;
import org.apache.commons.lang3.ObjectUtils;
import org.apache.shiro.authc.*;
import org.apache.shiro.authc.pam.UnsupportedTokenException;
import org.apache.shiro.authz.AuthorizationInfo;
import org.apache.shiro.authz.SimpleAuthorizationInfo;
import org.apache.shiro.realm.AuthorizingRealm;
import org.apache.shiro.subject.PrincipalCollection;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpSession;
import java.sql.Timestamp;
import java.util.List;

/**
 * @title ShiroAuthenRealm
 * @description
 * @author XIE
 * @date 2020年4月24日下午10:09:47
 */
public class ShiroAuthenRealm extends AuthorizingRealm {

    @Autowired
    UserRepository mUserRepository;

    @Autowired
    UserRoleRepository mUserRoleRepository;

    @Autowired
    SRoleRepository mRoleRepository;

    @Autowired
    RolePermissionRepository mRolePermissionRepository;

    @Autowired
    OrganRepository organRepository;

    /**
     * 认证
     */
    @Override
    protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) {
        try {
            // 获取到当前线程绑定的请求对象
            ServletRequestAttributes servlet = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
            // 获取Request
            HttpServletRequest request = servlet.getRequest();
            // 获取Session
            HttpSession session = request.getSession();
            // 获取凭据
            ShiroToken mShiroAuthenToken = (ShiroToken) token;
            String username = mShiroAuthenToken.getUsername();
            String password = new String(mShiroAuthenToken.getPassword());
            // 是否访客登录
            if (username.equals("guest") && password.equals("guest")) {
                String nickname = "游客";
                session.setAttribute(User.FIELDS.nickname, nickname);
                ShiroPrincipal mPrincipal = new ShiroPrincipal(-1L, username, nickname);
                return new SimpleAuthenticationInfo(mPrincipal, password, getName());
            }
            // 判断验证码
            // if (!Captcha.get().validate("login", captcha, true).equals(Status.MATCHED)) {
            // throw new UnsupportedTokenException();
            // }
            // 登录失败次数
            int i;
            // 判断是否为空
            if ((username != null) && (password != null)) {
                // 查找用户
                User user = mUserRepository.findByUsername(username);
                // 判断是否存在
                if (ObjectUtils.isEmpty(user)) {
                    throw new UnknownAccountException();
                }
                // 判断密码
                if (!password.equals(user.getPassword())) {
                    i = user.getLastLoginFailures() + 1;
                    if (i > 0 && i < 3) {
                        // 输错1-2次，"用户名密码错误"
                        user.setLastLoginFailures(i);
                        mUserRepository.insertOrUpdate(user);
                        throw new IncorrectCredentialsException();
                    } else if (i >= 3 && i < 5) {
                        // 输错3-4次，"登录失败次数过多"
                        user.setLastLoginFailures(i);
                        mUserRepository.insertOrUpdate(user);
                        throw new ExcessiveAttemptsException();
                    } else if (i >= 5) {
                        // 输错5次，"帐号被锁定"
                        user.setIsEnable(1);
                        user.setLastLoginFailures(i);
                        mUserRepository.insertOrUpdate(user);
                        throw new LockedAccountException();
                    }
                }
                // 判断是否启用
                if (user.getIsEnable() == 1) {
                    throw new DisabledAccountException();
                }
                // 判断是否黑名单
                if (user.getIsBlack() == 1) {
                    throw new LockedAccountException();
                }
                user.setLastLoginFailures(0);
                user.setLastLoginDate(new Timestamp(System.currentTimeMillis()));
                if(user.getOrganId() == null){
                    user.setOrganId(organRepository.findFirstId());
                }
                mUserRepository.insertOrUpdate(user);
                // 创建新的用户会话对象
                session.setAttribute(User.FIELDS.nickname, user.getNickname());
                return new SimpleAuthenticationInfo(new ShiroPrincipal(user.getId(), username, user.getNickname()), password, getName());
            }
        } catch (Exception e) {
            if (e instanceof UnknownAccountException) {
                throw new UnknownAccountException();// 帐号
            } else if (e instanceof IncorrectCredentialsException) {
                throw new IncorrectCredentialsException();// 密码
            } else if (e instanceof UnsupportedTokenException) {
                throw new UnsupportedTokenException();// 验证码
            } else if (e instanceof ExcessiveAttemptsException) {
                throw new ExcessiveAttemptsException();// 登录次数
            } else if (e instanceof DisabledAccountException) {
                throw new DisabledAccountException();// 禁用
            } else if (e instanceof LockedAccountException) {
                throw new LockedAccountException();// 锁定
            } else if (e instanceof AuthenticationException) {
                throw new AuthenticationException();// 认证
            } else {
                e.printStackTrace();
            }
        }
        return null;
    }

    /**
     * 授权
     */
    @Override
    protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals) {
        // 角色列表
        List<String> roles = Lists.newArrayList();
        // 权限列表
        List<String> permissions = Lists.newArrayList();
        // 获取凭据
        ShiroPrincipal localPrincipal = (ShiroPrincipal) principals.fromRealm(getName()).iterator().next();
        if (localPrincipal != null) {
            // 查询用户角色信息
            List<UserRole> userRoles = mUserRoleRepository.getRoleByUsers(localPrincipal.getId());
            for (UserRole ur : userRoles) {
                // 查询角色
                SRole role = mRoleRepository.findOne(ur.getPk().roles());
                // 循环添加角色
                roles.add(role.getRole());
                // 查询角色权限
                List<RolePermission> rolePermissions = mRolePermissionRepository.getListByRole(ur.getPk().roles());
                // 循环添加角色权限
                for (RolePermission rolePermission : rolePermissions) {
                    permissions.add(rolePermission.getPermission());
                }
            }
            SimpleAuthorizationInfo localSimpleAuthorizationInfo = new SimpleAuthorizationInfo();
            localSimpleAuthorizationInfo.addStringPermissions(permissions);
            localSimpleAuthorizationInfo.addRoles(roles);
            return localSimpleAuthorizationInfo;
        }
        return null;
    }
}
