package com.gci.boot.modules.system.service.impl;

import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.StrUtil;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.gci.boot.common.util.ParamsCheckUtil;
import com.gci.boot.constant.CommonConstant;
import com.gci.boot.exception.GciBootException;
import com.gci.boot.modules.projects.entity.ProjectUserRel;
import com.gci.boot.modules.projects.service.IProjectUserRelService;
import com.gci.boot.modules.system.entity.*;
import com.gci.boot.modules.system.mapper.SysUserMapper;
import com.gci.boot.modules.system.service.*;
import com.gci.boot.modules.system.util.AesEncryptUtil;
import com.gci.boot.modules.system.util.PasswordUtil;
import com.gci.boot.modules.system.util.QsEncodeUtil;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.*;
import java.util.stream.Collectors;

/**
 * <p>
 * 用户表 服务实现类
 * </p>
 *
 * @author chenzhiwei
 * @since 2023-08-17
 */
@Service
public class SysUserServiceImpl extends ServiceImpl<SysUserMapper, SysUser> implements ISysUserService {

    @Autowired
    private ISysUserRoleService sysUserRoleService;

    @Autowired
    private ISysUserDepartService sysUserDepartService;

    @Autowired
    private ISysRoleService sysRoleService;

    @Autowired
    private ISysPermissionService sysPermissionService;

    @Autowired
    private ISysDepartService sysDepartService;

    @Autowired
    private SysUserMapper sysUserMapper;

    @Autowired
    private IProjectUserRelService projectUserRelService;

    @Override
    public SysUser getByUsername(String username){
        return lambdaQuery().eq(SysUser::getUsername, username).one();
    }

    @Transactional(rollbackFor = Exception.class)
    @Override
    public void addUserEncryptPassword(SysUser user, List<String> roleIds, List<String> departIds){
        ParamsCheckUtil.paramsAssert().notBlank(user.getUsername(), "【用户名】不能为空！")
                .notBlank(user.getPassword(), "【密码】不能为空！")
                .isTrue(lambdaQuery().eq(SysUser::getUsername, user.getUsername()).count() == 0, String.format("用户名【%s】已存在！", user.getUsername()))
                .isTrue(PasswordUtil.checkPassword(user.getPassword()), "密码必须由8-12位数字、大小写字母和特殊符号组成")
        ;

        user.setCreateTime(new Date());//设置创建时间
        String salt = PasswordUtil.generateSalt(8);
        user.setSalt(salt);
        String passwordEncode = PasswordUtil.encrypt(user.getUsername(), user.getPassword(), salt);
        user.setPassword(passwordEncode);
        addUser(user, roleIds, departIds);
    }

    @Transactional(rollbackFor = Exception.class)
    @Override
    public void editUserEncryptPassword(SysUser user, List<String> roleIds, List<String> departIds){
        ParamsCheckUtil.paramsAssert().notBlank(user.getUsername(), "【用户名】不能为空！")
                .isTrue(lambdaQuery().ne(SysUser::getId, user.getId()).eq(SysUser::getUsername, user.getUsername()).count() == 0, String.format("用户名【%s】已存在！", user.getUsername()));

        if(StringUtils.isNotBlank(user.getPassword())) {
            ParamsCheckUtil.assertTrue(PasswordUtil.checkPassword(user.getPassword()), "密码必须由8-12位数字、大小写字母和特殊符号组成");
            String salt = PasswordUtil.generateSalt(8);
            user.setSalt(salt);
            String passwordEncode = PasswordUtil.encrypt(user.getUsername(), user.getPassword(), salt);
            user.setPassword(passwordEncode);
        }
        editUser(user, roleIds, departIds);
    }

    @Transactional(rollbackFor = Exception.class)
    @Override
    public void addUser(SysUser user, List<String> roleIds, List<String> departIds){
        if(departIds != null && departIds.size()>0){
            SysDepart depart = sysDepartService.getById(departIds.get(0));
            if(depart != null){
                user.setOrgCode(depart.getOrgCode());
            }
        }
        save(user);
        addUserRoleAndDepart(user.getId(), roleIds, departIds);
    }

    @Override
    public void addInnerUser(SysUser user, List<String> roleIds, List<String> departIds, List<String> projectIds) {
        addUser(user,roleIds,departIds);
        //新增内部员工和部门的关系数据
        if(projectIds != null && projectIds.size()>0){
            List<ProjectUserRel> relList = new ArrayList<>();
            for(String id:projectIds){
                ProjectUserRel projUserRel = new ProjectUserRel();
                projUserRel.setUserId(user.getId());
                projUserRel.setProjectId(id);
                relList.add(projUserRel);
            }
            projectUserRelService.saveBatch(relList);
        }
    }

    @Transactional(rollbackFor = Exception.class)
    @Override
    public void editUser(SysUser user, List<String> roleIds, List<String> departIds){
        if (StringUtils.isBlank(user.getOrgCode()) && departIds != null && departIds.size() > 0) {
            SysDepart depart = sysDepartService.getById(departIds.get(0));
            if (depart != null) {
                user.setOrgCode(depart.getOrgCode());
            }
        }
        updateById(user);
        sysUserRoleService.lambdaUpdate().eq(SysUserRole::getUserId, user.getId()).remove();
        sysUserDepartService.lambdaUpdate().eq(SysUserDepart::getUserId, user.getId()).remove();
        addUserRoleAndDepart(user.getId(), roleIds, departIds);
    }

    @Transactional(rollbackFor = Exception.class)
    @Override
    public void editInnerUser(SysUser user, List<String> roleIds, List<String> departIds, List<String> projectIds) {
        editUser(user,roleIds,departIds);
        projectUserRelService.lambdaUpdate().eq(ProjectUserRel::getUserId, user.getId()).remove();
        //新增内部员工和部门的关系数据
        if(projectIds != null && projectIds.size()>0){
            List<ProjectUserRel> relList = new ArrayList<>();
            for(String id:projectIds){
                ProjectUserRel projUserRel = new ProjectUserRel();
                projUserRel.setUserId(user.getId());
                projUserRel.setProjectId(id);
                relList.add(projUserRel);
            }
            projectUserRelService.saveBatch(relList);
        }
    }

    private void addUserRoleAndDepart(String userId, List<String> roleIds, List<String> departIds){
        if(roleIds != null && roleIds.size() > 0){
            List<SysUserRole> roleList = new ArrayList<>();
            for(String id:roleIds){
                SysUserRole sysUserRole = new SysUserRole();
                sysUserRole.setUserId(userId);
                sysUserRole.setRoleId(id);
                roleList.add(sysUserRole);
            }
            sysUserRoleService.saveBatch(roleList);
        }
        if(departIds != null && departIds.size()>0){
            List<SysUserDepart> depList = new ArrayList<>();
            for(String id:departIds){
                SysUserDepart sysUserDepart = new SysUserDepart();
                sysUserDepart.setUserId(userId);
                sysUserDepart.setDepId(id);
                depList.add(sysUserDepart);
            }
            sysUserDepartService.saveBatch(depList);
        }
    }


    @Override
    public String processPhone(SysUser user) {
        // 优先取phone字段
        if (StringUtils.isNotBlank(user.getPhone())) {
            return user.getPhone();
        }
        // 其次取解密后字段
        if (StringUtils.isNotBlank(user.getEncryptPhone()) && StringUtils.isNotBlank(user.getSecretPhone())) {
            try {
                return QsEncodeUtil.aesDecrypt(user.getEncryptPhone(), user.getSecretPhone());
            } catch (Exception e) {
                log.error("SysUser手机号解密失败,", e);
                return null;
            }
        }
        return null;
    }

    @Override
    public void resetPassword(String username, String oldPassword, String newPassword, String confirmPassword) {
        SysUser user = getByUsername(username);
        if (StrUtil.isBlank(oldPassword)) {
            throw new GciBootException("旧密码不能为空！");
        }
        if (StringUtils.isBlank(newPassword)) {
            throw new GciBootException("新密码不允许为空!");
        }
        if (!newPassword.equals(confirmPassword)) {
            throw new GciBootException("两次输入密码不一致!");
        }
        try {
            oldPassword = AesEncryptUtil.desEncrypt(oldPassword.replaceAll("%2B", "\\+")).trim();
            newPassword = AesEncryptUtil.desEncrypt(newPassword.replaceAll("%2B", "\\+")).trim();
            confirmPassword = AesEncryptUtil.desEncrypt(confirmPassword.replaceAll("%2B", "\\+")).trim();
        } catch (Exception e) {
            e.printStackTrace();
            log.error("修改密码解密错误！",e);
            throw new GciBootException("旧密码输入错误！");
        }
        String passwordEncode = PasswordUtil.encrypt(username, oldPassword, user.getSalt());
        if (!user.getPassword().equals(passwordEncode)) {
            throw new GciBootException("旧密码输入错误!");
        }
        if(!PasswordUtil.checkPassword(newPassword)){
            throw new GciBootException("密码必须由8-12位数字、大小写字母和特殊符号组成!");
        }
        String password = PasswordUtil.encrypt(username, newPassword, user.getSalt());

        lambdaUpdate().eq(SysUser::getId, user.getId())
                .set(SysUser::getPassword, password)
                .set(SysUser::getPasswordUpdateTime, new Date())
                .update();
    }
    @Override
    public Set<String> getUserRolesSet(String username){
        SysUser user = getByUsername(username);
        if(user != null) {
            return sysRoleService.getRoleCodeSetByUserId(user.getId());
        }
        return new HashSet<>();
    }

    @Override
    public Set<String> getUserRoleIdsSet(String username){
        SysUser user = getByUsername(username);
        if(user != null) {
            List<SysRole> roles = sysRoleService.getRoleByUserId(user.getId());
            return roles.stream().map(role-> role.getId()).collect(Collectors.toSet());
        }
        return new HashSet<>();
    }

    @Override
    public Set<String> getUserPermissionsSet(String username) {
        Set<String> roleIds = getUserRoleIdsSet(username);
        if(roleIds.size()>0) {
            return sysPermissionService.getPermCodeSetByroleIds(roleIds);
        }
        return new HashSet<>();
    }

    @Override
    public Map<String, String> getUserRoleIds(List<String> userIdList){
        QueryWrapper<SysUserRole> q = new QueryWrapper<>();
        q.select("string_agg(role_id,',') as role_id", "user_id");
        q.groupBy("user_id");
        q.in("user_id", userIdList);
        List<SysUserRole> roles = sysUserRoleService.list(q);
        Map<String, String> res = new LinkedHashMap<>();
        for(SysUserRole sur:roles){
            if(StringUtils.isBlank(sur.getRoleId())){
                continue;
            }
            res.put(sur.getUserId(), sur.getRoleId());
        }
        return res;
    }

    /**
     * 根据角色编码获取用户
     */
    @Override
    public List<SysUser> getByRoleCode(String roleCode){
    	if(StringUtils.isBlank(roleCode)) {
    		roleCode = CommonConstant.MAINTENANCE_ADMIN_ROLE_CODE;
    	}
    	String sql = "select 1 from sys_role r join sys_user_role ur on r.id = ur.role_id where sys_user.id = ur.user_id and r.role_code='"+roleCode+"'";
        return lambdaQuery().exists(sql).list();
    }


    @Transactional(rollbackFor = Exception.class)
    @Override
    public void deleteBatch(List<String> userIds){
        removeByIds(userIds);
        sysUserRoleService.lambdaUpdate().in(SysUserRole::getUserId, userIds).remove();
        sysUserDepartService.lambdaUpdate().in(SysUserDepart::getUserId, userIds).remove();
    }

    @Transactional(rollbackFor = Exception.class)
    @Override
    public void delete(String userId){
        removeById(userId);
        sysUserRoleService.lambdaUpdate().eq(SysUserRole::getUserId, userId).remove();
        sysUserDepartService.lambdaUpdate().eq(SysUserDepart::getUserId, userId).remove();
    }

    @Override
    public IPage<SysUser> queryInnerUserList(Page<SysUser> page, SysUser user) {
        return page.setRecords(sysUserMapper.queryInnerUserList(page,user));
    }

    @Override
    public IPage<SysUser> queryPageListV2(SysUser user, String roleName, String departName, String column, String order, Page<SysUser> page) {
        List<SysRole> roles = sysRoleService.lambdaQuery().like(StringUtils.isNotBlank(roleName),SysRole::getRoleName,roleName).list();
        List<String> roleIds = roles.stream().map(SysRole::getId).collect(Collectors.toList());
        List<SysUserRole> sysUserRoles = new ArrayList<>();
        if (ObjectUtil.isNotEmpty(roleIds)) {
            sysUserRoles = sysUserRoleService.lambdaQuery().in(SysUserRole::getRoleId, roleIds).list();
        }

        List<SysDepart> departs = sysDepartService.lambdaQuery().like(StringUtils.isNotBlank(departName), SysDepart::getDepartName, departName).list();
        List<String> departIds = departs.stream().map(SysDepart::getId).collect(Collectors.toList());
        List<SysUserDepart> sysUserDeparts = new ArrayList<>();
        if (ObjectUtil.isNotEmpty(departIds)) {
            sysUserDeparts = sysUserDepartService.lambdaQuery().in(SysUserDepart::getDepId, departIds).list();
        }

        List<String> allUserIdList = list().stream().map(SysUser::getId).collect(Collectors.toList());

        List<String> sysUserRoleIds;

        if (StrUtil.isBlank(roleName)) {
            sysUserRoleIds = allUserIdList;
        } else {
            sysUserRoleIds = sysUserRoles.stream().map(SysUserRole::getUserId).collect(Collectors.toList());
        }

        List<String> sysUserDepartIds;
        if (StrUtil.isBlank(departName)) {
            sysUserDepartIds = allUserIdList;
        } else {
            sysUserDepartIds = sysUserDeparts.stream().map(SysUserDepart::getUserId).collect(Collectors.toList());
        }

        return sysUserMapper.queryPageListV2(user,sysUserRoleIds,sysUserDepartIds,column,order,page);
    }

}
