package com.ruoyi.system.service.impl;

import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.util.ArrayUtil;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.StrUtil;
import com.mybatisflex.core.query.QueryWrapper;
import com.mybatisflex.core.util.UpdateEntity;
import com.mybatisflex.solon.service.impl.ServiceImpl;
import com.ruoyi.common.constants.UserConstant;
import com.ruoyi.common.enums.DictEnum;
import com.ruoyi.common.utils.CryptoUtil;
import com.ruoyi.common.utils.SecurityUtil;
import com.ruoyi.common.web.domain.model.LoginUser;
import com.ruoyi.common.web.domain.entity.SysRole;
import com.ruoyi.common.web.domain.entity.SysUser;
import com.ruoyi.common.web.exception.ServiceException;
import com.ruoyi.system.domain.SysPost;
import com.ruoyi.system.domain.SysUserPost;
import com.ruoyi.system.domain.SysUserRole;
import com.ruoyi.system.mapper.SysUserMapper;
import com.ruoyi.system.mapper.SysUserPostMapper;
import com.ruoyi.system.mapper.SysUserRoleMapper;
import com.ruoyi.system.service.ISysPostService;
import com.ruoyi.system.service.ISysRoleService;
import com.ruoyi.system.service.ISysUserService;
import org.noear.solon.annotation.Component;
import org.noear.solon.annotation.Inject;

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

/**
 * 系统用户 服务层实现
 * @author ruoyi
 */
@Component
public class SysUserServiceImpl extends ServiceImpl<SysUserMapper, SysUser> implements ISysUserService {

    @Inject
    SysUserMapper sysUserMapper;

    @Inject
    SysUserPostMapper sysUserPostMapper;

    @Inject
    SysUserRoleMapper sysUserRoleMapper;

    @Inject
    ISysRoleService sysRoleService;

    @Inject
    ISysPostService sysPostService;

    /**
     * 根据账号查询用户
     * @param userName
     * @return
     */
    @Override
    public SysUser selectSysUserByUserName(String userName) {
        return sysUserMapper.selectSysUserByUserName(userName, DictEnum.DEL_FLAG.OK.getValue());
    }

    /**
     * 查询用户列表
     * @param sysUser
     * @return
     */
    @Override
    public List<SysUser> selectUserList(SysUser sysUser) {
        return sysUserMapper.selectUserList(sysUser, DictEnum.DEL_FLAG.OK.getValue());
    }

    /**
     * 获取用户详情
     * @param userId
     * @param sysUser
     * @param sysRole
     * @return
     */
    @Override
    public Map<String, Object> info(Long userId, SysUser sysUser, SysRole sysRole) {
        sysUser.setUserId(userId);
        checkUserDataScope(sysUser);
        Map<String, Object> map = new HashMap<>();
        List<SysRole> roles = sysRoleService.selectRoleList(sysRole);
        map.put("roles", SecurityUtil.isAdmin(userId) ? roles : roles.stream().filter(r -> !r.isAdmin()).collect(Collectors.toList()));
        map.put("posts", sysPostService.list());
        if (userId != null) {
            SysUser user = sysUserMapper.selectUserById(userId);
            // 清除密码
            user.setPassword(null);
            map.put("data", user);
            map.put("postIds", sysPostService.selectPostListByUserId(userId));
            map.put("roleIds", user.getRoles().stream().map(SysRole::getRoleId).collect(Collectors.toList()));
        }
        return map;
    }

    /**
     * 新增用户
     * @param sysUser
     * @return
     */
    @Override
    public int add(SysUser sysUser) {
        if (!checkUserNameUnique(sysUser)) {
            throw new ServiceException("登录账号已存在");
        } else if (StrUtil.isNotEmpty(sysUser.getPhonenumber()) && !checkPhoneUnique(sysUser)) {
            throw new ServiceException("手机号码已存在");
        } else if (StrUtil.isNotEmpty(sysUser.getEmail()) && !checkEmailUnique(sysUser)) {
            throw new ServiceException("邮箱号已存在");
        }
        sysUser.setPassword(SecurityUtil.encryptPassword(sysUser.getPassword()));
        int row = sysUserMapper.insert(sysUser);
        // 新增用户岗位关联
        insertUserPost(sysUser);
        // 新增用户与角色管理
        insertUserRole(sysUser);
        return row;
    }

    /**
     * 注册用户
     * @param sysUser 用户信息
     * @return
     */
    @Override
    public int registerUser(SysUser sysUser) {
        return sysUserMapper.insert(sysUser);
    }

    /**
     * 修改用户
     * @param sysUser
     * @return
     */
    @Override
    public int edit(SysUser sysUser) {
        checkUserAllowed(sysUser);
        checkUserDataScope(sysUser);
        if (!checkUserNameUnique(sysUser)) {
            throw new ServiceException("登录账号已存在");
        } else if (StrUtil.isNotEmpty(sysUser.getPhonenumber()) && !checkPhoneUnique(sysUser)) {
            throw new ServiceException("手机号码已存在");
        } else if (StrUtil.isNotEmpty(sysUser.getEmail()) && !checkEmailUnique(sysUser)) {
            throw new ServiceException("邮箱账号已存在");
        }
        // 删除用户与角色关联
        sysUserRoleMapper.deleteUserRoleByUserId(sysUser.getUserId());
        // 新增用户与角色管理
        insertUserRole(sysUser);
        // 删除用户与岗位关联
        sysUserPostMapper.deleteUserPostByUserId(sysUser.getUserId());
        // 新增用户与岗位管理
        insertUserPost(sysUser);
        return sysUserMapper.update(sysUser);
    }

    /**
     * 删除用户
     * @param userIds
     * @param sysUser
     * @return
     */
    @Override
    public int delete(Long[] userIds, SysUser sysUser) {
        if (ArrayUtil.contains(userIds, SecurityUtil.getUserId())) {
            throw new ServiceException("当前用户不能删除");
        }
        for (Long userId : userIds) {
            sysUser.setUserId(userId);
            checkUserAllowed(sysUser);
            checkUserDataScope(sysUser);
        }
        // 删除用户与角色关联
        sysUserRoleMapper.deleteUserRole(userIds);
        // 删除用户与岗位关联
        sysUserPostMapper.deleteUserPost(userIds);
        return sysUserMapper.deleteBatchByIds(Arrays.asList(userIds));
    }

    /**
     * 重置密码
     * @param sysUser
     */
    @Override
    public int resetPwd(SysUser sysUser) {
        checkUserAllowed(sysUser);
        checkUserDataScope(sysUser);
        // 解密密码
        String password = sysUser.getPassword();
        try {
            password = CryptoUtil.rsaDecrypt(password);
        } catch (Exception ignored) {
        }
        // 密码是否在指定长度范围内
        if (password.length() < UserConstant.PASSWORD_MIN_LENGTH || password.length() > UserConstant.PASSWORD_MAX_LENGTH) {
            throw new ServiceException("密码长度不在指定范围");
        }
        SysUser user = UpdateEntity.of(SysUser.class, sysUser.getUserId());
        user.setPassword(SecurityUtil.encryptPassword(password));
        return sysUserMapper.update(user);
    }

    /**
     * 状态修改
     * @param sysUser
     * @return
     */
    @Override
    public int changeStatus(SysUser sysUser) {
        checkUserAllowed(sysUser);
        checkUserDataScope(sysUser);
        SysUser user = UpdateEntity.of(SysUser.class, sysUser.getUserId());
        user.setStatus(sysUser.getStatus());
        return sysUserMapper.update(user);
    }

    /**
     * 根据用户编号获取授权角色
     * @param userId
     * @param sysRole
     * @return
     */
    @Override
    public Map<String, Object> authRole(Long userId, SysRole sysRole) {
        Map<String, Object> map = new HashMap<>();
        SysUser sysUser = sysUserMapper.selectUserById(userId);
        List<SysRole> roles = sysRoleService.selectRolesByUserId(userId, sysRole);
        // 清除密码
        sysUser.setPassword(null);
        map.put("user", sysUser);
        map.put("roles", SecurityUtil.isAdmin(userId) ? roles : roles.stream().filter(r -> !r.isAdmin()).collect(Collectors.toList()));
        return map;
    }

    /**
     * 用户授权角色
     * @param userId
     * @param roleIds
     * @param sysUser
     */
    @Override
    public void insertAuthRole(Long userId, Long[] roleIds, SysUser sysUser) {
        sysUser.setUserId(userId);
        checkUserDataScope(sysUser);
        sysUserRoleMapper.deleteUserRoleByUserId(userId);
        insertUserRole(userId, roleIds);
    }

    /**
     * 查询角色已授权用户列表
     * @param sysUser 用户信息
     * @return
     */
    @Override
    public List<SysUser> selectAllocatedList(SysUser sysUser) {
        return sysUserMapper.selectAllocatedList(sysUser, DictEnum.DEL_FLAG.OK.getValue());
    }

    /**
     * 查询角色未授权用户列表
     * @param sysUser 用户信息
     * @return
     */
    @Override
    public List<SysUser> selectUnallocatedList(SysUser sysUser) {
        return sysUserMapper.selectUnallocatedList(sysUser, DictEnum.DEL_FLAG.OK.getValue());
    }

    /**
     * 校验账号是否唯一
     * @param sysUser 用户信息
     * @return
     */
    @Override
    public boolean checkUserNameUnique(SysUser sysUser) {
        long userId = sysUser.getUserId() == null ? -1L : sysUser.getUserId();
        QueryWrapper qw = QueryWrapper.create();
        qw.and(SysUser::getUserName).eq(sysUser.getUserName());
        qw.limit(1);
        SysUser su = sysUserMapper.selectOneByQuery(qw);
        return ObjectUtil.isNull(su) || su.getUserId() == userId;
    }

    /**
     * 校验用户是否有数据权限
     * @param sysUser
     */
    private void checkUserDataScope(SysUser sysUser) {
        if (!SecurityUtil.isAdmin(SecurityUtil.getUserId())) {
            List<SysUser> users = selectUserList(sysUser);
            if (CollectionUtil.isEmpty(users)) {
                throw new ServiceException("没有权限访问用户数据！");
            }
        }
    }

    /**
     * 个人中心 - 个人信息
     * @return
     */
    @Override
    public Map<String, Object> profile() {
        String userName = SecurityUtil.getUserName();
        SysUser sysUser = selectSysUserByUserName(userName);
        Map<String, Object> map = new HashMap<>();
        // 清除密码
        sysUser.setPassword(null);
        map.put("user", sysUser);
        List<SysRole> roles = sysRoleService.selectRolesByUserName(userName);
        map.put("roleGroup", CollectionUtil.isEmpty(roles) ? StrUtil.EMPTY : roles.stream().map(SysRole::getRoleName).collect(Collectors.joining(",")));
        List<SysPost> posts = sysPostService.selectPostsByUserName(userName);
        map.put("postGroup", CollectionUtil.isEmpty(posts) ? StrUtil.EMPTY : posts.stream().map(SysPost::getPostName).collect(Collectors.joining(",")));
        return map;
    }

    /**
     * 个人中心 - 修改用户
     * @param sysUser
     * @return
     */
    @Override
    public int updateProfile(SysUser sysUser) {
        LoginUser loginUser = SecurityUtil.getLoginUser();
        if(ObjectUtil.isNull(loginUser)) {
            throw new ServiceException("请登录");
        }
        SysUser currentUser = loginUser.getSysUser();
        currentUser.setNickName(sysUser.getNickName());
        currentUser.setEmail(sysUser.getEmail());
        currentUser.setPhonenumber(sysUser.getPhonenumber());
        currentUser.setSex(sysUser.getSex());
        if (StrUtil.isNotEmpty(sysUser.getPhonenumber()) && !checkPhoneUnique(currentUser)) {
            throw new ServiceException("手机号码已存在");
        }
        if (StrUtil.isNotEmpty(sysUser.getEmail()) && !checkEmailUnique(currentUser)) {
            throw new ServiceException("邮箱账号已存在");
        }
        int row = sysUserMapper.update(currentUser);
        if (row > 0) {
            // 更新缓存用户信息
            SecurityUtil.setLoginUser(loginUser);
        }
        return row;
    }

    /**
     * 个人中心 - 修改密码
     * @param oldPassword
     * @param newPassword
     * @return
     */
    @Override
    public int updateProfilePwd(String oldPassword, String newPassword) {
        // 账号密码非空
        if(!StrUtil.isAllNotEmpty(oldPassword, newPassword)) {
            throw new ServiceException("密码必须填写");
        }
        // 解密密码
        try {
            oldPassword = CryptoUtil.rsaDecrypt(oldPassword);
            newPassword = CryptoUtil.rsaDecrypt(newPassword);
        } catch (Exception ignored) {
        }
        // 密码是否在指定长度范围内
        if (newPassword.length() < UserConstant.PASSWORD_MIN_LENGTH || newPassword.length() > UserConstant.PASSWORD_MAX_LENGTH) {
            throw new ServiceException("密码长度不在指定范围");
        }
        String userName = SecurityUtil.getUserName();
        SysUser sysUser = selectSysUserByUserName(userName);
        String password = sysUser.getPassword();
        if (!SecurityUtil.matchesPassword(oldPassword, password)) {
            throw new ServiceException("旧密码错误");
        }
        if (SecurityUtil.matchesPassword(newPassword, password)) {
            throw new ServiceException("新密码不能与旧密码相同");
        }
        SysUser user = UpdateEntity.of(SysUser.class, SecurityUtil.getUserId());
        user.setPassword(SecurityUtil.encryptPassword(newPassword));
        return sysUserMapper.update(user);
    }

    /**
     * 个人中心 - 修改头像
     * @param avatar
     * @return
     */
    @Override
    public int updateProfileAvatar(String avatar) {
        SysUser user = UpdateEntity.of(SysUser.class, SecurityUtil.getUserId());
        user.setAvatar(avatar);
        int row = sysUserMapper.update(user);
        if (row > 0) {
            // 更新缓存用户头像
            LoginUser loginUser = SecurityUtil.getLoginUser();
            if(ObjectUtil.isNotNull(loginUser)) {
                loginUser.getSysUser().setAvatar(avatar);
                SecurityUtil.setLoginUser(loginUser);
            }
        }
        return row;
    }

    /**
     * 校验手机号码是否唯一
     * @param sysUser 用户信息
     * @return
     */
    private boolean checkPhoneUnique(SysUser sysUser) {
        long userId = sysUser.getUserId() == null ? -1L : sysUser.getUserId();
        QueryWrapper qw = QueryWrapper.create();
        qw.and(SysUser::getPhonenumber).eq(sysUser.getPhonenumber());
        qw.limit(1);
        SysUser su = sysUserMapper.selectOneByQuery(qw);
        return ObjectUtil.isNull(su) || su.getUserId() == userId;
    }

    /**
     * 校验email是否唯一
     * @param sysUser 用户信息
     * @return
     */
    private boolean checkEmailUnique(SysUser sysUser) {
        long userId = sysUser.getUserId() == null ? -1L : sysUser.getUserId();
        QueryWrapper qw = QueryWrapper.create();
        qw.and(SysUser::getEmail).eq(sysUser.getEmail());
        qw.limit(1);
        SysUser su = sysUserMapper.selectOneByQuery(qw);
        return ObjectUtil.isNull(su) || su.getUserId() == userId;
    }

    /**
     * 校验用户是否允许操作
     * @param sysUser 用户信息
     */
    private void checkUserAllowed(SysUser sysUser) {
        if(sysUser.getUserId() == null) {
            throw new ServiceException("非法操作！");
        }
        if (SecurityUtil.isAdmin(sysUser.getUserId())) {
            throw new ServiceException("不允许操作超级管理员用户");
        }
    }

    /**
     * 新增用户岗位信息
     * @param sysUser 用户对象
     */
    private void insertUserPost(SysUser sysUser) {
        Long[] posts = sysUser.getPostIds();
        if (ArrayUtil.isNotEmpty(posts)) {
            // 新增用户与岗位管理
            List<SysUserPost> list = new ArrayList<>();
            for (Long postId : posts) {
                SysUserPost up = new SysUserPost();
                up.setUserId(sysUser.getUserId());
                up.setPostId(postId);
                list.add(up);
            }
            sysUserPostMapper.insertBatch(list);
        }
    }

    /**
     * 新增用户角色信息
     * @param sysUser 用户对象
     */
    private void insertUserRole(SysUser sysUser) {
        this.insertUserRole(sysUser.getUserId(), sysUser.getRoleIds());
    }

    /**
     * 新增用户角色信息
     * @param userId 用户ID
     * @param roleIds 角色组
     */
    private void insertUserRole(Long userId, Long[] roleIds) {
        if (ArrayUtil.isNotEmpty(roleIds)) {
            // 新增用户与角色管理
            List<SysUserRole> list = new ArrayList<>();
            for (Long roleId : roleIds) {
                SysUserRole ur = new SysUserRole();
                ur.setUserId(userId);
                ur.setRoleId(roleId);
                list.add(ur);
            }
            sysUserRoleMapper.insertBatch(list);
        }
    }

}
