package com.hotwj.platform.resourceManagement.companySafetyManager.service.impl;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.convert.Convert;
import cn.hutool.core.lang.tree.Tree;
import cn.hutool.core.lang.tree.TreeNodeConfig;
import cn.hutool.core.lang.tree.TreeUtil;
import cn.hutool.crypto.digest.BCrypt;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
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.common.utils.PasswordUtils;
import com.hotwj.platform.config.companyDeptConfig.domain.HotCompanyDeptConfig;
import com.hotwj.platform.config.companyDeptConfig.mapper.HotCompanyDeptConfigMapper;
import com.hotwj.platform.config.signAuditPermissionConfig.domain.HotSignAuditPermissionConfig;
import com.hotwj.platform.config.signAuditPermissionConfig.mapper.HotSignAuditPermissionConfigMapper;
import com.hotwj.platform.driverManagement.driverGroup.domain.HotDriverGroup;
import com.hotwj.platform.driverManagement.driverGroup.mapper.HotDriverGroupMapper;
import com.hotwj.platform.noticeManagerment.noticeSignDocument.service.IHotNoticeSignDocumentService;
import com.hotwj.platform.noticeManagerment.systemNotification.domain.bo.HotSystemNotificationGroupBo;
import com.hotwj.platform.noticeManagerment.systemNotification.service.IHotSystemNotificationService;
import com.hotwj.platform.resourceManagement.company.domain.SysCompany;
import com.hotwj.platform.resourceManagement.company.domain.SysCompanyRole;
import com.hotwj.platform.resourceManagement.company.domain.SysUserLoginPort;
import com.hotwj.platform.resourceManagement.company.mapper.SysCompanyMapper;
import com.hotwj.platform.resourceManagement.company.mapper.SysCompanyRoleMapper;
import com.hotwj.platform.resourceManagement.company.mapper.SysUserLoginPortMapper;
import com.hotwj.platform.resourceManagement.companyChangeHistory.domain.HotCompanyChangeHistory;
import com.hotwj.platform.resourceManagement.companyChangeHistory.mapper.HotCompanyChangeHistoryMapper;
import com.hotwj.platform.resourceManagement.companyPermissionGrant.domain.HotCompanyPermissionGrant;
import com.hotwj.platform.resourceManagement.companyPermissionGrant.mapper.HotCompanyPermissionGrantMapper;
import com.hotwj.platform.resourceManagement.companySafetyManager.domain.HotCompanySafetyManager;
import com.hotwj.platform.resourceManagement.companySafetyManager.domain.bo.HotCompanySafetyManagerBo;
import com.hotwj.platform.resourceManagement.companySafetyManager.domain.bo.HotCompanySafetyManagerChangeReasonBo;
import com.hotwj.platform.resourceManagement.companySafetyManager.domain.vo.HotCompanySafetyManagerVo;
import com.hotwj.platform.resourceManagement.companySafetyManager.mapper.HotCompanySafetyManagerMapper;
import com.hotwj.platform.resourceManagement.companySafetyManager.service.IHotCompanySafetyManagerService;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.dromara.common.core.domain.model.LoginUser;
import org.dromara.common.core.exception.ServiceException;
import org.dromara.common.core.service.DictService;
import org.dromara.common.core.utils.MapstructUtils;
import org.dromara.common.core.utils.StringUtils;
import org.dromara.common.mybatis.core.page.PageQuery;
import org.dromara.common.mybatis.core.page.TableDataInfo;
import org.dromara.common.satoken.utils.LoginHelper;
import org.dromara.system.domain.SysUser;
import org.dromara.system.mapper.SysUserMapper;
import org.dromara.system.service.ISysUserService;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

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

import static com.hotwj.platform.resourceManagement.company.service.ISysUserLoginPortService.ENTERPRISE_PORT;
import static com.hotwj.platform.resourceManagement.company.service.ISysUserLoginPortService.HEADQUARTERS_ROLE_ID;

/**
 * 安全管理人员Service业务层处理
 *
 * @author shihongwei
 * @date 2025-12-09
 */
@Slf4j
@RequiredArgsConstructor
@Service
public class HotCompanySafetyManagerServiceImpl implements IHotCompanySafetyManagerService {

    private final HotCompanySafetyManagerMapper baseMapper;
    private final HotCompanyDeptConfigMapper hotCompanyDeptConfigMapper;
    private final SysUserMapper sysUserMapper;
    private final SysCompanyRoleMapper sysCompanyRoleMapper;
    private final SysUserLoginPortMapper sysUserLoginPortMapper;
    private final SysCompanyMapper sysCompanyMapper;
    private final ISysUserService userService;
    private final DictService dictService;
    private final HotCompanyChangeHistoryMapper changeHistoryMapper;
    private final IHotSystemNotificationService notificationService;
    private final HotCompanyPermissionGrantMapper hotCompanyPermissionGrantMapper;
    private final HotSignAuditPermissionConfigMapper signAuditPermissionConfigMapper;
    private final HotDriverGroupMapper groupMapper;
    private final IHotNoticeSignDocumentService noticeSignDocumentService;
    /**
     * 查询安全管理人员
     *
     * @param id 主键
     * @return 安全管理人员
     */
    @Override
    public HotCompanySafetyManagerVo queryById(Long id) {
        return baseMapper.selectVoById(id);
    }

    /**
     * 构建系统管理员组织树
     *
     * @param bo 查询条件（支持 companyId、deptId）
     * @return 组织树
     */
    @Override
    public Tree<Long> buildSystemAdminTree(HotCompanySafetyManagerBo bo) {
        if (bo.getCompanyId() == null) {
			bo.setCompanyId(LoginHelper.getLoginUser().getCompanyId());
        }

		if (bo.getCompanyId() == null) {
			return new Tree<>();
		}
        LambdaQueryWrapper<HotCompanySafetyManager> lqw = Wrappers.lambdaQuery();
        lqw.eq(HotCompanySafetyManager::getCompanyId, bo.getCompanyId())
            .eq(HotCompanySafetyManager::getIsDeleted, 0)
            .eq(HotCompanySafetyManager::getIsResigned, 0)
            .eq(HotCompanySafetyManager::getStatus, 1)
            .orderByAsc(HotCompanySafetyManager::getId);
        lqw.eq(bo.getDeptId() != null, HotCompanySafetyManager::getDeptId, bo.getDeptId());
        List<HotCompanySafetyManagerVo> list = baseMapper.selectVoList(lqw);
        if (list == null || list.isEmpty()) {
            Tree<Long> root = new Tree<>();
            root.setId(0L);
            root.setName("系统管理员组织图");
            root.setChildren(CollUtil.newArrayList());
            return root;
        }

        // 填充额外字段
        Map<Long, String> deptNameMap = new java.util.HashMap<>();
        if (CollUtil.isNotEmpty(list)) {
            // 1. 填充上级人员名称
            Map<Long, String> idNameMap = list.stream()
                .collect(Collectors.toMap(HotCompanySafetyManagerVo::getId, HotCompanySafetyManagerVo::getName));
            list.forEach(vo -> {
                if (vo.getReporterId() != null) {
                    vo.setReporterName(idNameMap.get(vo.getReporterId()));
                }
            });

            // 2. 填充登录IP和最近登录时间（从sys_user表获取）
            Set<Long> userIds = list.stream()
                .map(HotCompanySafetyManagerVo::getUserId)
                .filter(Objects::nonNull)
                .collect(Collectors.toSet());

            if (CollUtil.isNotEmpty(userIds)) {
                List<SysUser> users = sysUserMapper.selectList(
                    Wrappers.<SysUser>lambdaQuery()
                        .in(SysUser::getUserId, userIds)
                        .select(SysUser::getUserId, SysUser::getLoginIp, SysUser::getLoginDate)
                );
                Map<Long, SysUser> userMap = users.stream()
                    .collect(Collectors.toMap(SysUser::getUserId, Function.identity()));

                list.forEach(vo -> {
                    if (vo.getUserId() != null) {
                        SysUser user = userMap.get(vo.getUserId());
                        if (user != null) {
                            vo.setLoginIp(user.getLoginIp());
                            vo.setLastLoginTime(user.getLoginDate());
                        }
                    }
                });
            }

            // 3. 准备部门名称Map
            Set<Long> deptIds = list.stream()
                .map(HotCompanySafetyManagerVo::getDeptId)
                .filter(Objects::nonNull)
                .collect(Collectors.toSet());
            if (CollUtil.isNotEmpty(deptIds)) {
                List<HotCompanyDeptConfig> depts = hotCompanyDeptConfigMapper.selectBatchIds(deptIds);
                if (CollUtil.isNotEmpty(depts)) {
                    deptNameMap.putAll(depts.stream().collect(Collectors.toMap(HotCompanyDeptConfig::getId, HotCompanyDeptConfig::getDeptName)));
                }
            }
        }

        Map<Long, String> finalDeptNameMap = deptNameMap;
        TreeNodeConfig config = new TreeNodeConfig();
        config.setNameKey("label");
        config.setIdKey("id");
        config.setParentIdKey("reporterId");
        List<Tree<Long>> trees = TreeUtil.build(
                list,
                null,
                config,
                (node, treeNode) -> {
                    treeNode.setId(node.getId());
                    treeNode.setParentId(node.getReporterId());
                    treeNode.setName(node.getName());
                    treeNode.putExtra("deptId", node.getDeptId());
                    if (node.getDeptId() != null) {
                        treeNode.putExtra("deptName", finalDeptNameMap.get(node.getDeptId()));
                    }
                    treeNode.putExtra("jobName", node.getJobName());

                    // 扩展字段
                    treeNode.putExtra("isDepartmentHead", node.getIsDepartmentHead());
                    treeNode.putExtra("mobile", node.getPhone());
                    treeNode.putExtra("reporterName", node.getReporterName());
                    treeNode.putExtra("createTime", node.getCreateTime());
                    treeNode.putExtra("loginIp", node.getLoginIp());
                    treeNode.putExtra("lastLoginTime", node.getLastLoginTime());
                }
        );

        // 兜底逻辑：如果构建出的树为空，但列表不为空（通常是因为存在循环引用导致无法确定根节点）
        // 则强制将所有节点作为根节点返回，确保前端能看到数据
        if (CollUtil.isEmpty(trees) && CollUtil.isNotEmpty(list)) {
            trees = list.stream().map(node -> {
                Tree<Long> treeNode = new Tree<>();
                treeNode.setId(node.getId());
                treeNode.setParentId(0L);
                treeNode.setName(node.getName());
                treeNode.putExtra("deptId", node.getDeptId());
                if (node.getDeptId() != null) {
                    treeNode.putExtra("deptName", finalDeptNameMap.get(node.getDeptId()));
                }
                treeNode.putExtra("jobName", node.getJobName());

                // 扩展字段
                treeNode.putExtra("isDepartmentHead", node.getIsDepartmentHead());
                treeNode.putExtra("mobile", node.getPhone());
                treeNode.putExtra("reporterName", node.getReporterName());
                treeNode.putExtra("createTime", node.getCreateTime());
                treeNode.putExtra("loginIp", node.getLoginIp());
                treeNode.putExtra("lastLoginTime", node.getLastLoginTime());
                return treeNode;
            }).toList();
        }

        if (CollUtil.isEmpty(trees)) {
            Tree<Long> root = new Tree<>();
            root.setId(0L);
            root.setName("系统管理员组织图");
            root.setChildren(CollUtil.newArrayList());
            return root;
        }

        // 如果只有一个根节点，直接返回；否则包裹虚拟根节点
        if (trees.size() == 1) {
            return trees.get(0);
        } else {
            Tree<Long> root = new Tree<>();
            root.setId(0L);
            root.setName("系统管理员组织图");
            root.putExtra("label", "系统管理员组织图");
            root.setChildren(trees);
            return root;
        }
    }

    /**
     * 分页查询安全管理人员列表
     *
     * @param bo        查询条件
     * @param pageQuery 分页参数
     * @return 安全管理人员分页列表
     */
    @Override
    public TableDataInfo<HotCompanySafetyManagerVo> queryPageList(HotCompanySafetyManagerBo bo, PageQuery pageQuery) {
        LambdaQueryWrapper<HotCompanySafetyManager> lqw = buildQueryWrapper(bo);
        Page<HotCompanySafetyManagerVo> result = baseMapper.selectVoPage(pageQuery.build(), lqw);
        List<HotCompanySafetyManagerVo> records = result.getRecords();
        if (CollUtil.isNotEmpty(records)) {
            Set<Long> deptIds = records.stream()
                    .map(HotCompanySafetyManagerVo::getDeptId)
                    .filter(Objects::nonNull)
                    .collect(Collectors.toSet());
            if (CollUtil.isNotEmpty(deptIds)) {
                List<HotCompanyDeptConfig> depts = hotCompanyDeptConfigMapper.selectBatchIds(deptIds);
                Map<Long, String> deptNameMap = depts.stream()
                        .collect(Collectors.toMap(HotCompanyDeptConfig::getId, HotCompanyDeptConfig::getDeptName));
                records.forEach(vo -> {
                    if (vo.getDeptId() != null) {
                        vo.setDeptName(deptNameMap.get(vo.getDeptId()));
                    }
                });
            }
        }
        return TableDataInfo.build(result);
    }

    /**
     * 分页查询部门负责人列表
     *
     * @param bo        查询条件
     * @param pageQuery 分页参数
     * @return 部门负责人分页列表
     */
    @Override
    public TableDataInfo<HotCompanySafetyManagerVo> queryCompanyUserList(HotCompanySafetyManagerBo bo, PageQuery pageQuery) {
        LambdaQueryWrapper<HotCompanySafetyManager> lqw = new LambdaQueryWrapper<>();
        lqw.eq(HotCompanySafetyManager::getCompanyId, bo.getCompanyId())
                .eq(HotCompanySafetyManager::getIsResigned, 0)
                .eq(HotCompanySafetyManager::getStatus, 1)
                .eq(HotCompanySafetyManager::getIsDeleted, 0);
        Page<HotCompanySafetyManagerVo> result = baseMapper.selectVoPage(pageQuery.build(), lqw);
        return TableDataInfo.build(result);
    }

    /**
     * 查询符合条件的安全管理人员列表
     *
     * @param bo 查询条件
     * @return 安全管理人员列表
     */
    @Override
    public List<HotCompanySafetyManagerVo> queryList(HotCompanySafetyManagerBo bo) {
        LambdaQueryWrapper<HotCompanySafetyManager> lqw = buildQueryWrapper(bo);
        List<HotCompanySafetyManagerVo> list = baseMapper.selectVoList(lqw);
        if (CollUtil.isNotEmpty(list)) {
            List<Long> reporterIds = list.stream()
                    .map(HotCompanySafetyManagerVo::getReporterId)
                    .filter(id -> id != null && id > 0)
                    .distinct()
                    .toList();
            if (CollUtil.isNotEmpty(reporterIds)) {
                List<HotCompanySafetyManagerVo> reporters = baseMapper.selectVoList(
                        Wrappers.<HotCompanySafetyManager>lambdaQuery().in(HotCompanySafetyManager::getId, reporterIds)
                );
                Map<Long, String> idNameMap = reporters.stream()
                        .collect(Collectors.toMap(HotCompanySafetyManagerVo::getId, HotCompanySafetyManagerVo::getName));
                list.forEach(vo -> {
                    if (vo.getReporterId() != null) {
                        vo.setReporterName(idNameMap.get(vo.getReporterId()));
                    }
                });
            }

            // 填充部门名称
            Set<Long> deptIds = list.stream()
                .map(HotCompanySafetyManagerVo::getDeptId)
                .filter(Objects::nonNull)
                .collect(Collectors.toSet());
            if (CollUtil.isNotEmpty(deptIds)) {
                List<HotCompanyDeptConfig> depts = hotCompanyDeptConfigMapper.selectBatchIds(deptIds);
                Map<Long, String> deptNameMap = depts.stream()
                    .collect(Collectors.toMap(HotCompanyDeptConfig::getId, HotCompanyDeptConfig::getDeptName));
                list.forEach(vo -> {
                    if (vo.getDeptId() != null) {
                        vo.setDeptName(deptNameMap.get(vo.getDeptId()));
                    }
                });
            }
        }
        return list;
    }

    private LambdaQueryWrapper<HotCompanySafetyManager> buildQueryWrapper(HotCompanySafetyManagerBo bo) {
        Map<String, Object> params = bo.getParams();
        LambdaQueryWrapper<HotCompanySafetyManager> lqw = Wrappers.lambdaQuery();
        lqw.orderByAsc(HotCompanySafetyManager::getId);
        lqw.in(StringUtils.isNotBlank(bo.getIds()), HotCompanySafetyManager::getId, StringUtils.splitTo(bo.getIds(), Convert::toLong));
        if (bo.getCompanyId() == null) {
            LoginUser loginUser = LoginHelper.getLoginUser();
            if (loginUser != null && !loginUser.getIsAdmin() && loginUser.getRoleId() != HEADQUARTERS_ROLE_ID) {
                lqw.eq(HotCompanySafetyManager::getCompanyId, loginUser.getCompanyId());
            } else if (loginUser.getIsAdmin() || loginUser.getRoleId() == HEADQUARTERS_ROLE_ID) {

            } else {
                lqw.eq(HotCompanySafetyManager::getCompanyId, loginUser.getCompanyId());
            }
        } else {
            lqw.eq(HotCompanySafetyManager::getCompanyId, bo.getCompanyId());
        }

        lqw.eq(bo.getReporterId() != null, HotCompanySafetyManager::getReporterId, bo.getReporterId());
        lqw.eq(bo.getId() != null, HotCompanySafetyManager::getId, bo.getId());
        lqw.like(StringUtils.isNotBlank(bo.getName()), HotCompanySafetyManager::getName, bo.getName());
        lqw.eq(StringUtils.isNotBlank(bo.getIdCardNo()), HotCompanySafetyManager::getIdCardNo, bo.getIdCardNo());
        lqw.like(StringUtils.isNotBlank(bo.getPhone()), HotCompanySafetyManager::getPhone, bo.getPhone());
        lqw.eq(StringUtils.isNotBlank(bo.getLoginPassword()), HotCompanySafetyManager::getLoginPassword, bo.getLoginPassword());
        lqw.eq(bo.getIsPartyMember() != null, HotCompanySafetyManager::getIsPartyMember, bo.getIsPartyMember());
        lqw.eq(bo.getIsDepartmentHead() != null, HotCompanySafetyManager::getIsDepartmentHead, bo.getIsDepartmentHead());
        lqw.eq(bo.getEntryDate() != null, HotCompanySafetyManager::getEntryDate, bo.getEntryDate());
        lqw.eq(StringUtils.isNotBlank(bo.getJobName()), HotCompanySafetyManager::getJobName, bo.getJobName());
        lqw.eq(StringUtils.isNotBlank(bo.getJobDuty()), HotCompanySafetyManager::getJobDuty, bo.getJobDuty());
        lqw.like(bo.getDeptId() != null, HotCompanySafetyManager::getDeptId, bo.getDeptId());
        lqw.eq(StringUtils.isNotBlank(bo.getPermissionType()), HotCompanySafetyManager::getPermissionType, bo.getPermissionType());
        lqw.eq(StringUtils.isNotBlank(bo.getAddress()), HotCompanySafetyManager::getAddress, bo.getAddress());
        lqw.eq(StringUtils.isNotBlank(bo.getWechatId()), HotCompanySafetyManager::getWechatId, bo.getWechatId());
        lqw.eq(StringUtils.isNotBlank(bo.getIdcardFrontUrl()), HotCompanySafetyManager::getIdcardFrontUrl, bo.getIdcardFrontUrl());
        lqw.eq(StringUtils.isNotBlank(bo.getIdcardBackUrl()), HotCompanySafetyManager::getIdcardBackUrl, bo.getIdcardBackUrl());
        lqw.eq(StringUtils.isNotBlank(bo.getAvatarUrl()), HotCompanySafetyManager::getAvatarUrl, bo.getAvatarUrl());
        lqw.eq(StringUtils.isNotBlank(bo.getAppointmentDocUrl()), HotCompanySafetyManager::getAppointmentDocUrl, bo.getAppointmentDocUrl());
        lqw.eq(StringUtils.isNotBlank(bo.getCertificateNo()), HotCompanySafetyManager::getCertificateNo, bo.getCertificateNo());
        lqw.eq(bo.getCertificateExpireDate() != null, HotCompanySafetyManager::getCertificateExpireDate, bo.getCertificateExpireDate());
        lqw.eq(StringUtils.isNotBlank(bo.getIssuingAuthority()), HotCompanySafetyManager::getIssuingAuthority, bo.getIssuingAuthority());
        lqw.eq(StringUtils.isNotBlank(bo.getCertificateAttachmentUrl()), HotCompanySafetyManager::getCertificateAttachmentUrl, bo.getCertificateAttachmentUrl());
        lqw.eq(StringUtils.isNotBlank(bo.getSignatureUrl()), HotCompanySafetyManager::getSignatureUrl, bo.getSignatureUrl());
        lqw.eq(bo.getIsResigned() != null, HotCompanySafetyManager::getIsResigned, bo.getIsResigned());
        lqw.eq(bo.getStatus() != null, HotCompanySafetyManager::getStatus, bo.getStatus());
        lqw.eq(HotCompanySafetyManager::getIsDeleted, 0); // 只能查询未删除的安全管理人员
        return lqw;
    }

    /**
     * 新增安全管理人员
     *
     * @param bo 安全管理人员
     * @return 是否新增成功
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public Boolean insertByBo(HotCompanySafetyManagerBo bo) {
        HotCompanySafetyManager add = MapstructUtils.convert(bo, HotCompanySafetyManager.class);
        if (add.getCompanyId() == null) {
            add.setCompanyId(LoginHelper.getLoginUser().getCompanyId());
        }

        // 校验：如果当前部门没有负责人，且添加的不是负责人，则不允许添加
        if (add.getDeptId() != null && !Long.valueOf(1L).equals(add.getIsDepartmentHead())) {
            Long headCount = baseMapper.selectCount(Wrappers.<HotCompanySafetyManager>lambdaQuery()
                .eq(HotCompanySafetyManager::getCompanyId, add.getCompanyId())
                .eq(HotCompanySafetyManager::getDeptId, add.getDeptId())
                .eq(HotCompanySafetyManager::getIsDepartmentHead, 1)
                .eq(HotCompanySafetyManager::getIsDeleted, 0)
                    .eq(HotCompanySafetyManager::getIsResigned, 0)
                .eq(HotCompanySafetyManager::getStatus, 1)
            );

            if (headCount == 0) {
                throw new ServiceException("当前部门暂无负责人，请先添加部门负责人");
            }
        }

        add.setIsDeleted(0L);
        validEntityBeforeSave(add);
        validatePermissionAssignment(add.getCompanyId(), add.getCompanyHead());

        // 如果该手机号已在其他企业被注册，禁止创建SysUser (业务规则：一个手机号对应一个自然人，可以在多个企业任职，但是有且仅有一个SysUser)


        SysUser sysUser = findUserByPhone(add.getPhone());
        Long userId = null;
        if (sysUser == null) {
            sysUser = new SysUser();
            sysUser.setPhonenumber(add.getPhone());
            sysUser.setNickName(add.getName());
            sysUser.setUserName(add.getPhone());
            // 设置主密码（默认）
            sysUser.setPassword(PasswordUtils.createDefaultPassword(add.getPhone()));
            sysUser.setUserType("sys_user");
            sysUser.setStatus("0");
            sysUserMapper.insert(sysUser);
            userId = sysUser.getUserId();
        } else {
            userId = sysUser.getUserId();
        }

        // 初始化或更新子密码（特定企业的登录密码）
        String subPassword;
        if (StringUtils.isNotBlank(add.getLoginPassword())) {
            validatePassword(add.getLoginPassword());
            subPassword = BCrypt.hashpw(add.getLoginPassword());
        } else {
            subPassword = PasswordUtils.createDefaultPassword(add.getPhone());
        }

        // 确保有登录端口并设置子密码
        ensureLoginPort(userId, add.getCompanyId(), add.getName(), subPassword);

        log.info("[安全管理人员已创建] managerId={}, userId={}, companyId={}, operator={}", add.getId(), userId, add.getCompanyId(), add.getCreateBy());
        applyRoleByPermissionType(userId, add);

        add.setUserId(userId);
        boolean flag = baseMapper.insert(add) > 0;
        if (flag) {
            bo.setId(add.getId());
            noticeSignDocumentService.issueDefaultForNewManager(add);
        }

        return flag;
    }

    private void ensureLoginPort(Long userId, Long companyId, String username, String subPassword) {
        LambdaQueryWrapper<SysUserLoginPort> wrapper = new LambdaQueryWrapper<>();
        wrapper.eq(SysUserLoginPort::getUserId, userId)
                .eq(SysUserLoginPort::getCompanyId, companyId)
                .eq(SysUserLoginPort::getLoginPort, ENTERPRISE_PORT);

        SysUserLoginPort port = sysUserLoginPortMapper.selectOne(wrapper);
        if (port == null) {
            port = new SysUserLoginPort();
            port.setUserId(userId);
            port.setCompanyId(companyId);
            port.setUsername(username);
            port.setLoginPort(ENTERPRISE_PORT);
            port.setStatus(1);
            port.setSubPassword(subPassword);
            sysUserLoginPortMapper.insert(port);
        } else {
            // 如果端口已存在但没有子密码，或者需要更新子密码（通常新建时如果是新密码则覆盖，否则保留？这里假设新建时传入的密码是初始化的）
            // 如果是已存在的员工被重新录入，可能不应重置密码。但如果是“新增安全管理人员”，通常意味着新入职或新岗位。
            // 这里逻辑：如果传入了明确的密码，则更新；如果是默认密码且原密码为空，则更新。
            // 简化逻辑：新增人员操作，如果该人员在该公司已有端口，是否重置密码？
            // 通常“新增”意味着从无到有。如果已存在SysUser但无此公司端口，是新开端口。
            // 如果已存在此公司端口，可能是数据错误或重复添加。
            // 假设是新开端口或修复数据：
            if (StringUtils.isBlank(port.getSubPassword())) {
                port.setSubPassword(subPassword);
                sysUserLoginPortMapper.updateById(port);
            }
        }
    }

    /**
     * 修改安全管理人员
     *
     * @param bo 安全管理人员
     * @return 是否修改成功
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public Boolean updateByBo(HotCompanySafetyManagerChangeReasonBo bo) {
        HotCompanySafetyManager update = MapstructUtils.convert(bo, HotCompanySafetyManager.class);
        HotCompanySafetyManager before = baseMapper.selectById(update.getId());
        if (before == null) {
            throw new ServiceException("安全管理人员不存在");
        }
        // 参考新增：编辑时如果更换部门，且目标部门暂无负责人、当前人员又不是负责人，则不允许变更
        boolean deptChanged = update.getDeptId() != null && !Objects.equals(update.getDeptId(), before.getDeptId());
        Long finalIsDepartmentHead = update.getIsDepartmentHead() != null ? update.getIsDepartmentHead() : before.getIsDepartmentHead();
        if (deptChanged
                && !Long.valueOf(1L).equals(finalIsDepartmentHead)
                && update.getCompanyId() != null
                && countActiveDeptHead(update.getCompanyId(), update.getDeptId()) == 0) {
            throw new ServiceException("当前部门暂无负责人，请先添加部门负责人");
        }
        validEntityBeforeSave(update);
        boolean permissionChanged = !Objects.equals(update.getPermissionRoleId(), before.getPermissionRoleId())
                || !StringUtils.equals(update.getPermissionType(), before.getPermissionType());
        if (permissionChanged) {
            validatePermissionAssignment(before.getCompanyId(), update.getCompanyHead() == null ? before.getCompanyHead() : update.getCompanyHead());
        }

        // 如果是离职，将部门置空
        boolean isResigning = update.getIsResigned() != null
                && Long.valueOf(1L).equals(update.getIsResigned())
                && (before.getIsResigned() == null || !Long.valueOf(1L).equals(before.getIsResigned()));

        if (isResigning) {
            update.setDeptId(null);
        }

        boolean ok = baseMapper.updateById(update) > 0;

        if (ok && isResigning) {
            baseMapper.update(null, Wrappers.<HotCompanySafetyManager>lambdaUpdate()
                    .set(HotCompanySafetyManager::getDeptId, null)
                    .eq(HotCompanySafetyManager::getId, update.getId()));
        }

        // TODO 是否需要考虑修改密码
        if (before != null && ok) {
            syncUserAndRecordHistory(update, before, bo.getChangeReason(), bo.getBeforeBusiness());
        }
        return ok;
    }

    private long countActiveDeptHead(Long companyId, Long deptId) {
        if (companyId == null || deptId == null) {
            return 0L;
        }
        return baseMapper.selectCount(Wrappers.<HotCompanySafetyManager>lambdaQuery()
                .eq(HotCompanySafetyManager::getCompanyId, companyId)
                .eq(HotCompanySafetyManager::getDeptId, deptId)
                .eq(HotCompanySafetyManager::getIsDepartmentHead, 1)
                .eq(HotCompanySafetyManager::getIsDeleted, 0)
                .eq(HotCompanySafetyManager::getIsResigned, 0)
                .eq(HotCompanySafetyManager::getStatus, 1)
        );
    }

    private void syncUserAndRecordHistory(HotCompanySafetyManager update, HotCompanySafetyManager before, String changeReason, String beforeBusiness) {
        SysUser sysUser = findUserByPhone(before.getPhone());
        if (sysUser == null) {
            return;
        }

        boolean userChanged = false;

        // 1. Handle Phone Change
        if (handlePhoneChange(update, before, sysUser)) {
            userChanged = true;
        }

        // 2. Handle Name Change
        if (handleNameChange(update, before, sysUser)) {
            userChanged = true;
        }

        // 3. Handle Department Change
        if (handleDeptChange(update, before, sysUser)) {
            userChanged = true;
        }

        // 4. Handle Status Change (Disable/Resign)
        handleStatusChange(update, before, sysUser);

        // 5. Handle Password Change
        if (handlePasswordChange(update, before, sysUser)) {
            userChanged = true;
        }

        // 6. Handle Permission Change
        boolean permissionChanged = !Objects.equals(update.getPermissionRoleId(), before.getPermissionRoleId())
                || !StringUtils.equals(update.getPermissionType(), before.getPermissionType());
        if (permissionChanged) {
            applyRoleByPermissionType(sysUser.getUserId(), update);
        }

        // 7. Record Change History
        LoginUser loginUser = LoginHelper.getLoginUser();
        boolean isHead = Long.valueOf(1L).equals(before.getCompanyHead()) || Long.valueOf(1L).equals(before.getIsDepartmentHead());
        boolean operatorIsManagerSelf = loginUser != null && before.getUserId() != null && java.util.Objects.equals(loginUser.getUserId(), before.getUserId());
        boolean sameCompany = loginUser != null && java.util.Objects.equals(loginUser.getCompanyId(), before.getCompanyId());
        if (!(isHead && operatorIsManagerSelf && sameCompany)) {
            recordChangeHistory(update, before, changeReason, beforeBusiness);
        }
        boolean resignChanged = update.getIsResigned() != null && Long.valueOf(1L).equals(update.getIsResigned())
                && (before.getIsResigned() == null || !Long.valueOf(1L).equals(before.getIsResigned()));
        boolean disabledChanged = update.getStatus() != null && !Long.valueOf(1L).equals(update.getStatus())
                && (before.getStatus() == null || Long.valueOf(1L).equals(before.getStatus()));
        if (resignChanged && before.getCompanyId() != null) {
            List<HotCompanySafetyManager> heads = baseMapper.selectList(
                    Wrappers.<HotCompanySafetyManager>lambdaQuery()
                            .eq(HotCompanySafetyManager::getCompanyId, before.getCompanyId())
                            .eq(HotCompanySafetyManager::getCompanyHead, 1L)
                            .eq(HotCompanySafetyManager::getIsDeleted, 0L)
                            .eq(HotCompanySafetyManager::getIsResigned, 0L)
                            .eq(HotCompanySafetyManager::getStatus, 1L)
            );
            if (CollUtil.isNotEmpty(heads)) {
                List<String> receiverIds = heads.stream().map(h -> String.valueOf(h.getId())).collect(java.util.stream.Collectors.toList());
                HotSystemNotificationGroupBo bos = new HotSystemNotificationGroupBo();
                bos.setLevel("普通");
                bos.setContent("企业管理人员【" + StringUtils.blankToDefault(update.getName(), "该人员") + "】已经离职。");
                bos.setSourceType("企业管理");
                bos.setSenderType("SYSTEM");
                bos.setReceiverType("管理员");
                bos.setReceiverIds(receiverIds);
                bos.setIsDeleted(0L);
                try {
                    notificationService.insertByBo(bos);
                } catch (Exception e) {
                    log.warn("发送企业管理人员离职通知失败 companyId={} managerId={}", before.getCompanyId(), before.getId(), e);
                }
            }
        }
        if ((resignChanged || disabledChanged) && before.getCompanyId() != null) {
            signAuditPermissionConfigMapper.delete(
                    Wrappers.<HotSignAuditPermissionConfig>lambdaQuery()
                            .eq(HotSignAuditPermissionConfig::getCompanyId, before.getCompanyId())
                            .eq(HotSignAuditPermissionConfig::getAuditorId, before.getId())
            );
            log.info("[SafetyManager-AuditPerm] removed sign audit permissions auditorId={}, companyId={}", before.getId(), before.getCompanyId());
        }

        // 8. Handle Group Deletion on Resign/Disable
        if ((resignChanged || disabledChanged) && before.getCompanyId() != null) {
            groupMapper.delete(
                    Wrappers.<HotDriverGroup>lambdaQuery()
                            .eq(HotDriverGroup::getCompanyId, before.getCompanyId())
                            .eq(HotDriverGroup::getLeaderId, before.getId())
            );
            log.info("[SafetyManager-Group] removed groups where leaderId={}, companyId={}", before.getId(), before.getCompanyId());
        }

        // 9. Update SysUser if needed
        if (userChanged) {
            sysUserMapper.updateById(sysUser);
            log.info("[SafetyManager-Update] synced fields for userId={}, managerId={}, operator={}", sysUser.getUserId(), update.getId(), update.getUpdateBy());
        }
    }

    private boolean handlePasswordChange(HotCompanySafetyManager update, HotCompanySafetyManager before, SysUser sysUser) {
        String newPwd = update.getLoginPassword();
        String oldPwd = before.getLoginPassword();
        if (StringUtils.isBlank(newPwd) || StringUtils.equals(newPwd, oldPwd)) {
            return false;
        }
        validatePassword(newPwd);

        // 修改子密码
        userService.resetUserPwd(sysUser.getUserId(), BCrypt.hashpw(newPwd), before.getCompanyId());

        // 不需要单独更新 sysUser 密码，resetUserPwd 已经处理
        return false; 
    }

    private boolean handlePhoneChange(HotCompanySafetyManager update, HotCompanySafetyManager before, SysUser sysUser) {
        if (StringUtils.isBlank(update.getPhone()) || StringUtils.equals(update.getPhone(), before.getPhone())) {
            return false;
        }

        // Check if new phone exists in sys_user
        SysUser existUser = sysUserMapper.selectOne(new LambdaQueryWrapper<SysUser>()
                .eq(SysUser::getPhonenumber, update.getPhone()));

        if (existUser != null) {
            validatePhoneUsage(existUser);
        }

        sysUser.setPhonenumber(update.getPhone());
        return true;
    }

    private void validatePhoneUsage(SysUser existUser) {
        // Check if used in same port
        Long samePortCount = sysUserLoginPortMapper.selectCount(new LambdaQueryWrapper<SysUserLoginPort>()
                .eq(SysUserLoginPort::getUserId, existUser.getUserId())
                .eq(SysUserLoginPort::getLoginPort, ENTERPRISE_PORT));
        if (samePortCount > 0) {
            throw new org.dromara.common.core.exception.ServiceException("该手机号已在当前端口被使用");
        }

        // Check if used in any other port
        Long anyPortCount = sysUserLoginPortMapper.selectCount(new LambdaQueryWrapper<SysUserLoginPort>()
                .eq(SysUserLoginPort::getUserId, existUser.getUserId()));
        if (anyPortCount > 0) {
            throw new org.dromara.common.core.exception.ServiceException("该手机号已被其他端口使用");
        }

        // Exists in sys_user but not used in any port?
        throw new org.dromara.common.core.exception.ServiceException("该手机号已被注册");
    }

    private boolean handleNameChange(HotCompanySafetyManager update, HotCompanySafetyManager before, SysUser sysUser) {
        if (StringUtils.isBlank(update.getName()) || StringUtils.equals(update.getName(), before.getName())) {
            return false;
        }

        sysUser.setNickName(update.getName());

        // Sync port username
        SysUserLoginPort portEntry = getLoginPortEntry(sysUser.getUserId(), before.getCompanyId());
        if (portEntry != null) {
            portEntry.setUsername(update.getName());
            sysUserLoginPortMapper.updateById(portEntry);
        }
        return true;
    }

    private boolean handleDeptChange(HotCompanySafetyManager update, HotCompanySafetyManager before, SysUser sysUser) {
        if (update.getDeptId() != null && !update.getDeptId().equals(before.getDeptId())) {
            sysUser.setDeptId(update.getDeptId());
            return true;
        }
        return false;
    }

    private void handleStatusChange(HotCompanySafetyManager update, HotCompanySafetyManager before, SysUser sysUser) {
        if (update.getStatus() == null && update.getIsResigned() == null) {
            return;
        }

        boolean toDisable = (update.getStatus() != null && !Long.valueOf(1L).equals(update.getStatus()))
                || (update.getIsResigned() != null && Long.valueOf(1L).equals(update.getIsResigned()));

        SysUserLoginPort portEntry = getLoginPortEntry(sysUser.getUserId(), before.getCompanyId());
        if (portEntry != null) {
            portEntry.setStatus(toDisable ? 0 : 1);
            sysUserLoginPortMapper.updateById(portEntry);

            String statusAction = toDisable ? "disabled" : "enabled";
            log.info("[安全管理人员状态] {} port access userId={}, managerId={}, operator={}",
                    statusAction, sysUser.getUserId(), update.getId(), update.getUpdateBy());
        }
    }

    private void recordChangeHistory(HotCompanySafetyManager update, HotCompanySafetyManager before, String changeReason, String beforeBusiness) {
        boolean resignChanged = update.getIsResigned() != null && Long.valueOf(1L).equals(update.getIsResigned())
                && (before.getIsResigned() == null || !Long.valueOf(1L).equals(before.getIsResigned()));

        boolean jobChanged = StringUtils.isNotBlank(update.getJobName()) && !StringUtils.equals(update.getJobName(), before.getJobName());
        // 如果是离职，且原部门不为空，则认为部门变更（变为空）
        boolean deptChanged = (update.getDeptId() != null && !update.getDeptId().equals(before.getDeptId()))
                || (resignChanged && before.getDeptId() != null);

        boolean appointmentDocChanged = StringUtils.isNotBlank(update.getAppointmentDocUrl()) && !StringUtils.equals(update.getAppointmentDocUrl(), before.getAppointmentDocUrl());

        if (!jobChanged && !deptChanged && !resignChanged && !appointmentDocChanged) {
            return;
        }

        String changeType = determineChangeType(jobChanged, deptChanged, resignChanged, appointmentDocChanged);

        HotCompanyChangeHistory history = new HotCompanyChangeHistory();
        history.setCompanyId(before.getCompanyId());
        history.setName(update.getName());
        history.setPhone(update.getPhone());
        history.setEmployeeId(before.getId());
        history.setBeforeJobName(before.getJobName());
        history.setAfterJobName(jobChanged ? update.getJobName() : before.getJobName());
        history.setBeforeDeptId(before.getDeptId());
        history.setAfterDeptId(deptChanged ? update.getDeptId() : before.getDeptId());
        history.setChangeType(changeType);
        history.setChangeTime(new java.util.Date());
        history.setOperatorId(LoginHelper.getUserId());
        history.setOperatorName(LoginHelper.getUsername());
        history.setIsDeleted(0);
        history.setChangeReason(changeReason);
        history.setBeforeBusiness(StringUtils.isNotBlank(beforeBusiness) ? beforeBusiness : before.getJobDuty());
        history.setBeforeAppointmentUrl(before.getAppointmentDocUrl());
        history.setAfterAppointmentUrl(update.getAppointmentDocUrl());
        changeHistoryMapper.insert(history);

        log.info("[安全管理人员变更] type={}, managerId={}, operator={}", changeType, before.getId(), update.getUpdateBy());
    }

    private String determineChangeType(boolean jobChanged, boolean deptChanged, boolean resignChanged, boolean appointmentDocChanged) {
        if (resignChanged) return "离职";
        if (jobChanged && deptChanged) return "调岗调部门";
        if (jobChanged) return "调岗位";
        if (deptChanged) return "调部门";
        if (appointmentDocChanged) return "任命书变更";
        return "信息变更";
    }

    private SysUserLoginPort getLoginPortEntry(Long userId, Long companyId) {
        return sysUserLoginPortMapper.selectOne(new LambdaQueryWrapper<SysUserLoginPort>()
                .eq(SysUserLoginPort::getUserId, userId)
                .eq(SysUserLoginPort::getLoginPort, ENTERPRISE_PORT)
                .eq(SysUserLoginPort::getCompanyId, companyId));
    }

    /**
     * 保存前的数据校验
     */
    private void validEntityBeforeSave(HotCompanySafetyManager entity) {
    }

    /**
     * 校验并批量删除安全管理人员信息
     *
     * @param ids     待删除的主键集合
     * @param isValid 是否进行有效性校验
     * @return 是否删除成功
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public Boolean deleteWithValidByIds(Collection<Long> ids, Boolean isValid) {
        if (isValid) {
        }
        boolean ok = baseMapper.deleteByIds(ids) > 0;
        if (ok) {
            ids.forEach(id -> {
                HotCompanySafetyManager mgr = baseMapper.selectById(id);
                if (mgr != null) {
                    SysUser sysUser = findUserByPhone(mgr.getPhone());
                    if (sysUser != null) {
                        // 应该停用此端口，此用户的登录就行了，不能删除用户
                        LambdaQueryWrapper<SysUserLoginPort> wrapper = new LambdaQueryWrapper<>();
                        wrapper.eq(SysUserLoginPort::getUserId, id);
                        wrapper.eq(SysUserLoginPort::getCompanyId, mgr.getCompanyId());
                        wrapper.eq(SysUserLoginPort::getLoginPort, ENTERPRISE_PORT);
                        List<SysUserLoginPort> loginPorts = sysUserLoginPortMapper.selectList(wrapper);
                        if (CollUtil.isEmpty(loginPorts)) {
                            sysUserLoginPortMapper.deleteByIds(loginPorts);
                        }
                    }
                }
            });
        }
        return ok;
    }

    @Override
    public boolean updateUserFaceInitialOssId(String businessUserId, Long ossId) {
        return baseMapper.update(null,
                new LambdaUpdateWrapper<HotCompanySafetyManager>()
                        .set(HotCompanySafetyManager::getAvatarUrl, ossId)
                        .eq(HotCompanySafetyManager::getId, businessUserId)
        ) > 0;
    }

    /**
     * 查询所有安全管理人员列表
     *
     * @param companyId 企业ID
     * @return 安全管理人员列表
     */
    @Override
    public List<HotCompanySafetyManagerVo> queryAllList(Long companyId) {
        return baseMapper.selectVoList(Wrappers.<HotCompanySafetyManager>lambdaQuery()
                .eq(HotCompanySafetyManager::getCompanyId, companyId)
                .eq(HotCompanySafetyManager::getIsDeleted, 0));
    }

    /**
     * 查询特定的安全管理人员列表（未离职、已启用、已通过审核）
     *
     * @param companyId 企业ID
     * @return 安全管理人员列表
     */
    @Override
    public List<HotCompanySafetyManagerVo> queryValidList(Long companyId) {
        return baseMapper.selectVoList(Wrappers.<HotCompanySafetyManager>lambdaQuery()
                .eq(HotCompanySafetyManager::getCompanyId, companyId)
                .eq(HotCompanySafetyManager::getIsDeleted, 0)
                .eq(HotCompanySafetyManager::getIsResigned, 0)
                .eq(HotCompanySafetyManager::getStatus, 1));
    }

    private SysUser findUserByPhone(String phone) {
        if (StringUtils.isBlank(phone)) {
            return null;
        }
        List<SysUser> users = sysUserMapper.selectList(Wrappers.<SysUser>lambdaQuery().eq(SysUser::getPhonenumber, phone));
        if (users == null || users.isEmpty()) {
            return null;
        }
        return users.get(0);
    }


    private void validatePassword(String raw) {
        if (raw.length() < 8) {
            throw new IllegalArgumentException("密码长度至少8位");
        }
        boolean hasLetter = raw.chars().anyMatch(Character::isLetter);
        boolean hasDigit = raw.chars().anyMatch(Character::isDigit);
        if (!hasLetter || !hasDigit) {
            throw new IllegalArgumentException("密码需包含字母和数字");
        }
    }

    @Override
    public List<HotCompanySafetyManagerVo> getSuperiorCandidates(Long companyId, Long deptId, Long currentId) {
        // 1. 获取该企业下所有在职未删除的安全管理人员，并确保包括企业负责人（即使状态可能有问题）
        SysCompany company = sysCompanyMapper.selectById(companyId);
        String responsibleMobile = (company != null) ? company.getResponsibleMobile() : null;

        LambdaQueryWrapper<HotCompanySafetyManager> lqw = Wrappers.lambdaQuery();
        lqw.eq(HotCompanySafetyManager::getCompanyId, companyId)
                .eq(HotCompanySafetyManager::getIsDeleted, 0)
                .and(w -> w
                        // 情况1：是企业负责人（不限部门，不论状态）
                        .or(StringUtils.isNotBlank(responsibleMobile), n -> n.eq(HotCompanySafetyManager::getPhone, responsibleMobile))
                        // 情况2：其他人员（必须正常在职）
                        .or(n -> {
                            n.eq(HotCompanySafetyManager::getIsResigned, 0)
                                    .eq(HotCompanySafetyManager::getStatus, 1);
                            // 如果传入了部门ID，则必须是同部门
                            if (deptId != null) {
                                n.eq(HotCompanySafetyManager::getDeptId, deptId);
                            }
                        })
                );

        List<HotCompanySafetyManager> allManagers = baseMapper.selectList(lqw);

        if (CollUtil.isEmpty(allManagers)) {
            return Collections.emptyList();
        }

        // 如果是新增（currentId 为空），所有人都是候选人
        if (currentId == null) {
            return MapstructUtils.convert(allManagers, HotCompanySafetyManagerVo.class);
        }

        // 2. 过滤掉自己
        List<HotCompanySafetyManager> candidates = allManagers.stream()
                .filter(m -> !m.getId().equals(currentId))
                .collect(Collectors.toList());

        // 3. 构建上下级关系映射 (Parent ID -> List<Child ID>)
        Map<Long, List<Long>> childrenMap = allManagers.stream()
                .filter(m -> m.getReporterId() != null)
                .collect(Collectors.groupingBy(HotCompanySafetyManager::getReporterId,
                        Collectors.mapping(HotCompanySafetyManager::getId, Collectors.toList())));

        // 4. 找出 currentId 的所有下级（递归）
        Set<Long> descendants = new HashSet<>();
        findDescendants(currentId, childrenMap, descendants);

        // 5. 过滤掉所有下级
        return candidates.stream()
                .filter(m -> !descendants.contains(m.getId()))
                .map(m -> {
                    HotCompanySafetyManagerVo vo = new HotCompanySafetyManagerVo();
                    vo.setId(m.getId());
                    vo.setName(m.getName());
                    return vo;
                })
                .collect(Collectors.toList());
    }

    private void findDescendants(Long currentId, Map<Long, List<Long>> childrenMap, Set<Long> descendants) {
        List<Long> children = childrenMap.get(currentId);
        if (CollUtil.isNotEmpty(children)) {
            for (Long childId : children) {
                // 防止数据本身有环导致死循环
                if (descendants.add(childId)) {
                    findDescendants(childId, childrenMap, descendants);
                }
            }
        }
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public Boolean resetPassword(Long id) {
        HotCompanySafetyManager mgr = baseMapper.selectById(id);
        if (mgr == null) {
            log.warn("[安全管理人员重置密码] 未找到安全管理人员 id={}", id);
            return false;
        }
        SysUser sysUser = findUserByPhone(mgr.getPhone());
        if (sysUser == null) {
            log.warn("[安全管理人员重置密码] 未找到系统用户 phone={} (managerId={})", mgr.getPhone(), id);
            return false;
        }
        String phoneNumber = sysUser.getPhonenumber();
        if (StringUtils.isBlank(phoneNumber)) {
            log.warn("[SafetyManager-ResetPwd] 系统用户手机号为空 userId={}", sysUser.getUserId());
            return false;
        }

        String defaultPassword = PasswordUtils.createDefaultPassword(phoneNumber);

        userService.checkUserAllowed(sysUser.getUserId());
        userService.checkUserDataScope(sysUser.getUserId());
        int rows = userService.resetUserPwd(sysUser.getUserId(), defaultPassword, mgr.getCompanyId());
        if (rows > 0) {
            log.info("[安全管理人员重置密码] managerId={}, userId={}, operator={}", id, sysUser.getUserId(), LoginHelper.getUserId());
            return true;
        }
        return false;
    }

    // 需要插入两个角色，一个是进入企业端，一个是其他权限业务权限，如果不存在，则创建
    private void applyRoleByPermissionType(Long userId, HotCompanySafetyManager bo) {
        Long companyId = bo.getCompanyId();
        Long permissionRoleId = bo.getPermissionRoleId();
        String name = bo.getName();

        if (userId == null || companyId == null || permissionRoleId == null) {
            log.warn("[安全管理人员角色] 参数无效，跳过设置 userId={}, companyId={}, permissionRoleId={}", userId, companyId, permissionRoleId);
            return;
        }

        // 使用企业角色
        SysCompanyRole role = sysCompanyRoleMapper.selectOne(Wrappers.<SysCompanyRole>lambdaQuery()
                .eq(SysCompanyRole::getId, permissionRoleId)
                .eq(SysCompanyRole::getStatus, "0"));

        if (role == null) {
            throw new org.dromara.common.core.exception.ServiceException("未找到匹配的企业角色，请检查角色配置");
        }

        Long roleId = role.getId();
        clearGrantedPermissions(companyId, userId);

        List<SysUserLoginPort> list = sysUserLoginPortMapper.selectList(Wrappers.<SysUserLoginPort>lambdaQuery()
                .eq(SysUserLoginPort::getCompanyId, companyId)
                .eq(SysUserLoginPort::getUserId, userId)
                .eq(SysUserLoginPort::getLoginPort, ENTERPRISE_PORT) // 插入企业端端口
                .eq(SysUserLoginPort::getStatus, 1));

        if (CollUtil.isEmpty(list)) {
            // 取保新增的用户能进入企业端
            SysUserLoginPort ucr = new SysUserLoginPort();
            ucr.setCompanyId(companyId);
            ucr.setUserId(userId);
            ucr.setLoginPort(ENTERPRISE_PORT);
            ucr.setUsername(name);
            ucr.setIsDefault(0);
            ucr.setStatus(1);
            sysUserLoginPortMapper.insert(ucr);
            log.info("[安全管理人员角色] 关联企业角色 userId={}, companyId={}, roleId={} ({})", userId, companyId, roleId, permissionRoleId);
        } else {
            // 用户已关联企业角色，无需重复添加
            log.info("[安全管理人员角色] 用户已关联企业角色，跳过端口添加 userId={}, companyId={}", userId, companyId);
        }
    }

    private void validatePermissionAssignment(Long companyId, Long targetCompanyHead) {
        if (companyId == null) {
            return;
        }
        LoginUser loginUser = LoginHelper.getLoginUser();
        if (loginUser == null || loginUser.getUserId() == null) {
            throw new ServiceException("登录状态异常，请重新登录后重试");
        }
        HotCompanySafetyManager operator = baseMapper.selectOne(Wrappers.<HotCompanySafetyManager>lambdaQuery()
                .eq(HotCompanySafetyManager::getCompanyId, companyId)
                .eq(HotCompanySafetyManager::getUserId, loginUser.getUserId())
                .eq(HotCompanySafetyManager::getIsDeleted, 0L)
                .eq(HotCompanySafetyManager::getIsResigned, 0L)
                .eq(HotCompanySafetyManager::getStatus, 1L));
        if (operator == null) {
            throw new ServiceException("仅企业负责人或安全管理人员可以分配权限");
        }
        if (Long.valueOf(1L).equals(targetCompanyHead)) {
            throw new ServiceException("不允许给企业负责人分配权限");
        }
    }

    private void clearGrantedPermissions(Long companyId, Long userId) {
        hotCompanyPermissionGrantMapper.update(null, Wrappers.<HotCompanyPermissionGrant>lambdaUpdate()
                .eq(HotCompanyPermissionGrant::getCompanyId, companyId)
                .eq(HotCompanyPermissionGrant::getGranteeUserId, userId)
                .eq(HotCompanyPermissionGrant::getIsDeleted, 0L)
                .set(HotCompanyPermissionGrant::getStatus, 0L)
                .set(HotCompanyPermissionGrant::getIsDeleted, 1L));
    }
}
