package com.ktg.framework.web.service;

import com.ktg.common.core.domain.entity.SysRole;
import com.ktg.common.core.domain.entity.SysUser;
import com.ktg.common.core.domain.model.LoginUser;
import com.ktg.common.core.redis.RedisCache;
import com.ktg.common.core.text.Convert;
import com.ktg.common.enums.UserStatus;
import com.ktg.common.exception.ServiceException;
import com.ktg.common.utils.DictUtils;
import com.ktg.common.utils.ServletUtils;
import com.ktg.common.utils.StringUtils;
import com.ktg.system.domain.vo.IsSystemAttributeVO;
import com.ktg.system.domain.vo.UserBlackVo;
import com.ktg.system.service.ISysRoleService;
import com.ktg.system.service.ISysUserService;
import com.ktg.system.strategy.PhoneUtils;
import eu.bitwalker.useragentutils.UserAgent;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.core.userdetails.UsernameNotFoundException;
import org.springframework.stereotype.Service;

import java.util.List;

import static com.ktg.common.constant.Constants.SYS_ATTR;

/**
 * 用户验证处理
 *
 * @author guoruan
 */
@Service
public class UserDetailsServiceImpl implements UserDetailsService {
    private static final Logger log = LoggerFactory.getLogger(UserDetailsServiceImpl.class);

    @Autowired
    private ISysUserService userService;
    @Autowired
    private ISysRoleService iSysRoleService;

    @Autowired
    private SysPermissionService permissionService;

    @Autowired
    private RedisCache redisCache;

    @Override
    public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
        SysUser user = null;
        if (PhoneUtils.isMobile(username)) {
            user = userService.selectUserByMobile(username);
        }

        if (!StringUtils.isNotNull(user)) {
            user = userService.selectUserByUserName(username);
            if (StringUtils.isNotNull(user)) {
                // 开始放入岗位的权限数据
                List<Long> userWorkstationIds = userService.getUserWorkstationIds(user.getUserId());
                if (!userWorkstationIds.isEmpty()) {
                    // 将List<Long>转换为Long[]
                    Long[] array = new Long[userWorkstationIds.size()];
                    Long[] workstationIdsArray = userWorkstationIds.toArray(array);
                    user.setWorkstationIds(workstationIdsArray);
                }
            }
        }

        if (StringUtils.isNull(user)) {
            log.info("登录用户：{} 不存在.", username);
            throw new ServiceException("登录用户：" + username + " 不存在");
        } else if (UserStatus.DELETED.getCode().equals(user.getDelFlag())) {
            log.info("登录用户：{} 已被删除.", username);
            throw new ServiceException("对不起，您的账号：" + username + " 已被删除");
        } else if (UserStatus.DISABLE.getCode().equals(user.getStatus())) {
            log.info("登录用户：{} 已被停用.", username);
            throw new ServiceException("对不起，您的账号：" + username + " 已停用");
        } else {
            // 检查用户在该模块是否是黑名单
            UserAgent userAgent = UserAgent.parseUserAgentString(ServletUtils.getRequest().getHeader("User-Agent"));
            String headerModule = ServletUtils.getRequest().getHeader("Module");
            // 1.获取用户黑名单
            List<UserBlackVo> userBlackList = userService.getUserBlackList(user.getUserId());
            if (!userBlackList.isEmpty()) {
                for (UserBlackVo userBlackVo : userBlackList) {
                    String module = DictUtils.getDictLabel("module", userBlackVo.getModule());
                    if (StringUtils.isNotBlank(module) && userAgent.getOperatingSystem().getName().contains(module)) {
                        log.info("登录用户：{} 已被拉入 {} 模块黑名单.", username, module);
                        throw new ServiceException("对不起，您的账号：" + username + " 已被拉入" + module + "模块黑名单，暂时无法登录！");
                    }
                    if (StringUtils.isNotBlank(headerModule) && headerModule.equals(module)) {
                        log.info("登录用户：{} 已被拉入 {} 模块黑名单.", username, module);
                        throw new ServiceException("对不起，您的账号：" + username + " 已被拉入" + module + "模块黑名单，暂时无法登录！");
                    }
                }
            }
            // 2.检查安卓的登录，根据登录模块和角色决定
            if (!"admin".equals(username) && StringUtils.isNotBlank(headerModule) && "Android_Normal".equals(headerModule)) {
                Boolean b = checkLoginByAttrModule(headerModule, user.getUserId());
                if (!b) {
                    log.info("登录用户：{} 正在登录 {} 模块，由于您无相关角色，无法登录.", username, headerModule);
                    throw new ServiceException("对不起，您的账号：" + username + " 缺失角色权限，暂时无法登录。请前往角色或基础数据配置！");
                }
            }
        }
        return createLoginUser(user);
    }

    public UserDetails createLoginUser(SysUser user) {
        return new LoginUser(user.getUserId(), user.getDeptId(), user, permissionService.getMenuPermission(user));
    }

    // 检测用户的角色能否在该模块登录
    private Boolean checkLoginByAttrModule(String headerModule, Long userId) {
        if (userId != null) {
            // 1.获取用户的角色
            List<SysRole> roles = iSysRoleService.getRolesByUserId(userId);
            if (!roles.isEmpty()) {
                if ("Android_Normal".equals(headerModule)) {
                    // 机柜
                    IsSystemAttributeVO cacheObject = redisCache.getCacheObject(SYS_ATTR + "sys.loto_cabinet.role");
                    if (cacheObject != null && StringUtils.isNotBlank(cacheObject.getSysAttrValue())) {
                        String[] strArray = Convert.toStrArray(cacheObject.getSysAttrValue());
                        for (SysRole role : roles) {
                            for (String s : strArray) {
                                if (role.getRoleKey().equals(s)) {
                                    return true;
                                }
                            }
                        }
                    }
                }
            }
        }
        return false;
    }

}
