package org.dromara.system.service.impl;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.convert.Convert;
import cn.hutool.core.util.ArrayUtil;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.crypto.digest.BCrypt;
import com.baomidou.mybatisplus.core.conditions.Wrapper;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.hotwj.platform.driverManagement.driver.mapper.HotDriverMapper;
import com.hotwj.platform.integration.face.FaceMatchResult;
import com.hotwj.platform.integration.face.FaceRecognitionService;
import com.hotwj.platform.resourceManagement.company.domain.SysUserLoginPort;
import com.hotwj.platform.resourceManagement.company.mapper.SysUserLoginPortMapper;
import com.hotwj.platform.resourceManagement.companySafetyManager.mapper.HotCompanySafetyManagerMapper;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.dromara.common.core.constant.CacheNames;
import org.dromara.common.core.constant.SystemConstants;
import org.dromara.common.core.domain.dto.UserDTO;
import org.dromara.common.core.domain.model.LoginUser;
import org.dromara.common.core.exception.ServiceException;
import org.dromara.common.core.service.UserService;
import org.dromara.common.core.utils.*;
import org.dromara.common.mybatis.core.page.PageQuery;
import org.dromara.common.mybatis.core.page.TableDataInfo;
import org.dromara.common.oss.core.OssClient;
import org.dromara.common.oss.factory.OssFactory;
import com.hotwj.platform.driverManagement.driver.domain.vo.HotDriverVo;
import com.hotwj.platform.resourceManagement.company.service.ISysUserLoginPortService;
import com.hotwj.platform.resourceManagement.companySafetyManager.domain.vo.HotCompanySafetyManagerVo;
import org.dromara.common.core.utils.StringUtils;
import org.dromara.common.satoken.utils.LoginHelper;
import org.dromara.system.domain.SysUser;
import org.dromara.system.domain.SysUserPost;
import org.dromara.system.domain.SysUserRole;
import org.dromara.system.domain.bo.SysUserBo;
import org.dromara.system.domain.vo.*;
import org.dromara.system.mapper.*;
import org.dromara.system.service.ISysOssService;
import org.dromara.system.service.ISysUserService;
import org.springframework.cache.annotation.CacheEvict;
import org.springframework.cache.annotation.Cacheable;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.multipart.MultipartFile;

import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.util.*;
import java.util.stream.Collectors;

import static com.hotwj.platform.resourceManagement.company.service.ISysUserLoginPortService.HEADQUARTERS_PORT;

/**
 * 用户 业务层处理
 *
 * @author shihongwei
 */
@Slf4j
@RequiredArgsConstructor
@Service
public class SysUserServiceImpl implements ISysUserService, UserService {

    private final SysUserMapper baseMapper;
    private final SysDeptMapper deptMapper;
    private final SysRoleMapper roleMapper;
    private final SysPostMapper postMapper;
    private final SysUserRoleMapper userRoleMapper;
    private final SysUserPostMapper userPostMapper;
    private final SysUserLoginPortMapper sysUserLoginPortMapper;
    private final ISysOssService sysOssService;
    private final FaceRecognitionService faceRecognitionService;
    private final HotCompanySafetyManagerMapper safetyManagerMapper;
    private final HotDriverMapper driverMapper;

    @Override
    public boolean verifyUserFace(Long userId, MultipartFile file) {
        LoginUser loginUser = LoginHelper.getLoginUser();
        if (loginUser == null) {
            throw new ServiceException("用户未登录");
        }

        Long ossId = null;
        String businessUserId = loginUser.getBusinessUserId();

        if (StringUtils.isBlank(businessUserId)) {
            throw new ServiceException("未找到关联的业务人员信息");
        }

        // 根据登录端口判断业务身份
        if (ISysUserLoginPortService.ENTERPRISE_PORT.equals(loginUser.getLoginPort())) {
            // 安全管理人员
            HotCompanySafetyManagerVo manager = safetyManagerMapper.selectVoById(Long.valueOf(businessUserId));
            if (manager != null && StringUtils.isNotBlank(manager.getAvatarUrl())) {
                try {
                    ossId = Long.valueOf(manager.getAvatarUrl());
                } catch (NumberFormatException e) {
                    // 兼容旧数据存的是URL的情况，如果存的是URL，需要根据URL反查OSS ID或者直接下载
                    // 这里假设新逻辑都存OSS ID。如果存的是URL，且是本系统OSS的URL，可以尝试解析
                    // 简单起见，如果无法转为Long，说明没存ID，抛错提示重新上传
                    throw new ServiceException("初始照片格式不正确，请重新上传");
                }
            }
        } else if (ISysUserLoginPortService.DRIVER_PORT.equals(loginUser.getLoginPort())) {
            // 驾驶员
            HotDriverVo driver = driverMapper.selectVoById(businessUserId);
            if (driver != null && StringUtils.isNotBlank(driver.getPortraitUrl())) {
                try {
                    ossId = Long.valueOf(driver.getPortraitUrl());
                } catch (NumberFormatException e) {
                    throw new ServiceException("初始照片格式不正确，请重新上传");
                }
            }
        } else {
            throw new ServiceException("当前登录身份不支持人脸验证");
        }

        if (ossId == null) {
            throw new ServiceException("未设置人脸初始照片，请先上传");
        }

        SysOssVo ossVo = sysOssService.getById(ossId);
        if (ossVo == null) {
            throw new ServiceException("人脸初始照片文件不存在");
        }

        // 获取初始照片 Base64
        String originalBase64;
        try (ByteArrayOutputStream bos = new ByteArrayOutputStream()) {
            OssClient client = OssFactory.instance(ossVo.getService());
            client.download(ossVo.getFileName(), bos, null);
            originalBase64 = cn.hutool.core.codec.Base64.encode(bos.toByteArray());
        } catch (Exception e) {
            throw new ServiceException("读取初始照片失败: " + e.getMessage());
        }

        // 获取上传照片 Base64
        String uploadedBase64;
        try {
            uploadedBase64 = cn.hutool.core.codec.Base64.encode(file.getBytes());
        } catch (IOException e) {
            throw new ServiceException("读取上传照片失败");
        }

        // 比对
        FaceMatchResult result = faceRecognitionService.match(originalBase64, uploadedBase64);
        if (!result.isMatch()) {
            log.warn("人脸比对失败，用户ID: {}, 相似度: {}", userId, result.getScore());
        }
        return result.isMatch();
    }

    @Override
    public TableDataInfo<SysUserVo> selectPageUserList(SysUserBo user, PageQuery pageQuery) {
        Page<SysUserVo> page = baseMapper.selectPageUserList(pageQuery.build(), this.buildQueryWrapper(user));
        
        // 如果指定了端口和公司，尝试回显该端口下的独立账号
        if (CollUtil.isNotEmpty(user.getLoginPort()) && ObjectUtil.isNotNull(user.getCompanyId())) {
            String loginPort = user.getLoginPort().get(0);
            Long companyId = user.getCompanyId();
            List<SysUserVo> records = page.getRecords();
            if (CollUtil.isNotEmpty(records)) {
                List<Long> userIds = StreamUtils.toList(records, SysUserVo::getUserId);
                // 批量查端口账号
                if (CollUtil.isNotEmpty(userIds)) {
                    Map<Long, String> portUsernameMap = sysUserLoginPortMapper.selectList(new LambdaQueryWrapper<SysUserLoginPort>()
                        .eq(SysUserLoginPort::getCompanyId, companyId)
                        .eq(SysUserLoginPort::getLoginPort, loginPort)
                        .in(SysUserLoginPort::getUserId, userIds))
                        .stream()
                        .filter(p -> StringUtils.isNotBlank(p.getUsername()))
                        .collect(Collectors.toMap(SysUserLoginPort::getUserId, SysUserLoginPort::getUsername, (v1, v2) -> v1));
                    
                    // 替换
                    for (SysUserVo vo : records) {
                        String portUsername = portUsernameMap.get(vo.getUserId());
                        if (StringUtils.isNotBlank(portUsername)) {
                            vo.setUserName(portUsername);
                        }
                    }
                }
            }
        }
        return TableDataInfo.build(page);
    }

    /**
     * 根据条件分页查询用户列表
     *
     * @param user 用户信息
     * @return 用户信息集合信息
     */
    @Override
    public List<SysUserExportVo> selectUserExportList(SysUserBo user) {
        Map<String, Object> params = user.getParams();
        QueryWrapper<SysUser> wrapper = Wrappers.query();
        wrapper.eq("u.del_flag", SystemConstants.NORMAL)
                .like(StringUtils.isNotBlank(user.getUserName()), "u.user_name", user.getUserName())
                .like(StringUtils.isNotBlank(user.getNickName()), "u.nick_name", user.getNickName())
                .eq(StringUtils.isNotBlank(user.getStatus()), "u.status", user.getStatus())
                .like(StringUtils.isNotBlank(user.getPhonenumber()), "u.phonenumber", user.getPhonenumber())
                .between(params.get("beginTime") != null && params.get("endTime") != null,
                        "u.create_time", params.get("beginTime"), params.get("endTime"))
                .and(ObjectUtil.isNotNull(user.getDeptId()), w -> {
                    List<Long> deptIds = deptMapper.selectDeptAndChildById(user.getDeptId());
                    w.in("u.dept_id", deptIds);
                }).orderByAsc("u.user_id");
        return baseMapper.selectUserExportList(wrapper);
    }

    private Wrapper<SysUser> buildQueryWrapper(SysUserBo user) {
        Map<String, Object> params = user.getParams();
        LambdaQueryWrapper<SysUser> wrapper = Wrappers.lambdaQuery();
        wrapper.eq(SysUser::getDelFlag, SystemConstants.NORMAL)
                .eq(ObjectUtil.isNotNull(user.getUserId()), SysUser::getUserId, user.getUserId())
                .in(StringUtils.isNotBlank(user.getUserIds()), SysUser::getUserId, StringUtils.splitTo(user.getUserIds(), Convert::toLong))
                .like(StringUtils.isNotBlank(user.getUserName()), SysUser::getUserName, user.getUserName())
                .like(StringUtils.isNotBlank(user.getNickName()), SysUser::getNickName, user.getNickName())
                .eq(StringUtils.isNotBlank(user.getStatus()), SysUser::getStatus, user.getStatus())
                .like(StringUtils.isNotBlank(user.getPhonenumber()), SysUser::getPhonenumber, user.getPhonenumber())
                .between(params.get("beginTime") != null && params.get("endTime") != null,
                        SysUser::getCreateTime, params.get("beginTime"), params.get("endTime"))
                .and(ObjectUtil.isNotNull(user.getDeptId()), w -> {
                    List<Long> ids = deptMapper.selectDeptAndChildById(user.getDeptId());
                    w.in(SysUser::getDeptId, ids);
                }).orderByAsc(SysUser::getUserId);
        if (StringUtils.isNotBlank(user.getExcludeUserIds())) {
            wrapper.notIn(SysUser::getUserId, StringUtils.splitTo(user.getExcludeUserIds(), Convert::toLong));
        }
        if (CollUtil.isNotEmpty(user.getLoginPort())) {
            List<String> ports = user.getLoginPort();
            boolean hasOther = ports.contains("other");
            List<String> actualPorts = ports.stream()
                    .filter(port -> StringUtils.isNotBlank(port) && !"other".equals(port))
                    .collect(Collectors.toList());

            if (hasOther && CollUtil.isEmpty(actualPorts)) {
                wrapper.notInSql(SysUser::getUserId,
                        "select distinct user_id from sys_user_login_port where status = 1");
            } else if (!hasOther && CollUtil.isNotEmpty(actualPorts)) {
                String inPorts = actualPorts.stream()
                        .map(port -> "'" + port.replace("'", "''") + "'")
                        .collect(Collectors.joining(","));
                wrapper.inSql(SysUser::getUserId,
                        "select distinct user_id from sys_user_login_port where login_port in (" + inPorts + ") and status = 1");
            } else if (hasOther && CollUtil.isNotEmpty(actualPorts)) {
                String inPorts = actualPorts.stream()
                        .map(port -> "'" + port.replace("'", "''") + "'")
                        .collect(Collectors.joining(","));
                wrapper.and(w -> w.inSql(SysUser::getUserId,
                                "select distinct user_id from sys_user_login_port where login_port in (" + inPorts + ") and status = 1")
                        .or()
                        .notInSql(SysUser::getUserId,
                                "select distinct user_id from sys_user_login_port where status = 1"));
            }
        }
        return wrapper;
    }

    /**
     * 根据条件分页查询已分配用户角色列表
     *
     * @param user 用户信息
     * @return 用户信息集合信息
     */
    @Override
    public TableDataInfo<SysUserVo> selectAllocatedList(SysUserBo user, PageQuery pageQuery) {
        QueryWrapper<SysUser> wrapper = Wrappers.query();
        wrapper.eq("u.del_flag", SystemConstants.NORMAL)
                .eq(ObjectUtil.isNotNull(user.getRoleId()), "r.role_id", user.getRoleId())
                .like(StringUtils.isNotBlank(user.getUserName()), "u.user_name", user.getUserName())
                .eq(StringUtils.isNotBlank(user.getStatus()), "u.status", user.getStatus())
                .like(StringUtils.isNotBlank(user.getPhonenumber()), "u.phonenumber", user.getPhonenumber())
                .orderByAsc("u.user_id");
        Page<SysUserVo> page = baseMapper.selectAllocatedList(pageQuery.build(), wrapper);
        return TableDataInfo.build(page);
    }

    /**
     * 根据条件分页查询未分配用户角色列表
     *
     * @param user 用户信息
     * @return 用户信息集合信息
     */
    @Override
    public TableDataInfo<SysUserVo> selectUnallocatedList(SysUserBo user, PageQuery pageQuery) {
        List<Long> userIds = userRoleMapper.selectUserIdsByRoleId(user.getRoleId());
        QueryWrapper<SysUser> wrapper = Wrappers.query();
        wrapper.eq("u.del_flag", SystemConstants.NORMAL)
                .and(w -> w.ne("r.role_id", user.getRoleId()).or().isNull("r.role_id"))
                .notIn(CollUtil.isNotEmpty(userIds), "u.user_id", userIds)
                .like(StringUtils.isNotBlank(user.getUserName()), "u.user_name", user.getUserName())
                .like(StringUtils.isNotBlank(user.getPhonenumber()), "u.phonenumber", user.getPhonenumber())
                .orderByAsc("u.user_id");
        Page<SysUserVo> page = baseMapper.selectUnallocatedList(pageQuery.build(), wrapper);
        return TableDataInfo.build(page);
    }

    /**
     * 通过用户名查询用户
     *
     * @param userName 用户名
     * @return 用户对象信息
     */
    @Override
    public SysUserVo selectUserByUserName(String userName) {
        return baseMapper.selectVoOne(new LambdaQueryWrapper<SysUser>().eq(SysUser::getUserName, userName));
    }

    /**
     * 通过手机号查询用户
     *
     * @param phonenumber 手机号
     * @return 用户对象信息
     */
    @Override
    public SysUserVo selectUserByPhonenumber(String phonenumber) {
        return baseMapper.selectVoOne(new LambdaQueryWrapper<SysUser>().eq(SysUser::getPhonenumber, phonenumber));
    }

    /**
     * 通过用户ID查询用户
     *
     * @param userId 用户ID
     * @return 用户对象信息
     */
    @Override
    public SysUserVo selectUserById(Long userId) {
        SysUserVo user = baseMapper.selectVoById(userId);
        if (ObjectUtil.isNull(user)) {
            return user;
        }
        user.setRoles(roleMapper.selectRolesByUserId(user.getUserId()));
        return user;
    }

    /**
     * 通过用户ID串查询用户
     *
     * @param userIds 用户ID串
     * @param deptId  部门id
     * @return 用户列表信息
     */
    @Override
    public List<SysUserVo> selectUserByIds(List<Long> userIds, Long deptId) {
        return baseMapper.selectUserList(new LambdaQueryWrapper<SysUser>()
                .select(SysUser::getUserId, SysUser::getUserName, SysUser::getNickName)
                .eq(SysUser::getStatus, SystemConstants.NORMAL)
                .eq(ObjectUtil.isNotNull(deptId), SysUser::getDeptId, deptId)
                .in(CollUtil.isNotEmpty(userIds), SysUser::getUserId, userIds));
    }

    /**
     * 查询用户所属角色组
     *
     * @param userId 用户ID
     * @return 结果
     */
    @Override
    public String selectUserRoleGroup(Long userId) {
        List<SysRoleVo> list = roleMapper.selectRolesByUserId(userId);
        if (CollUtil.isEmpty(list)) {
            return StringUtils.EMPTY;
        }
        return StreamUtils.join(list, SysRoleVo::getRoleName);
    }

    /**
     * 查询用户所属岗位组
     *
     * @param userId 用户ID
     * @return 结果
     */
    @Override
    public String selectUserPostGroup(Long userId) {
        List<SysPostVo> list = postMapper.selectPostsByUserId(userId);
        if (CollUtil.isEmpty(list)) {
            return StringUtils.EMPTY;
        }
        return StreamUtils.join(list, SysPostVo::getPostName);
    }

    /**
     * 校验用户名称是否唯一
     *
     * @param user 用户信息
     * @return 结果
     */
    @Override
    public boolean checkUserNameUnique(SysUserBo user) {
        boolean exist = baseMapper.exists(new LambdaQueryWrapper<SysUser>()
                .eq(SysUser::getUserName, user.getUserName())
                .ne(ObjectUtil.isNotNull(user.getUserId()), SysUser::getUserId, user.getUserId()));
        return !exist;
    }

    /**
     * 校验手机号码是否唯一
     *
     * @param user 用户信息
     */
    @Override
    public boolean checkPhoneUnique(SysUserBo user) {
        if (StringUtils.isBlank(user.getPhonenumber())) {
            return true;
        }
        // 新增场景：允许同一手机号在多个企业、多端口下复用
        if (ObjectUtil.isNull(user.getUserId())) {
            return true;
        }
        // 编辑场景：仅防止把手机号改成其它用户已经使用的
        boolean exist = baseMapper.exists(new LambdaQueryWrapper<SysUser>()
            .eq(SysUser::getPhonenumber, user.getPhonenumber())
            .ne(SysUser::getUserId, user.getUserId()));
        return !exist;
    }

    /**
     * 校验email是否唯一
     *
     * @param user 用户信息
     */
    @Override
    public boolean checkEmailUnique(SysUserBo user) {
        boolean exist = baseMapper.exists(new LambdaQueryWrapper<SysUser>()
                .eq(SysUser::getEmail, user.getEmail())
                .ne(ObjectUtil.isNotNull(user.getUserId()), SysUser::getUserId, user.getUserId()));
        return !exist;
    }

    /**
     * 校验用户是否允许操作
     *
     * @param userId 用户ID
     */
    @Override
    public void checkUserAllowed(Long userId) {
        if (ObjectUtil.isNotNull(userId) && LoginHelper.isSuperAdmin(userId)) {
            throw new ServiceException("不允许操作超级管理员用户");
        }
    }

    /**
     * 校验用户是否有数据权限
     *
     * @param userId 用户id
     */
    @Override
    public void checkUserDataScope(Long userId) {
        if (ObjectUtil.isNull(userId)) {
            return;
        }
        if (LoginHelper.isSuperAdmin()) {
            return;
        }
        if (baseMapper.countUserById(userId) == 0) {
            throw new ServiceException("没有权限访问用户数据！");
        }
    }

    /**
     * 新增保存用户信息
     *
     * @param user 用户信息
     * @return 结果
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public int insertUser(SysUserBo user, boolean needInsertPort) {
        SysUser sysUser = baseMapper.selectOne(new LambdaQueryWrapper<SysUser>()
            .eq(SysUser::getPhonenumber, user.getPhonenumber()));
        int rows;
        if (sysUser == null) {
            sysUser = MapstructUtils.convert(user, SysUser.class);
            sysUser.setUserName(null);
            sysUser.setNickName(null);
            rows = baseMapper.insert(sysUser);
        } else {
            // 手机号已存在，复用用户，不覆盖昵称和用户名，仅更新必要字段（如密码，如果需要）
            // 注意：这里保留原逻辑更新密码，但不更新 userName 和 nickName
            if (StringUtils.isNotBlank(user.getPassword())) {
                sysUser.setPassword(user.getPassword());
                rows = baseMapper.updateById(sysUser);
            } else {
                rows = 1; // 无需更新，模拟成功
            }
        }
        user.setUserId(sysUser.getUserId());
        // 新增用户岗位关联
        insertUserPost(user, false);
        // 新增用户与角色管理
        insertUserRole(user, false);
        // 新增用户登录端口信息
        if (needInsertPort) {
            insertUserLoginPort(user);
        }
        return rows;
    }

    /**
     * 注册用户信息
     *
     * @param user 用户信息
     * @return 结果
     */
    @Override
    public boolean registerUser(SysUserBo user, String tenantId) {
        user.setCreateBy(0L);
        user.setUpdateBy(0L);
        SysUser sysUser = MapstructUtils.convert(user, SysUser.class);
        sysUser.setTenantId(tenantId);
        return baseMapper.insert(sysUser) > 0;
    }

    /**
     * 修改保存用户信息
     *
     * @param user 用户信息
     * @return 结果
     */
    @Override
    @CacheEvict(cacheNames = CacheNames.SYS_NICKNAME, key = "#user.userId")
    @Transactional(rollbackFor = Exception.class)
    public int updateUser(SysUserBo user, boolean needInsertPort) {
        // 新增用户与角色管理
        insertUserRole(user, true);
        // 新增用户与岗位管理
        insertUserPost(user, true);
        // 新增用户登录端口信息
        if (needInsertPort) {
            insertUserLoginPort(user);
        }

        SysUser sysUser = MapstructUtils.convert(user, SysUser.class);
        // 现在不在表里面保存用户名和昵称了
        sysUser.setUserName(null);
        sysUser.setNickName(null);
        // 防止错误更新后导致的数据误删除
        int flag = baseMapper.updateById(sysUser);
        if (flag < 1) {
            throw new ServiceException("修改用户{}信息失败", user.getUserName());
        }
        return flag;
    }

    /**
     * 用户授权角色
     *
     * @param userId    用户ID
     * @param roleIds   角色组
     * @param companyId 企业ID
     * @param loginPort 登录端口
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public void insertUserAuth(Long userId, Long[] roleIds, Long companyId, String loginPort) {
        insertUserRole(userId, roleIds, companyId, loginPort, true);
    }

    /**
     * 修改用户状态
     *
     * @param userId 用户ID
     * @param status 帐号状态
     * @return 结果
     */
    @Override
    public int updateUserStatus(Long userId, String status) {
        return baseMapper.update(null,
                new LambdaUpdateWrapper<SysUser>()
                        .set(SysUser::getStatus, status)
                        .eq(SysUser::getUserId, userId));
    }

    /**
     * 修改用户基本信息
     *
     * @param user 用户信息
     * @return 结果
     */
    @CacheEvict(cacheNames = CacheNames.SYS_NICKNAME, key = "#user.userId")
    @Override
    public int updateUserProfile(SysUserBo user) {
        return baseMapper.update(null,
                new LambdaUpdateWrapper<SysUser>()
                        .set(ObjectUtil.isNotNull(user.getNickName()), SysUser::getNickName, user.getNickName())
                        .set(SysUser::getPhonenumber, user.getPhonenumber())
                        .set(SysUser::getEmail, user.getEmail())
                        .set(SysUser::getSex, user.getSex())
                        .eq(SysUser::getUserId, user.getUserId()));
    }

    /**
     * 修改用户头像
     *
     * @param userId 用户ID
     * @param avatar 头像地址
     * @return 结果
     */
    @Override
    public boolean updateUserAvatar(Long userId, Long avatar) {
        return baseMapper.update(null,
            new LambdaUpdateWrapper<SysUser>()
                .set(SysUser::getAvatar, avatar)
                .eq(SysUser::getUserId, userId)) > 0;
    }

    /**
     * 修改用户人脸初始照片
     *
     * @param userId           用户ID
     * @param faceInitialPhoto 人脸初始照片
     * @return 结果
     */
    @Override
    public boolean updateUserFaceInitialOssId(Long userId, Long ossId) {
        return baseMapper.update(null,
            new LambdaUpdateWrapper<SysUser>()
                .set(SysUser::getFaceInitialOssId, ossId)
                .eq(SysUser::getUserId, userId)) > 0;
    }

    /**
     * 重置用户密码
     *
     * @param userId    用户ID
     * @param password  密码
     * @param companyId 公司ID（可选）
     * @return 结果
     */
    @Override
    public int resetUserPwd(Long userId, String password, Long companyId) {
        // 更新 sys_user 密码（保留给超级管理员或兼容，若只重置特定公司密码，则不应更新主密码，除非主密码和子密码逻辑有关联）
        // 考虑到用户要求“通过公司id来修改子密码”，如果指定了 companyId，那么我们只更新对应的 sub_password
        // 如果 companyId 为空，则按照原来的逻辑，全部重置（包括主密码）

        int rows = 0;
        if (companyId == null) {
            rows = baseMapper.update(null,
                    new LambdaUpdateWrapper<SysUser>()
                            .set(SysUser::getPassword, password)
                            .eq(SysUser::getUserId, userId));

            // 同时重置所有关联端口的子密码
            sysUserLoginPortMapper.update(null,
                    new LambdaUpdateWrapper<SysUserLoginPort>()
                            .set(SysUserLoginPort::getSubPassword, password)
                            .eq(SysUserLoginPort::getUserId, userId)
                            .eq(SysUserLoginPort::getStatus, 1));
        } else {
            // 指定了公司ID，仅重置该公司的子密码
            rows = sysUserLoginPortMapper.update(null,
                    new LambdaUpdateWrapper<SysUserLoginPort>()
                            .set(SysUserLoginPort::getSubPassword, password)
                            .eq(SysUserLoginPort::getUserId, userId)
                            .eq(SysUserLoginPort::getCompanyId, companyId)
                            .eq(SysUserLoginPort::getStatus, 1));
        }

        return rows;
    }

    /**
     * 新增用户登录端口信息
     *
     * @param user 用户对象
     */
    private void insertUserLoginPort(SysUserBo user) {
        if (CollUtil.isEmpty(user.getLoginPort())) {
            return;
        }
        String loginPort = user.getLoginPort().get(0);

        sysUserLoginPortMapper.delete(new LambdaQueryWrapper<SysUserLoginPort>()
                .eq(SysUserLoginPort::getUserId, user.getUserId())
                .eq(SysUserLoginPort::getCompanyId, user.getCompanyId())
                .eq(SysUserLoginPort::getLoginPort, loginPort));

        SysUserLoginPort userLoginPort = new SysUserLoginPort();
        userLoginPort.setUserId(user.getUserId());
        userLoginPort.setCompanyId(user.getCompanyId());
        userLoginPort.setLoginPort(loginPort);
        // 生成端口独立账号：端口_手机号
        if (StringUtils.isNotBlank(user.getUserName())) {
            userLoginPort.setUsername(user.getUserName());
        }
        if (user.getPortEnable() != null) {
            userLoginPort.setStatus(user.getPortEnable() ? 1 : 0);
        }
        // 初始化子密码，默认使用用户设置的密码，如果没有设置密码，则使用默认规则：手机号+hot
        if (StringUtils.isNotBlank(user.getPassword())) {
            userLoginPort.setSubPassword(user.getPassword());
        } else if (StringUtils.isNotBlank(user.getPhonenumber())) {
            userLoginPort.setSubPassword(BCrypt.hashpw(user.getPhonenumber() + "hot"));
        }
        sysUserLoginPortMapper.insert(userLoginPort);
    }

    /**
     * 新增用户角色信息
     *
     * @param user  用户对象
     * @param clear 清除已存在的关联数据
     */
    private void insertUserRole(SysUserBo user, boolean clear) {
        String loginPort = CollUtil.isEmpty(user.getLoginPort()) ? null : user.getLoginPort().get(0);
        this.insertUserRole(user.getUserId(), user.getRoleIds(), user.getCompanyId(), loginPort, clear);
    }

    /**
     * 新增用户岗位信息
     *
     * @param user  用户对象
     * @param clear 清除已存在的关联数据
     */
    private void insertUserPost(SysUserBo user, boolean clear) {
        Long[] postIdArr = user.getPostIds();
        if (ArrayUtil.isEmpty(postIdArr)) {
            return;
        }
        List<Long> postIds = Arrays.asList(postIdArr);

        // 校验是否有权限操作这些岗位（含数据权限控制）
        if (postMapper.selectPostCount(postIds) != postIds.size()) {
            throw new ServiceException("没有权限访问岗位的数据");
        }

        // 是否清除旧的用户岗位绑定
        if (clear) {
            userPostMapper.delete(new LambdaQueryWrapper<SysUserPost>().eq(SysUserPost::getUserId, user.getUserId()));
        }

        // 构建用户岗位关联列表并批量插入
        List<SysUserPost> list = StreamUtils.toList(postIds,
                postId -> {
                    SysUserPost up = new SysUserPost();
                    up.setUserId(user.getUserId());
                    up.setPostId(postId);
                    return up;
                });
        userPostMapper.insertBatch(list);
    }

    /**
     * 新增用户角色信息
     *
     * @param userId    用户ID
     * @param roleIds   角色组
     * @param companyId 企业ID
     * @param loginPort 登录端口
     * @param clear     清除已存在的关联数据
     */
    private void insertUserRole(Long userId, Long[] roleIds, Long companyId, String loginPort, boolean clear) {
        if (ArrayUtil.isEmpty(roleIds)) {
            return;
        }

        List<Long> roleList = new ArrayList<>(Arrays.asList(roleIds));

        // 非超级管理员，禁止包含超级管理员角色
        if (!LoginHelper.isSuperAdmin(userId)) {
            roleList.remove(SystemConstants.SUPER_ADMIN_ID);
        }

        // 校验是否有权限访问这些角色（含数据权限控制）
        if (roleMapper.selectRoleCount(roleList) != roleList.size()) {
            throw new ServiceException("没有权限访问角色的数据");
        }

        // 是否清除原有绑定
        if (clear) {
            userRoleMapper.delete(new LambdaQueryWrapper<SysUserRole>()
                    .eq(SysUserRole::getUserId, userId)
                    .eq(SysUserRole::getCompanyId, companyId)
                    .eq(SysUserRole::getLoginPort, loginPort));
        }

        // 批量插入用户-角色关联
        List<SysUserRole> list = StreamUtils.toList(roleList,
                roleId -> {
                    SysUserRole ur = new SysUserRole();
                    ur.setUserId(userId);
                    ur.setRoleId(roleId);
                    ur.setCompanyId(companyId);
                    ur.setLoginPort(loginPort);
                    return ur;
                });
        userRoleMapper.insertBatch(list);
    }

    /**
     * 通过用户ID删除用户
     *
     * @param userId 用户ID
     * @return 结果
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public int deleteUserById(Long userId) {
        // 删除用户与角色关联
        userRoleMapper.delete(new LambdaQueryWrapper<SysUserRole>().eq(SysUserRole::getUserId, userId).eq(SysUserRole::getLoginPort, HEADQUARTERS_PORT).eq(SysUserRole::getCompanyId, 1L));
        // 删除用户与岗位表
        userPostMapper.delete(new LambdaQueryWrapper<SysUserPost>().eq(SysUserPost::getUserId, userId));
        // 防止更新失败导致的数据删除
        int flag = baseMapper.deleteById(userId);
        if (flag < 1) {
            throw new ServiceException("删除用户失败!");
        }
        return flag;
    }

    /**
     * 批量删除用户信息
     *
     * @param userIds 需要删除的用户ID
     * @return 结果
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public int deleteUserByIds(Long[] userIds) {
        for (Long userId : userIds) {
            checkUserAllowed(userId);
            checkUserDataScope(userId);
        }
        List<Long> ids = List.of(userIds);
        // 删除用户与角色关联（所有公司、所有端口）
        userRoleMapper.delete(new LambdaQueryWrapper<SysUserRole>().in(SysUserRole::getUserId, ids));
        // 删除用户与岗位表
        userPostMapper.delete(new LambdaQueryWrapper<SysUserPost>().in(SysUserPost::getUserId, ids));
        // 删除用户登录端口关系
        sysUserLoginPortMapper.delete(new LambdaQueryWrapper<SysUserLoginPort>().in(SysUserLoginPort::getUserId, ids));

        // 仅在用户不再绑定任何企业端口时才删除用户记录
        int deleteCount = 0;
        for (Long userId : ids) {
            Long portCount = sysUserLoginPortMapper.selectCount(new LambdaQueryWrapper<SysUserLoginPort>()
                    .eq(SysUserLoginPort::getUserId, userId));
            if (portCount == 0) {
                int flag = baseMapper.deleteById(userId);
                if (flag < 1) {
                    throw new ServiceException("删除用户失败!");
                }
                deleteCount += flag;
            }
        }
        return deleteCount;
    }

    /**
     * 通过部门id查询当前部门所有用户
     *
     * @param deptId 部门ID
     * @return 用户信息集合信息
     */
    @Override
    public List<SysUserVo> selectUserListByDept(Long deptId) {
        LambdaQueryWrapper<SysUser> lqw = Wrappers.lambdaQuery();
        lqw.eq(SysUser::getDeptId, deptId);
        lqw.orderByAsc(SysUser::getUserId);
        return baseMapper.selectVoList(lqw);
    }

    /**
     * 通过用户ID查询用户账户
     *
     * @param userId 用户ID
     * @return 用户账户
     */
    @Cacheable(cacheNames = CacheNames.SYS_USER_NAME, key = "#userId")
    @Override
    public String selectUserNameById(Long userId) {
        SysUser sysUser = baseMapper.selectOne(new LambdaQueryWrapper<SysUser>()
                .select(SysUser::getUserName).eq(SysUser::getUserId, userId));
        return ObjectUtils.notNullGetter(sysUser, SysUser::getUserName);
    }

    /**
     * 通过用户ID查询用户账户
     *
     * @param userId 用户ID
     * @return 用户账户
     */
    @Override
    @Cacheable(cacheNames = CacheNames.SYS_NICKNAME, key = "#userId")
    public String selectNicknameById(Long userId) {
        SysUser sysUser = baseMapper.selectOne(new LambdaQueryWrapper<SysUser>()
                .select(SysUser::getNickName).eq(SysUser::getUserId, userId));
        return ObjectUtils.notNullGetter(sysUser, SysUser::getNickName);
    }

    /**
     * 通过用户ID查询用户账户
     *
     * @param userIds 用户ID 多个用逗号隔开
     * @return 用户账户
     */
    @Override
    public String selectNicknameByIds(String userIds) {
        List<String> list = new ArrayList<>();
        for (Long id : StringUtils.splitTo(userIds, Convert::toLong)) {
            String nickname = SpringUtils.getAopProxy(this).selectNicknameById(id);
            if (StringUtils.isNotBlank(nickname)) {
                list.add(nickname);
            }
        }
        return StringUtils.joinComma(list);
    }

    /**
     * 通过用户ID查询用户手机号
     *
     * @param userId 用户id
     * @return 用户手机号
     */
    @Override
    public String selectPhonenumberById(Long userId) {
        SysUser sysUser = baseMapper.selectOne(new LambdaQueryWrapper<SysUser>()
                .select(SysUser::getPhonenumber).eq(SysUser::getUserId, userId));
        return ObjectUtils.notNullGetter(sysUser, SysUser::getPhonenumber);
    }

    /**
     * 通过用户ID查询用户邮箱
     *
     * @param userId 用户id
     * @return 用户邮箱
     */
    @Override
    public String selectEmailById(Long userId) {
        SysUser sysUser = baseMapper.selectOne(new LambdaQueryWrapper<SysUser>()
                .select(SysUser::getEmail).eq(SysUser::getUserId, userId));
        return ObjectUtils.notNullGetter(sysUser, SysUser::getEmail);
    }

    /**
     * 通过用户ID查询用户列表
     *
     * @param userIds 用户ids
     * @return 用户列表
     */
    @Override
    public List<UserDTO> selectListByIds(List<Long> userIds) {
        if (CollUtil.isEmpty(userIds)) {
            return List.of();
        }
        List<SysUserVo> list = baseMapper.selectVoList(new LambdaQueryWrapper<SysUser>()
                .select(SysUser::getUserId, SysUser::getDeptId, SysUser::getUserName,
                        SysUser::getNickName, SysUser::getUserType, SysUser::getEmail,
                        SysUser::getPhonenumber, SysUser::getSex, SysUser::getStatus,
                        SysUser::getCreateTime)
                .eq(SysUser::getStatus, SystemConstants.NORMAL)
                .in(SysUser::getUserId, userIds));
        return BeanUtil.copyToList(list, UserDTO.class);
    }

    /**
     * 通过角色ID查询用户ID
     *
     * @param roleIds 角色ids
     * @return 用户ids
     */
    @Override
    public List<Long> selectUserIdsByRoleIds(List<Long> roleIds) {
        if (CollUtil.isEmpty(roleIds)) {
            return List.of();
        }
        List<SysUserRole> userRoles = userRoleMapper.selectList(
                new LambdaQueryWrapper<SysUserRole>().in(SysUserRole::getRoleId, roleIds));
        return StreamUtils.toList(userRoles, SysUserRole::getUserId);
    }

    /**
     * 通过角色ID查询用户
     *
     * @param roleIds 角色ids
     * @return 用户
     */
    @Override
    public List<UserDTO> selectUsersByRoleIds(List<Long> roleIds) {
        if (CollUtil.isEmpty(roleIds)) {
            return List.of();
        }

        // 通过角色ID获取用户角色信息
        List<SysUserRole> userRoles = userRoleMapper.selectList(
                new LambdaQueryWrapper<SysUserRole>().in(SysUserRole::getRoleId, roleIds));

        // 获取用户ID列表
        Set<Long> userIds = StreamUtils.toSet(userRoles, SysUserRole::getUserId);

        return this.selectListByIds(new ArrayList<>(userIds));
    }

    /**
     * 通过部门ID查询用户
     *
     * @param deptIds 部门ids
     * @return 用户
     */
    @Override
    public List<UserDTO> selectUsersByDeptIds(List<Long> deptIds) {
        if (CollUtil.isEmpty(deptIds)) {
            return List.of();
        }
        List<SysUserVo> list = baseMapper.selectVoList(new LambdaQueryWrapper<SysUser>()
                .select(SysUser::getUserId, SysUser::getUserName, SysUser::getNickName, SysUser::getEmail, SysUser::getPhonenumber)
                .eq(SysUser::getStatus, SystemConstants.NORMAL)
                .in(SysUser::getDeptId, deptIds));
        return BeanUtil.copyToList(list, UserDTO.class);
    }

    /**
     * 通过岗位ID查询用户
     *
     * @param postIds 岗位ids
     * @return 用户
     */
    @Override
    public List<UserDTO> selectUsersByPostIds(List<Long> postIds) {
        if (CollUtil.isEmpty(postIds)) {
            return List.of();
        }

        // 通过岗位ID获取用户岗位信息
        List<SysUserPost> userPosts = userPostMapper.selectList(
                new LambdaQueryWrapper<SysUserPost>().in(SysUserPost::getPostId, postIds));

        // 获取用户ID列表
        Set<Long> userIds = StreamUtils.toSet(userPosts, SysUserPost::getUserId);

        return this.selectListByIds(new ArrayList<>(userIds));
    }

    /**
     * 根据用户 ID 列表查询用户名称映射关系
     *
     * @param userIds 用户 ID 列表
     * @return Map，其中 key 为用户 ID，value 为对应的用户名称
     */
    @Override
    public Map<Long, String> selectUserNamesByIds(List<Long> userIds) {
        if (CollUtil.isEmpty(userIds)) {
            return Collections.emptyMap();
        }
        List<SysUser> list = baseMapper.selectList(
                new LambdaQueryWrapper<SysUser>()
                        .select(SysUser::getUserId, SysUser::getNickName)
                        .in(SysUser::getUserId, userIds)
        );
        return StreamUtils.toMap(list, SysUser::getUserId, SysUser::getNickName);
    }

}
