package ink.wgink.login.base.service.user;

import ink.wgink.common.enums.RoleDataRightEnum;
import ink.wgink.exceptions.SaveException;
import ink.wgink.exceptions.UpdateException;
import ink.wgink.interfaces.consts.ISystemConstant;
import ink.wgink.interfaces.group.IGroupUserBaseService;
import ink.wgink.interfaces.position.IPositionUserBaseService;
import ink.wgink.interfaces.role.IRoleDataRightBaseService;
import ink.wgink.interfaces.role.IRoleMenuBaseService;
import ink.wgink.interfaces.role.IRolePermissionBaseService;
import ink.wgink.interfaces.role.IRoleUserBaseService;
import ink.wgink.login.base.service.log.ILoginLogService;
import ink.wgink.login.base.util.UserLoginUtil;
import ink.wgink.pojo.bos.LoginUser;
import ink.wgink.pojo.bos.RoleGrantedAuthorityBO;
import ink.wgink.pojo.dtos.department.DepartmentSimpleDTO;
import ink.wgink.pojo.dtos.group.GroupSimpleDTO;
import ink.wgink.pojo.dtos.position.PositionSimpleDTO;
import ink.wgink.pojo.dtos.role.RoleSimpleDTO;
import ink.wgink.pojo.pos.DepartmentPO;
import ink.wgink.pojo.pos.GroupPO;
import ink.wgink.pojo.pos.PositionPO;
import ink.wgink.pojo.pos.RolePO;
import ink.wgink.properties.AccessControlProperties;
import ink.wgink.service.department.service.IDepartmentService;
import ink.wgink.service.department.service.IDepartmentUserService;
import ink.wgink.service.user.enums.UserTypeEnum;
import ink.wgink.service.user.service.IUserService;
import ink.wgink.util.UUIDUtil;
import ink.wgink.util.date.DateUtil;
import ink.wgink.util.request.RequestUtil;
import ink.wgink.util.thread.CachedThreadPoolUtil;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.core.AuthenticationException;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.stereotype.Service;

import java.util.*;

/**
 * When you feel like quitting. Think about why you started
 * 当你想要放弃的时候，想想当初你为何开始
 *
 * @ClassName: UserLoginService
 * @Description: 用户登录业务
 * @Author: WangGeng
 * @Date: 2020/5/25 3:32 下午
 * @Version: 1.0
 **/
@Service
public class UserLoginService {

    private static final Logger LOG = LoggerFactory.getLogger(UserLoginService.class);
    @Autowired
    private IUserService userService;
    @Autowired
    private IDepartmentService departmentService;
    @Autowired
    private IDepartmentUserService departmentUserService;
    @Autowired
    private ILoginLogService loginLogService;
    @Autowired(required = false)
    private IRoleDataRightBaseService roleDataRightBaseService;
    @Autowired(required = false)
    private IRoleUserBaseService roleUserBaseService;
    @Autowired(required = false)
    private IRoleMenuBaseService roleMenuBaseService;
    @Autowired(required = false)
    private IRolePermissionBaseService rolePermissionService;
    @Autowired(required = false)
    private IGroupUserBaseService groupUserBaseService;
    @Autowired(required = false)
    private IPositionUserBaseService positionUserBaseService;
    @Autowired
    private AccessControlProperties accessControlProperties;

    public void setLoginUserInfo(LoginUser loginUser) {
        LOG.debug("set authority");
        Set<GrantedAuthority> grantedAuthorities = new LinkedHashSet<>();
        boolean isAdmin = false;
        if (StringUtils.equalsIgnoreCase(ISystemConstant.ADMIN, loginUser.getUsername())) {
            grantedAuthorities.add(new RoleGrantedAuthorityBO(ISystemConstant.ADMIN));
        } else {
            List<RolePO> rolePOs = null;
            // 先处理授权，再创建对象，否则 grantedAuthorities 中无法赋值
            if (roleUserBaseService != null) {
                LOG.debug("check is admin");
                List<String> roleIds = roleUserBaseService.listRoleIdByUserId(loginUser.getUserId());
                isAdmin = UserLoginUtil.hasAdmin(roleIds);
                if (!isAdmin && loginUser.getUserType().equals(UserTypeEnum.SYSTEM.getValue())) {
                    // 非管理员，系统用户设置角色权限
                    LOG.debug("set role, not admin");
                    rolePOs = roleUserBaseService.listRolePOByRoleIds(roleIds);
                    UserLoginUtil.removalDuplicateRole(rolePOs);
                    grantedAuthorities.addAll(loadRoleAuthority(rolePOs));
                }
            }
            // 标记超管
            if (isAdmin) {
                LOG.debug("mark admin role");
                grantedAuthorities.add(new RoleGrantedAuthorityBO(ISystemConstant.ADMIN));
            } else {
                // 非超管设置其他信息
                if (rolePOs != null) {
                    List<RoleSimpleDTO> roleSimpleDTOs = roleUserBaseService.listSimple(rolePOs);
                    loginUser.setRoles(roleSimpleDTOs);
                }

                LOG.debug("set department");
                List<DepartmentPO> departmentPOs = departmentUserService.listDepartmentPOByUserId(loginUser.getUserId());
                List<DepartmentSimpleDTO> departmentSimpleDTOs = departmentUserService.listSimple(departmentPOs);
                loginUser.setDepartments(departmentSimpleDTOs);

                if (groupUserBaseService != null) {
                    LOG.debug("set group");
                    List<GroupPO> groupPOs = groupUserBaseService.listGroupPOByUserId(loginUser.getUserId());
                    List<GroupSimpleDTO> groupSimpleDTOs = groupUserBaseService.listSimple(groupPOs);
                    loginUser.setGroups(groupSimpleDTOs);
                }
                if (positionUserBaseService != null) {
                    LOG.debug("set position");
                    List<PositionPO> positionPOs = positionUserBaseService.listPositionPOByUserId(loginUser.getUserId());
                    List<PositionSimpleDTO> positionSimpleDTOs = positionUserBaseService.listSimple(positionPOs);
                    loginUser.setPositions(positionSimpleDTOs);
                }
            }
        }
        // 设置数据权限，排除超管
        if (!StringUtils.equalsIgnoreCase(ISystemConstant.ADMIN, loginUser.getUsername()) && !isAdmin) {
            // 非管理员，系统用户设置数据权限
            if (loginUser.getUserType().equals(UserTypeEnum.SYSTEM.getValue())) {
                LOG.debug("set data authority");
                setUserDataAuthority(loginUser);
            }
        }
        loginUser.setAuthorities(grantedAuthorities);
    }

    /**
     * 设置人员数据权限
     *
     * @param loginUser
     * @throws Exception
     */
    public void setUserDataAuthority(LoginUser loginUser) throws AuthenticationException {
        LOG.debug("取出所属部门列表");
        loginUser.setBaseDepartmentIds(departmentService.listRootId(loginUser.getDepartments()));
        LOG.debug("权限信息，判断数据权限");
        String roleDataAuthority = getDataRight(loginUser.getRoles());
        loginUser.setDataRight(roleDataAuthority);
        if (StringUtils.equals(RoleDataRightEnum.DEPARTMENT.getValue(), roleDataAuthority)) {
            LOG.debug("角色拥有部门的数据权限");
            List<String> departmentIds = new ArrayList<>();
            loginUser.getDepartments().forEach(departmentPO -> {
                departmentIds.add(departmentPO.getDepartmentId());
            });
            loginUser.setDataRightUserIds(departmentUserService.listUserId(departmentIds));
        } else if (StringUtils.equals(RoleDataRightEnum.CUSTOM.getValue(), roleDataAuthority)) {
            if (roleDataRightBaseService != null) {
                LOG.debug("角色拥有自定义数据权限");
                List<String> roleIds = new ArrayList<>();
                loginUser.getRoles().forEach(rolePO -> {
                    roleIds.add(rolePO.getRoleId());
                });
                loginUser.setDataRightUserIds(roleDataRightBaseService.listUserId(roleIds));
            }
        }
    }

    /**
     * 更新用户登录信息
     *
     * @param userId
     */
    public void updateUserLoginInfo(String userId, String userName, String loginType) {
        String address = RequestUtil.getRequestIp();
        String currentTime = DateUtil.getTime();
        CachedThreadPoolUtil.execute(() -> {
            LOG.debug("更新登录信息");
            updateLoginInfo(userId, address, currentTime);
            LOG.debug("新增登录日志");
            saveLoginLogger(userId, userName, loginType, address, currentTime);
        });
    }

    /**
     * 登录日志
     *
     * @param userId
     * @param userName
     * @param loginType
     * @param address
     * @param currentTime
     * @throws SaveException
     */
    private void saveLoginLogger(String userId, String userName, String loginType, String address, String currentTime) throws SaveException {
        Map<String, Object> params = new HashMap<>(12);
        params.put("loginLogId", UUIDUtil.getUUID());
        params.put("loginAddress", address);
        params.put("loginType", loginType);
        params.put("gmtCreate", currentTime);
        params.put("creator", userId);
        params.put("creatorName", userName);
        loginLogService.save(params);
    }

    /**
     * 更新登录信息
     *
     * @param userId
     * @param address
     * @param currentTime
     * @throws UpdateException
     */
    private void updateLoginInfo(String userId, String address, String currentTime) throws UpdateException {
        Map<String, Object> params = new HashMap<>(10);
        params.put("userId", userId);
        params.put("lastLoginAddress", address);
        params.put("lastLoginTime", currentTime);
        params.put("gmtModified", currentTime);
        params.put("modifier", userId);
        userService.updateLoginInfo(params);
    }

    /**
     * 获取数据权限
     *
     * @param roles
     * @return
     */

    public String getDataRight(List<RoleSimpleDTO> roles) {
        String roleDataAuthority = RoleDataRightEnum.SELF.getValue();
        for (RoleSimpleDTO roleSimplePO : roles) {
            if (StringUtils.equals(RoleDataRightEnum.ALL.getValue(), roleSimplePO.getRoleDataRight())) {
                roleDataAuthority = RoleDataRightEnum.ALL.getValue();
                break;
            }
            if (StringUtils.equals(RoleDataRightEnum.DEPARTMENT.getValue(), roleSimplePO.getRoleDataRight())) {
                roleDataAuthority = RoleDataRightEnum.DEPARTMENT.getValue();
                break;
            }
            if (StringUtils.equals(RoleDataRightEnum.CUSTOM.getValue(), roleSimplePO.getRoleDataRight())) {
                roleDataAuthority = RoleDataRightEnum.CUSTOM.getValue();
                break;
            }
        }
        return roleDataAuthority;
    }

    /**
     * 角色授权列表
     *
     * @param rolePOs
     * @return
     */
    private List<GrantedAuthority> loadRoleAuthority(List<RolePO> rolePOs) {
        List<GrantedAuthority> grantedAuthorities = new ArrayList<>();
        if (null != rolePOs && !rolePOs.isEmpty()) {
            // 设置菜单权限
            rolePOs.forEach((rolePO) -> {
                List<String> menuUrls = roleMenuBaseService.listMenuUrl(rolePO.getRoleId());
                List<String> inserts = new ArrayList<>();
                List<String> deletes = new ArrayList<>();
                List<String> updates = new ArrayList<>();
                List<String> queries = new ArrayList<>();
                if (accessControlProperties.getRolePermission()) {
                    inserts.addAll(rolePermissionService.listPermissionUrl(rolePO.getRoleId(), IRolePermissionBaseService.PERMISSION_INSERT));
                    deletes.addAll(rolePermissionService.listPermissionUrl(rolePO.getRoleId(), IRolePermissionBaseService.PERMISSION_DELETE));
                    updates.addAll(rolePermissionService.listPermissionUrl(rolePO.getRoleId(), IRolePermissionBaseService.PERMISSION_UPDATE));
                    queries.addAll(rolePermissionService.listPermissionUrl(rolePO.getRoleId(), IRolePermissionBaseService.PERMISSION_QUERY));
                }
                grantedAuthorities.add(new RoleGrantedAuthorityBO(rolePO.getRoleId(), rolePO.getRoleName(), menuUrls, inserts, deletes, updates, queries));
            });

        }
        return grantedAuthorities;
    }

}
