package com.hotwj.platform.driverManagement.driver.service.impl;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.date.DateUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.baomidou.mybatisplus.core.toolkit.IdWorker;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.hotwj.platform.common.helper.DriverLoginContextHelper;
import com.hotwj.platform.common.utils.PasswordUtils;
import com.hotwj.platform.driverManagement.driver.domain.HotDriver;
import com.hotwj.platform.driverManagement.driver.domain.bo.DriverRegisterBo;
import com.hotwj.platform.driverManagement.driver.domain.bo.HotDriverBatchBindVehicleBo;
import com.hotwj.platform.driverManagement.driver.domain.bo.HotDriverBo;
import com.hotwj.platform.driverManagement.driver.domain.bo.HotDriverSwitchVehicleBo;
import com.hotwj.platform.driverManagement.driver.domain.vo.HotDriverImportVo;
import com.hotwj.platform.driverManagement.driver.domain.vo.HotDriverVo;
import com.hotwj.platform.driverManagement.driver.mapper.HotDriverMapper;
import com.hotwj.platform.driverManagement.driver.service.IHotDriverService;
import com.hotwj.platform.driverManagement.driverAnnualAssessment.domain.HotDriverAnnualAssessment;
import com.hotwj.platform.driverManagement.driverAnnualAssessment.mapper.HotDriverAnnualAssessmentMapper;
import com.hotwj.platform.driverManagement.driverFamilyMember.domain.HotDriverFamilyMember;
import com.hotwj.platform.driverManagement.driverFamilyMember.mapper.HotDriverFamilyMemberMapper;
import com.hotwj.platform.driverManagement.driverGroup.domain.HotDriverGroup;
import com.hotwj.platform.driverManagement.driverGroup.mapper.HotDriverGroupMapper;
import com.hotwj.platform.driverManagement.driverHealthReport.domain.HotDriverHealthReport;
import com.hotwj.platform.driverManagement.driverHealthReport.mapper.HotDriverHealthReportMapper;
import com.hotwj.platform.driverManagement.driverLaborContract.domain.HotDriverLaborContract;
import com.hotwj.platform.driverManagement.driverLaborContract.mapper.HotDriverLaborContractMapper;
import com.hotwj.platform.driverManagement.driverRewardPunishment.domain.HotDriverRewardPunishment;
import com.hotwj.platform.driverManagement.driverRewardPunishment.mapper.HotDriverRewardPunishmentMapper;
import com.hotwj.platform.driverManagement.driverSkillAssessment.domain.HotDriverSkillAssessment;
import com.hotwj.platform.driverManagement.driverSkillAssessment.mapper.HotDriverSkillAssessmentMapper;
import com.hotwj.platform.driverManagement.driverWorkExperience.domain.HotDriverWorkExperience;
import com.hotwj.platform.driverManagement.driverWorkExperience.mapper.HotDriverWorkExperienceMapper;
import com.hotwj.platform.driverManagement.inviteLog.domain.HotDriverInviteLog;
import com.hotwj.platform.driverManagement.inviteLog.mapper.HotDriverInviteLogMapper;
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.config.vehicleThreeInspect.service.IHotVehicleThreeInspectService;
import com.hotwj.platform.resourceManagement.company.domain.SysUserLoginPort;
import com.hotwj.platform.resourceManagement.company.domain.vo.SysCompanyVo;
import com.hotwj.platform.resourceManagement.company.service.ISysCompanyService;
import com.hotwj.platform.resourceManagement.company.service.ISysUserLoginPortService;
import com.hotwj.platform.resourceManagement.companySafetyManager.domain.HotCompanySafetyManager;
import com.hotwj.platform.resourceManagement.companySafetyManager.mapper.HotCompanySafetyManagerMapper;
import com.hotwj.platform.resourceManagement.vehicleManagement.domain.HotVehicle;
import com.hotwj.platform.resourceManagement.vehicleManagement.mapper.HotVehicleMapper;
import jakarta.validation.ConstraintViolation;
import jakarta.validation.ConstraintViolationException;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.dromara.common.core.exception.ServiceException;
import org.dromara.common.core.utils.MapstructUtils;
import org.dromara.common.core.utils.StringUtils;
import org.dromara.common.core.utils.ValidatorUtils;
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.bo.SysUserBo;
import org.dromara.system.domain.vo.SysUserVo;
import org.dromara.system.service.ISysUserService;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

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

/**
 * 驾驶员基本信息Service业务层处理
 *
 * @author shihongwei
 * @date 2025-12-19
 */
@Slf4j
@RequiredArgsConstructor
@Service
public class HotDriverServiceImpl implements IHotDriverService {

    private final HotDriverMapper baseMapper;
    private final HotDriverFamilyMemberMapper driverFamilyMemberMapper;
    private final HotDriverWorkExperienceMapper driverWorkExperienceMapper;
    private final HotDriverLaborContractMapper driverLaborContractMapper;
    private final HotDriverHealthReportMapper driverHealthReportMapper;
    private final ISysCompanyService sysCompanyService;
    private final HotDriverInviteLogMapper inviteLogMapper;
    private final ISysUserService sysUserService;
    private final ISysUserLoginPortService sysUserLoginPortService;
    private final HotVehicleMapper vehicleMapper;
    private final HotDriverMapper driverMapper;
    private final HotCompanySafetyManagerMapper managerMapper;
    private final HotDriverGroupMapper groupMapper;
    private final IHotSystemNotificationService notificationService;
    private final HotDriverRewardPunishmentMapper rewardPunishmentMapper;
    private final HotDriverSkillAssessmentMapper skillAssessmentMapper;
    private final HotDriverAnnualAssessmentMapper annualAssessmentMapper;
    private final IHotNoticeSignDocumentService noticeSignDocumentService;
    private final IHotVehicleThreeInspectService hotVehicleThreeInspectService;

    /**
     * 查询驾驶员基本信息
     *
     * @param id 主键
     * @return 驾驶员基本信息
     */
    @Override
    public HotDriverVo queryById(String id) {
        HotDriverVo vo = baseMapper.selectVoById(id);
        fillVehiclePlateNumbers(Collections.singletonList(vo));
        return vo;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public Boolean registerByInviteCode(DriverRegisterBo bo) {
        // 1. 校验邀请码
        SysCompanyVo company = sysCompanyService.queryByInviteCode(bo.getInviteCode());
        if (company == null) {
            throw new ServiceException("邀请码无效");
        }
        if (!company.getId().equals(bo.getCompanyId())) {
            throw new ServiceException("邀请码与企业不匹配");
        }

        // 2. 校验手机号是否已存在
        SysUserVo existingUser = sysUserService.selectUserByPhonenumber(bo.getPhone());
        if (existingUser != null) {
            throw new ServiceException("手机号已存在");
        }
        HotDriver existingDriver = baseMapper.selectOne(Wrappers.<HotDriver>lambdaQuery().eq(HotDriver::getPhone, bo.getPhone()));
        if (existingDriver != null) {
            throw new ServiceException("驾驶员信息已存在");
        }

        // 3. 创建驾驶员信息
        HotDriver driver = new HotDriver();
        String driverId = IdWorker.get32UUID();
        driver.setId(driverId);
        driver.setCompanyId(bo.getCompanyId());
        driver.setPhone(bo.getPhone());
        driver.setPersonType(bo.getPersonType());
        // 初始姓名暂存为手机号，待完善
//        driver.setName(bo.getPhone());
        driver.setAuditStatus(0); // 待审核
        driver.setStatus(1L);
        driver.setCreateTime(new Date());
        // 其他必填项需后续完善
        int insert = baseMapper.insert(driver);

        if (insert > 0) {
            // 4. 同步驾驶员信息到用户表
            syncDriverToSysUser(driver, bo.getPassword());
            // 5. 根据默认新进人员配置自动下发签订文件
            noticeSignDocumentService.issueDefaultForNewDriver(driver);
            // 5. 记录邀请日志
            HotDriverInviteLog log = new HotDriverInviteLog();
            log.setInviteCode(bo.getInviteCode());
            log.setCompanyId(company.getId());
            log.setDriverId(driverId);
            log.setDriverName(driver.getName());
            log.setDriverPhone(driver.getPhone());
            log.setCreateTime(new Date());
            inviteLogMapper.insert(log);
        }

        return true;
    }

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

    @Override
    @Transactional(rollbackFor = Exception.class)
    public Boolean updatePassword(String driverId, String newPassword) {
        HotDriver driver = baseMapper.selectById(driverId);
        if (driver == null || Long.valueOf(1L).equals(driver.getIsDeleted())) {
            throw new ServiceException("驾驶员不存在");
        }
        if (driver.getCompanyId() == null) {
            throw new ServiceException("驾驶员未关联企业，无法修改密码");
        }
        validateCompanyHeadPermission(driver.getCompanyId());

        if (StringUtils.isBlank(driver.getPhone())) {
            throw new ServiceException("驾驶员手机号为空，无法修改密码");
        }
        SysUserVo sysUser = sysUserService.selectUserByPhonenumber(driver.getPhone());
        if (sysUser == null || sysUser.getUserId() == null) {
            throw new ServiceException("未找到驾驶员关联账号");
        }

        int rows = sysUserService.resetUserPwd(sysUser.getUserId(), PasswordUtils.createPassword(newPassword), driver.getCompanyId());
        if (rows <= 0) {
            throw new ServiceException("修改失败，请确认驾驶员账号已开通");
        }
        log.info("[驾驶员修改密码] driverId={}, userId={}, operator={}, companyId={}",
                driverId, sysUser.getUserId(), LoginHelper.getUserId(), driver.getCompanyId());
        return true;
    }

    /**
     * 分页查询驾驶员基本信息列表
     *
     * @param bo        查询条件
     * @param pageQuery 分页参数
     * @return 驾驶员基本信息分页列表
     */
    @Override
    public TableDataInfo<HotDriverVo> queryPageList(HotDriverBo bo, PageQuery pageQuery) {
        LambdaQueryWrapper<HotDriver> lqw = buildQueryWrapper(bo);
        Page<HotDriverVo> result = baseMapper.selectVoPage(pageQuery.build(), lqw);
        fillVehiclePlateNumbers(result.getRecords());
        return TableDataInfo.build(result);
    }

    /**
     * 查询符合条件的驾驶员基本信息列表
     *
     * @param bo 查询条件
     * @return 驾驶员基本信息列表
     */
    @Override
    public List<HotDriverVo> queryList(HotDriverBo bo) {
        LambdaQueryWrapper<HotDriver> lqw = buildQueryWrapper(bo);
        List<HotDriverVo> list = baseMapper.selectVoList(lqw);
        fillVehiclePlateNumbers(list);
        return list;
    }

    private void fillVehiclePlateNumbers(Collection<HotDriverVo> drivers) {
        if (CollUtil.isEmpty(drivers)) {
            return;
        }
        Set<String> vehicleIds = new LinkedHashSet<>();
        for (HotDriverVo driver : drivers) {
            if (driver == null) {
                continue;
            }
            vehicleIds.addAll(splitCsv(driver.getVehicleIds()));
        }
        if (CollUtil.isEmpty(vehicleIds)) {
            return;
        }
        List<HotVehicle> vehicles = vehicleMapper.selectList(Wrappers.<HotVehicle>lambdaQuery()
                .in(HotVehicle::getId, vehicleIds)
                .eq(HotVehicle::getIsDeleted, 0L));
        Map<String, String> vehiclePlateMap = vehicles.stream()
                .filter(Objects::nonNull)
                .filter(vehicle -> StringUtils.isNotBlank(vehicle.getId()))
                .collect(Collectors.toMap(HotVehicle::getId, HotVehicle::getPlateNumber, (left, right) -> left));
        for (HotDriverVo driver : drivers) {
            if (driver == null) {
                continue;
            }
            String joinedPlateNumbers = splitCsv(driver.getVehicleIds()).stream()
                    .map(vehiclePlateMap::get)
                    .filter(StringUtils::isNotBlank)
                    .collect(Collectors.joining(","));
            driver.setVehiclePlateNumbers(StringUtils.isNotBlank(joinedPlateNumbers) ? joinedPlateNumbers : null);
        }
    }

    private LambdaQueryWrapper<HotDriver> buildQueryWrapper(HotDriverBo bo) {
        Map<String, Object> params = bo.getParams();
        LambdaQueryWrapper<HotDriver> lqw = Wrappers.lambdaQuery();
        lqw.orderByDesc(HotDriver::getCreateTime);
        lqw.in(CollUtil.isNotEmpty(bo.getIds()), HotDriver::getId, bo.getIds());
        lqw.eq(bo.getCompanyId() != null, HotDriver::getCompanyId, bo.getCompanyId());
        lqw.eq(bo.getEntryDate() != null, HotDriver::getEntryDate, bo.getEntryDate());
        lqw.like(StringUtils.isNotBlank(bo.getName()), HotDriver::getName, bo.getName());
        lqw.eq(StringUtils.isNotBlank(bo.getPersonType()), HotDriver::getPersonType, bo.getPersonType());
        lqw.eq(bo.getDrivingYears() != null, HotDriver::getDrivingYears, bo.getDrivingYears());
        lqw.like(StringUtils.isNotBlank(bo.getPhone()), HotDriver::getPhone, bo.getPhone());
        lqw.eq(StringUtils.isNotBlank(bo.getGender()), HotDriver::getGender, bo.getGender());
        lqw.eq(StringUtils.isNotBlank(bo.getNation()), HotDriver::getNation, bo.getNation());
        lqw.eq(bo.getStartWorkDate() != null, HotDriver::getStartWorkDate, bo.getStartWorkDate());
        lqw.eq(StringUtils.isNotBlank(bo.getHouseholdAddress()), HotDriver::getHouseholdAddress, bo.getHouseholdAddress());
        lqw.eq(StringUtils.isNotBlank(bo.getNativePlace()), HotDriver::getNativePlace, bo.getNativePlace());
        lqw.eq(StringUtils.isNotBlank(bo.getCurrentAddress()), HotDriver::getCurrentAddress, bo.getCurrentAddress());
        lqw.eq(bo.getIsPartyMember() != null, HotDriver::getIsPartyMember, bo.getIsPartyMember());
        lqw.eq(bo.getMaritalStatus() != null, HotDriver::getMaritalStatus, bo.getMaritalStatus());
        lqw.eq(StringUtils.isNotBlank(bo.getEducation()), HotDriver::getEducation, bo.getEducation());
        lqw.eq(StringUtils.isNotBlank(bo.getHealthStatus()), HotDriver::getHealthStatus, bo.getHealthStatus());
        lqw.eq(bo.getBirthDate() != null, HotDriver::getBirthDate, bo.getBirthDate());
        lqw.like(StringUtils.isNotBlank(bo.getIdCardNo()), HotDriver::getIdCardNo, bo.getIdCardNo());
        lqw.eq(bo.getIdCardExpireDate() != null, HotDriver::getIdCardExpireDate, bo.getIdCardExpireDate());
        lqw.eq(bo.getIdCardLongTerm() != null, HotDriver::getIdCardLongTerm, bo.getIdCardLongTerm());
        lqw.eq(StringUtils.isNotBlank(bo.getIdcardFrontUrl()), HotDriver::getIdcardFrontUrl, bo.getIdcardFrontUrl());
        lqw.eq(StringUtils.isNotBlank(bo.getIdcardBackUrl()), HotDriver::getIdcardBackUrl, bo.getIdcardBackUrl());
        lqw.eq(StringUtils.isNotBlank(bo.getPortraitUrl()), HotDriver::getPortraitUrl, bo.getPortraitUrl());
        lqw.eq(StringUtils.isNotBlank(bo.getSignatureUrl()), HotDriver::getSignatureUrl, bo.getSignatureUrl());
        lqw.eq(bo.getIntegrityPromiseExpireDate() != null, HotDriver::getIntegrityPromiseExpireDate, bo.getIntegrityPromiseExpireDate());
        lqw.eq(StringUtils.isNotBlank(bo.getIntegrityLevel()), HotDriver::getIntegrityLevel, bo.getIntegrityLevel());
        lqw.eq(StringUtils.isNotBlank(bo.getIntegrityPromiseAttachmentUrl()), HotDriver::getIntegrityPromiseAttachmentUrl, bo.getIntegrityPromiseAttachmentUrl());
        lqw.eq(StringUtils.isNotBlank(bo.getHrOpinion()), HotDriver::getHrOpinion, bo.getHrOpinion());
        lqw.eq(StringUtils.isNotBlank(bo.getDeptOpinion()), HotDriver::getDeptOpinion, bo.getDeptOpinion());
        lqw.eq(StringUtils.isNotBlank(bo.getLeaderOpinion()), HotDriver::getLeaderOpinion, bo.getLeaderOpinion());
        lqw.eq(StringUtils.isNotBlank(bo.getRewardOrPunishment()), HotDriver::getRewardOrPunishment, bo.getRewardOrPunishment());
        lqw.eq(StringUtils.isNotBlank(bo.getSignature()), HotDriver::getSignature, bo.getSignature());
        lqw.eq(bo.getStatus() != null, HotDriver::getStatus, bo.getStatus());
        lqw.eq(bo.getAuditStatus() != null, HotDriver::getAuditStatus, bo.getAuditStatus());
        lqw.eq(bo.getIsDeleted() != null, HotDriver::getIsDeleted, bo.getIsDeleted());
        lqw.eq(bo.getDriverLicenseFirstIssueDate() != null, HotDriver::getDriverLicenseFirstIssueDate, bo.getDriverLicenseFirstIssueDate());
        lqw.eq(bo.getDriverLicenseExpireDate() != null, HotDriver::getDriverLicenseExpireDate, bo.getDriverLicenseExpireDate());
        lqw.eq(bo.getDriverLicenseLongTerm() != null, HotDriver::getDriverLicenseLongTerm, bo.getDriverLicenseLongTerm());
        lqw.eq(StringUtils.isNotBlank(bo.getDriverLicenseVehicleType()), HotDriver::getDriverLicenseVehicleType, bo.getDriverLicenseVehicleType());
        lqw.eq(StringUtils.isNotBlank(bo.getDriverLicenseNo()), HotDriver::getDriverLicenseNo, bo.getDriverLicenseNo());
        lqw.eq(StringUtils.isNotBlank(bo.getDriverLicenseArchiveNo()), HotDriver::getDriverLicenseArchiveNo, bo.getDriverLicenseArchiveNo());
        lqw.eq(StringUtils.isNotBlank(bo.getDriverLicenseOrg()), HotDriver::getDriverLicenseOrg, bo.getDriverLicenseOrg());
        lqw.eq(StringUtils.isNotBlank(bo.getDriverLicenseMainImg()), HotDriver::getDriverLicenseMainImg, bo.getDriverLicenseMainImg());
        lqw.eq(StringUtils.isNotBlank(bo.getDriverLicenseViceImg()), HotDriver::getDriverLicenseViceImg, bo.getDriverLicenseViceImg());
        lqw.eq(StringUtils.isNotBlank(bo.getDriverLicenseOtherImg()), HotDriver::getDriverLicenseOtherImg, bo.getDriverLicenseOtherImg());
        lqw.eq(StringUtils.isNotBlank(bo.getQualificationType()), HotDriver::getQualificationType, bo.getQualificationType());
        lqw.eq(StringUtils.isNotBlank(bo.getQualificationNo()), HotDriver::getQualificationNo, bo.getQualificationNo());
        lqw.eq(bo.getQualificationFirstIssueDate() != null, HotDriver::getQualificationFirstIssueDate, bo.getQualificationFirstIssueDate());
        lqw.eq(bo.getQualificationValidStartDate() != null, HotDriver::getQualificationValidStartDate, bo.getQualificationValidStartDate());
        lqw.eq(bo.getQualificationValidEndDate() != null, HotDriver::getQualificationValidEndDate, bo.getQualificationValidEndDate());
        lqw.eq(StringUtils.isNotBlank(bo.getQualificationOrg()), HotDriver::getQualificationOrg, bo.getQualificationOrg());
        lqw.eq(StringUtils.isNotBlank(bo.getQualificationImg()), HotDriver::getQualificationImg, bo.getQualificationImg());
        return lqw;
    }

    private void validateCompanyHeadPermission(Long targetCompanyId) {
        Long loginUserId = LoginHelper.getUserId();
        Long loginCompanyId = LoginHelper.getCompanyId();
        if (loginUserId == null) {
            throw new ServiceException("当前登录信息已失效");
        }
        if (loginCompanyId == null || !Objects.equals(loginCompanyId, targetCompanyId)) {
            throw new ServiceException("仅可修改本企业驾驶员密码");
        }
        String loginPort = LoginHelper.getLoginUser() != null ? LoginHelper.getLoginUser().getLoginPort() : null;
        if (!ISysUserLoginPortService.ENTERPRISE_PORT.equals(loginPort)) {
            throw new ServiceException("仅企业端负责人可修改驾驶员密码");
        }
        Long count = managerMapper.selectCount(Wrappers.<HotCompanySafetyManager>lambdaQuery()
                .eq(HotCompanySafetyManager::getUserId, loginUserId)
                .eq(HotCompanySafetyManager::getCompanyId, targetCompanyId)
                .eq(HotCompanySafetyManager::getCompanyHead, 1L)
                .eq(HotCompanySafetyManager::getIsDeleted, 0L)
                .eq(HotCompanySafetyManager::getIsResigned, 0L)
                .eq(HotCompanySafetyManager::getStatus, 1L));
        if (count == null || count == 0) {
            throw new ServiceException("仅企业负责人可修改驾驶员密码");
        }
    }

    /**
     * 新增驾驶员基本信息
     *
     * @param bo 驾驶员基本信息
     * @return 是否新增成功
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public Boolean insertByBo(HotDriverBo bo) {
        // 校验手机号
        checkPhoneUnique(bo.getPhone(), null);

        HotDriver add = MapstructUtils.convert(bo, HotDriver.class);
        String id = IdWorker.get32UUID();
        add.setId(id);
        if (add.getAuditStatus() == null) {
            add.setAuditStatus(0);
        }
        if (add.getStatus() == null) {
            add.setStatus(1L);
        }
        validEntityBeforeSave(add);
        boolean flag = baseMapper.insert(add) > 0;
        if (flag) {
            bo.setId(add.getId());
        }

        insertDriverFamilyMembers(bo, id);
        insertDriverWorkExperiences(bo, id);
        insertDriverLaborContracts(bo, id);
        insertDriverHealthReports(bo, id);

        // 创建关联账号或同步信息
        // 无论是否有邀请码，都尝试同步/创建账号
        if (flag) {
            syncDriverToSysUser(add, null);
            noticeSignDocumentService.issueDefaultForNewDriver(add);
        }

        return flag;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public Boolean auditDriver(String driverId, Integer auditStatus) {
        HotDriver driver = baseMapper.selectById(driverId);
        if (driver == null) {
            throw new ServiceException("驾驶员不存在");
        }
        Integer oldAuditStatus = driver.getAuditStatus();
        driver.setAuditStatus(auditStatus);
        boolean flag = baseMapper.updateById(driver) > 0;

        if (flag) {
            // 同步账号状态
            syncDriverToSysUser(driver, null);

            // 检查审核状态变更：变成未通过(0)
            boolean isAuditRejected = (oldAuditStatus == null || oldAuditStatus != 0) && (auditStatus != null && auditStatus == 0);
            if (isAuditRejected) {
                handleDriverResignation(driverId, driver.getPhone(), driver.getCompanyId());
            }
        }

        return flag;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public String importData(List<HotDriverImportVo> driverList, Long companyId) {
        if (CollUtil.isEmpty(driverList)) {
            throw new ServiceException("导入数据不能为空！");
        }
        int successNum = 0;
        int failureNum = 0;
        StringBuilder successMsg = new StringBuilder();
        StringBuilder failureMsg = new StringBuilder();
        Set<String> batchIdCards = new HashSet<>();

        for (HotDriverImportVo vo : driverList) {
            try {
                ValidatorUtils.validate(vo);
                String idCardNo = vo.getIdCardNo();
                if (StringUtils.isBlank(idCardNo)) {
                    failureNum++;
                    failureMsg.append("<br/>").append(failureNum).append("、缺少身份证号，不能导入");
                    continue;
                }
                if (!batchIdCards.add(idCardNo)) {
                    failureNum++;
                    failureMsg.append("<br/>").append(failureNum).append("、身份证号 ").append(idCardNo).append(" 在本次导入中重复，不能导入重复的人员信息");
                    continue;
                }
                boolean exists = baseMapper.selectCount(new LambdaQueryWrapper<HotDriver>()
                        .eq(HotDriver::getIdCardNo, idCardNo)
                        .eq(HotDriver::getCompanyId, companyId)
                        .eq(HotDriver::getIsDeleted, 0L)) > 0;
                if (exists) {
                    failureNum++;
                    failureMsg.append("<br/>").append(failureNum).append("、身份证号 ").append(idCardNo).append(" 已存在，不能导入重复的人员信息");
                    continue;
                }

                HotDriver driver = buildDriverFromImport(vo);

                // 校验手机号唯一性
                if (StringUtils.isNotBlank(driver.getPhone())) {
                    try {
                        checkPhoneUnique(driver.getPhone(), null);
                    } catch (ServiceException e) {
                        failureNum++;
                        failureMsg.append("<br/>").append(failureNum).append("、手机号 ").append(driver.getPhone()).append(" 已存在，不能导入重复的人员信息");
                        continue;
                    }
                }

                String id = IdWorker.get32UUID();
                driver.setId(id);
                driver.setCompanyId(companyId);
                driver.setStatus(1L);
                driver.setIsDeleted(0L);
                driver.setCreateTime(new Date());
                driver.setAuditStatus(0);
                validEntityBeforeSave(driver);

                baseMapper.insert(driver);
                // 创建关联账号或同步信息
                syncDriverToSysUser(driver, null);
                noticeSignDocumentService.issueDefaultForNewDriver(driver);
                successNum++;
                String nameOrCard = StringUtils.blankToDefault(driver.getName(), idCardNo);
                successMsg.append("<br/>").append(successNum).append("、驾驶员 ").append(nameOrCard).append(" 导入成功");
            } catch (ConstraintViolationException e) {
                failureNum++;
                String msg = e.getConstraintViolations().stream()
                        .map(ConstraintViolation::getMessage)
                        .collect(Collectors.joining(", "));
                failureMsg.append("<br/>").append(failureNum).append("、身份证号 ")
                        .append(vo.getIdCardNo()).append(" 导入失败：").append(msg);
            } catch (Exception e) {
                failureNum++;
                String msg = "<br/>" + failureNum + "、身份证号 " + vo.getIdCardNo() + " 导入失败：";
                failureMsg.append(msg).append(e.getMessage());
                log.error(msg, e);
            }
        }
        if (failureNum > 0) {
            failureMsg.insert(0, "很抱歉，导入失败！共 " + failureNum + " 条校验错误，错误如下：");
            throw new ServiceException(failureMsg.toString());
        } else {
            successMsg.insert(0, "恭喜您，数据已全部导入成功！共 " + successNum + " 条，数据如下：");
        }
        return successMsg.toString();
    }

    private HotDriver buildDriverFromImport(HotDriverImportVo vo) {
        HotDriver driver = new HotDriver();
        driver.setName(vo.getName());
        driver.setPhone(vo.getPhone());
        driver.setPlateNumber(vo.getPlateNumber());
        driver.setIdCardNo(vo.getIdCardNo());
        setIdCardExpire(driver, vo.getIdCardExpireDate());
        driver.setDriverLicenseFirstIssueDate(vo.getDriverLicenseFirstIssueDate());
        driver.setDriverLicenseVehicleType(vo.getDriverLicenseVehicleType());
        setDriverLicenseExpire(driver, vo.getDriverLicenseExpireDate());
        driver.setDriverLicenseOrg(vo.getDriverLicenseOrg());
        driver.setGender(vo.getGender());
        driver.setNation(vo.getNation());
        driver.setQualificationType(vo.getQualificationType());
        driver.setQualificationNo(vo.getQualificationNo());
        driver.setQualificationFirstIssueDate(vo.getQualificationFirstIssueDate());
        driver.setQualificationValidEndDate(vo.getQualificationValidEndDate());
        driver.setQualificationValidStartDate(vo.getQualificationValidStartDate());
        driver.setQualificationOrg(vo.getQualificationOrg());
        driver.setBirthDate(vo.getBirthDate());
        driver.setHouseholdAddress(vo.getHouseholdAddress());
        driver.setCurrentAddress(vo.getCurrentAddress());
        driver.setEducation(vo.getEducation());
        driver.setPoliticalStatus(vo.getPoliticalStatus());
        driver.setMaritalStatus(vo.getMaritalStatus());
        driver.setHealthStatus(vo.getHealthStatus());
        driver.setEntryDate(vo.getEntryDate());
        driver.setPersonType(vo.getPersonType());
        return driver;
    }

    private void setIdCardExpire(HotDriver driver, String rawValue) {
        String text = normalizeCellText(rawValue);
        if (text == null) {
            driver.setIdCardExpireDate(null);
            driver.setIdCardLongTerm(null);
            return;
        }
        if (isLongTerm(text)) {
            driver.setIdCardExpireDate(null);
            driver.setIdCardLongTerm(1L);
            return;
        }
        driver.setIdCardExpireDate(parseDateText(text, "身份证到期时间"));
        driver.setIdCardLongTerm(0L);
    }

    private void setDriverLicenseExpire(HotDriver driver, String rawValue) {
        String text = normalizeCellText(rawValue);
        if (text == null) {
            driver.setDriverLicenseExpireDate(null);
            driver.setDriverLicenseLongTerm(null);
            return;
        }
        if (isLongTerm(text)) {
            driver.setDriverLicenseExpireDate(null);
            driver.setDriverLicenseLongTerm(1L);
            return;
        }
        driver.setDriverLicenseExpireDate(parseDateText(text, "驾驶证到期时间"));
        driver.setDriverLicenseLongTerm(0L);
    }

    private Date parseDateText(String text, String fieldName) {
        try {
            return DateUtil.parse(text).toJdkDate();
        } catch (Exception e) {
            throw new ServiceException(fieldName + "格式错误，值：" + text + "，请填写yyyy-MM-dd或“长期”");
        }
    }

    private boolean isLongTerm(String text) {
        return "长期".equals(text)
                || "长期有效".equals(text)
                || "长期/有效".equals(text)
                || "长期有效期".equals(text);
    }

    private String normalizeCellText(String text) {
        if (text == null) {
            return null;
        }
        String value = text.trim();
        return value.isEmpty() ? null : value;
    }

    /**
     * 同步驾驶员信息到系统用户
     */
    private void syncDriverToSysUser(HotDriver driver, String registerPassword) {
        if (driver == null || StringUtils.isBlank(driver.getPhone())) {
            return;
        }

        SysUserVo existingUser = sysUserService.selectUserByPhonenumber(driver.getPhone());
        Long userId = null;

        if (existingUser != null) {
            // 用户已存在，更新信息
            SysUserBo userUpdate = new SysUserBo();
            userUpdate.setUserId(existingUser.getUserId());
            userUpdate.setUserName(driver.getName());
            userUpdate.setPhonenumber(driver.getPhone());
            // 用户始终不禁用，只禁用端口
            userUpdate.setStatus("0");
            userUpdate.setPortEnable(driver.getStatus() != null && driver.getStatus() == 1L); // 只要启用了就能登录
            // 确保绑定驾驶员端口
            userUpdate.setCompanyId(driver.getCompanyId());
            userUpdate.setLoginPort(Collections.singletonList(ISysUserLoginPortService.DRIVER_PORT));
            userUpdate.setRoleIds(new Long[]{ISysUserLoginPortService.DRIVER_ROLE_ID});
            // 确保设置子密码（如果需要）- updateUser可能不会处理子密码初始化，所以需要单独检查

            // 此处使用 updateUser，旨在涵盖管理端的完整更新逻辑
            sysUserService.updateUser(userUpdate, false);
            userId = existingUser.getUserId();
        } else {
            // 用户不存在，创建新用户
            SysUserBo userBo = new SysUserBo();
            userBo.setUserName(driver.getName());
            userBo.setNickName(driver.getName());
            userBo.setPhonenumber(driver.getPhone());
            // 主密码保留默认
            userBo.setPassword(PasswordUtils.createDefaultPassword(driver.getPhone())); // 现在没用
            userBo.setStatus("0");
            userBo.setPortEnable(true);
            userBo.setCompanyId(driver.getCompanyId());
            userBo.setLoginPort(Collections.singletonList(ISysUserLoginPortService.DRIVER_PORT));
            userBo.setRoleIds(new Long[]{ISysUserLoginPortService.DRIVER_ROLE_ID});
            sysUserService.insertUser(userBo, false);
            log.info("驾驶员账号创建成功，驾驶员ID：{}，用户账号：{}", driver.getId(), userBo.getUserName());
            userId = sysUserService.selectUserByPhonenumber(driver.getPhone()).getUserId();
        }

        // 显式确保驾驶员端口和子密码存在
        ensureDriverLoginPort(userId, driver.getCompanyId(), driver.getName(), driver.getPhone(), registerPassword);
    }

    private void ensureDriverLoginPort(Long userId, Long companyId, String username, String phone, String registerPassword) {
        LambdaQueryWrapper<SysUserLoginPort> wrapper = new LambdaQueryWrapper<>();
        wrapper.eq(SysUserLoginPort::getUserId, userId)
                .eq(SysUserLoginPort::getCompanyId, companyId)
                .eq(SysUserLoginPort::getLoginPort, ISysUserLoginPortService.DRIVER_PORT);

        SysUserLoginPort port = sysUserLoginPortService.getOne(wrapper);
        // 子密码默认规则
        String defaultSubPwd = PasswordUtils.createDefaultPassword(phone);
        String regSubPwd = PasswordUtils.createPassword(registerPassword);
        if (port == null) {
            port = new SysUserLoginPort();
            port.setUserId(userId);
            port.setCompanyId(companyId);
            port.setUsername(username);
            port.setLoginPort(ISysUserLoginPortService.DRIVER_PORT);
            port.setStatus(1);
            if (StringUtils.isNotBlank(registerPassword)) {
                port.setSubPassword(regSubPwd);
            } else {
                port.setSubPassword(defaultSubPwd);
            }
            sysUserLoginPortService.save(port);
        } else {
            // 如果已存在但无子密码，初始化
            if (StringUtils.isBlank(port.getSubPassword())) {
                if (StringUtils.isNotBlank(registerPassword)) {
                    port.setSubPassword(regSubPwd);
                } else {
                    port.setSubPassword(defaultSubPwd);
                }
                sysUserLoginPortService.updateById(port);
            }
        }
    }

    /**
     * 修改驾驶员基本信息
     *
     * @param bo 驾驶员基本信息
     * @return 是否修改成功
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public Boolean updateByBo(HotDriverBo bo) {
        // 校验手机号
        checkPhoneUnique(bo.getPhone(), bo.getId());

        // 获取旧数据用于比对
        HotDriver oldDriver = baseMapper.selectById(bo.getId());
        HotDriver update = MapstructUtils.convert(bo, HotDriver.class);
        validEntityBeforeSave(update);
        boolean flag = baseMapper.updateById(update) > 0;

        String driverId = update.getId();
        Long companyId = update.getCompanyId();
        // 如果bo中没有companyId，尝试从旧数据获取，保证子表数据完整
        if (companyId == null && oldDriver != null) {
            companyId = oldDriver.getCompanyId();
        }

        if (bo.getDriverFamilyMemberList() != null) {
            LambdaQueryWrapper<HotDriverFamilyMember> familyDelLqw = Wrappers.lambdaQuery();
            familyDelLqw.eq(HotDriverFamilyMember::getDriverId, driverId);
            driverFamilyMemberMapper.delete(familyDelLqw);

            if (CollUtil.isNotEmpty(bo.getDriverFamilyMemberList())) {
                List<HotDriverFamilyMember> members = MapstructUtils.convert(bo.getDriverFamilyMemberList(), HotDriverFamilyMember.class);
                for (HotDriverFamilyMember m : members) {
                    m.setId(IdWorker.getId());
                    m.setDriverId(driverId);
                    m.setCompanyId(companyId);
                    m.setIsDeleted(0L);
                    driverFamilyMemberMapper.insert(m);
                }
            }
        }

        if (bo.getDriverWorkExperienceList() != null) {
            LambdaQueryWrapper<HotDriverWorkExperience> workDelLqw = Wrappers.lambdaQuery();
            workDelLqw.eq(HotDriverWorkExperience::getDriverId, driverId);
            driverWorkExperienceMapper.delete(workDelLqw);

            if (CollUtil.isNotEmpty(bo.getDriverWorkExperienceList())) {
                List<HotDriverWorkExperience> works = MapstructUtils.convert(bo.getDriverWorkExperienceList(), HotDriverWorkExperience.class);
                for (HotDriverWorkExperience w : works) {
                    w.setId(IdWorker.getId());
                    w.setDriverId(driverId);
                    w.setCompanyId(companyId);
                    w.setIsDeleted(0L);
                    driverWorkExperienceMapper.insert(w);
                }
            }
        }

        if (bo.getDriverLaborContractList() != null) {
            LambdaQueryWrapper<HotDriverLaborContract> laborDelLqw = Wrappers.lambdaQuery();
            laborDelLqw.eq(HotDriverLaborContract::getDriverId, driverId);
            driverLaborContractMapper.delete(laborDelLqw);

            if (CollUtil.isNotEmpty(bo.getDriverLaborContractList())) {
                List<HotDriverLaborContract> labors = MapstructUtils.convert(bo.getDriverLaborContractList(), HotDriverLaborContract.class);
                for (HotDriverLaborContract c : labors) {
                    c.setId(IdWorker.getId());
                    c.setDriverId(driverId);
                    c.setCompanyId(companyId);
                    c.setIsDeleted(0L);
                    driverLaborContractMapper.insert(c);
                }
            }
        }

        if (bo.getDriverHealthReportList() != null) {
            LambdaQueryWrapper<HotDriverHealthReport> healthDelLqw = Wrappers.lambdaQuery();
            healthDelLqw.eq(HotDriverHealthReport::getDriverId, driverId);
            driverHealthReportMapper.delete(healthDelLqw);

            if (CollUtil.isNotEmpty(bo.getDriverHealthReportList())) {
                List<HotDriverHealthReport> reports = MapstructUtils.convert(bo.getDriverHealthReportList(), HotDriverHealthReport.class);
                for (HotDriverHealthReport r : reports) {
                    r.setId(IdWorker.getId());
                    r.setDriverId(driverId);
                    r.setCompanyId(companyId);
                    r.setIsDeleted(0L);
                    driverHealthReportMapper.insert(r);
                }
            }
        }

        if (flag) {
            // 处理手机号变更：如果手机号改变，移除旧手机号对应的用户在当前企业的司机端权限
            if (oldDriver != null && StringUtils.isNotBlank(update.getPhone())
                    && !update.getPhone().equals(oldDriver.getPhone())) {
                removeDriverPortFromUser(oldDriver.getPhone(), oldDriver.getCompanyId());
            }

            Set<String> impactedDriverIds = new LinkedHashSet<>();
            impactedDriverIds.add(driverId);
            if (oldDriver != null) {
                impactedDriverIds.addAll(findOtherDriversBoundToVehicles(companyId, getBoundVehicleIds(oldDriver), driverId));
            }

            boolean bindingSpecified = bo.getVehicleIds() != null || bo.getVehicleId() != null || bo.getPlateNumber() != null;
            if (bindingSpecified) {
                List<HotVehicle> targetVehicles = resolveDriverTargetVehicles(bo, companyId);
                validateVehiclesCanChangeBinding(oldDriver == null ? null : getBoundVehicleIds(oldDriver), targetVehicles);
                impactedDriverIds.addAll(syncVehicleBindingsForDriver(driverId, companyId, targetVehicles));
            }

            syncDriverVehicleRelationsByDriverIds(companyId, impactedDriverIds);

            // 同步最新的驾驶员信息到用户表（包含状态变更、基本信息变更）
            HotDriver newDriver = baseMapper.selectById(driverId);
            syncDriverToSysUser(newDriver, null);
            Long oldStatus = oldDriver != null ? oldDriver.getStatus() : null;
            Long newStatus = update.getStatus();
            boolean resigned = oldStatus != null && Long.valueOf(1L).equals(oldStatus) && newStatus != null && Long.valueOf(0L).equals(newStatus);

            // 检查审核状态变更：变成未通过(0)
            Integer oldAuditStatus = oldDriver != null ? oldDriver.getAuditStatus() : null;
            Integer newAuditStatus = update.getAuditStatus();
            boolean isAuditRejected = (oldAuditStatus == null || oldAuditStatus != 0) && (newAuditStatus != null && newAuditStatus == 0);

            if ((resigned || isAuditRejected) && companyId != null) {
                String phone = StringUtils.isNotBlank(update.getPhone()) ? update.getPhone() : (oldDriver != null ? oldDriver.getPhone() : null);
                handleDriverResignation(driverId, phone, companyId);
            }

            if (resigned && companyId != null) {
                List<HotCompanySafetyManager> managers = managerMapper.selectList(
                        Wrappers.<HotCompanySafetyManager>lambdaQuery()
                                .eq(HotCompanySafetyManager::getCompanyId, companyId)
                                .eq(HotCompanySafetyManager::getIsDeleted, 0L)
                                .eq(HotCompanySafetyManager::getIsResigned, 0L)
                                .eq(HotCompanySafetyManager::getStatus, 1L)
                );
                if (CollUtil.isNotEmpty(managers)) {
                    List<String> receiverIds = managers.stream().map(m -> String.valueOf(m.getId())).collect(Collectors.toList());
                    String name = StringUtils.blankToDefault(update.getName(), "该驾驶员");
                    HotSystemNotificationGroupBo bos = new HotSystemNotificationGroupBo();
                    bos.setLevel("普通");
                    bos.setContent("驾驶员【" + name + "】已经离职。");
                    bos.setSourceType("驾驶员管理");
                    bos.setSenderType("SYSTEM");
                    bos.setReceiverType("管理员");
                    bos.setReceiverIds(receiverIds);
                    bos.setIsDeleted(0L);
                    try {
                        notificationService.insertByBo(bos);
                    } catch (Exception e) {
                        log.warn("发送驾驶员离职通知失败 companyId={} driverId={}", companyId, driverId, e);
                    }
                }
            }
        }

        return flag;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public Boolean batchBindVehicles(HotDriverBatchBindVehicleBo bo) {
        HotDriver driver = baseMapper.selectById(bo.getDriverId());
        if (driver == null || Long.valueOf(1L).equals(driver.getIsDeleted())) {
            throw new ServiceException("驾驶员不存在");
        }
        Long companyId = driver.getCompanyId();
        if (companyId == null) {
            throw new ServiceException("驾驶员所属公司不能为空");
        }

        List<String> currentVehicleIds = getBoundVehicleIds(driver);
        List<String> targetVehicleIds = splitCsv(bo.getVehicleIds());
        List<HotVehicle> targetVehicles = new ArrayList<>();
        if (CollUtil.isNotEmpty(targetVehicleIds)) {
            targetVehicles = vehicleMapper.selectList(Wrappers.<HotVehicle>lambdaQuery()
                    .eq(HotVehicle::getCompanyId, companyId)
                    .in(HotVehicle::getId, targetVehicleIds)
                    .eq(HotVehicle::getIsDeleted, 0L));
            validateVehicleSelection(targetVehicleIds, targetVehicles, true);
        }

        validateVehiclesCanChangeBinding(currentVehicleIds, targetVehicles);

        Set<String> impactedDriverIds = new LinkedHashSet<>();
        impactedDriverIds.add(driver.getId());
        impactedDriverIds.addAll(findOtherDriversBoundToVehicles(companyId, currentVehicleIds, driver.getId()));
        impactedDriverIds.addAll(syncVehicleBindingsForDriver(driver.getId(), companyId, targetVehicles));
        syncDriverVehicleRelationsByDriverIds(companyId, impactedDriverIds);
        return true;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public Boolean appendBindVehicles(HotDriverBatchBindVehicleBo bo) {
        HotDriver driver = baseMapper.selectById(bo.getDriverId());
        if (driver == null || Long.valueOf(1L).equals(driver.getIsDeleted())) {
            throw new ServiceException("驾驶员不存在");
        }
        Long companyId = driver.getCompanyId();
        if (companyId == null) {
            throw new ServiceException("驾驶员所属公司不能为空");
        }

        List<String> currentVehicleIds = getBoundVehicleIds(driver);
        List<String> appendVehicleIds = splitCsv(bo.getVehicleIds());
        if (CollUtil.isEmpty(appendVehicleIds)) {
            return true;
        }

        List<HotVehicle> appendVehicles = vehicleMapper.selectList(Wrappers.<HotVehicle>lambdaQuery()
                .eq(HotVehicle::getCompanyId, companyId)
                .in(HotVehicle::getId, appendVehicleIds)
                .eq(HotVehicle::getIsDeleted, 0L));
        validateVehicleSelection(appendVehicleIds, appendVehicles, true);
        validateAppendVehiclesCanBind(appendVehicles, currentVehicleIds);

        Set<String> mergedVehicleIds = new LinkedHashSet<>(currentVehicleIds);
        mergedVehicleIds.addAll(appendVehicleIds);
        List<HotVehicle> targetVehicles = vehicleMapper.selectList(Wrappers.<HotVehicle>lambdaQuery()
                .eq(HotVehicle::getCompanyId, companyId)
                .in(HotVehicle::getId, mergedVehicleIds)
                .eq(HotVehicle::getIsDeleted, 0L));
        validateVehicleSelection(new ArrayList<>(mergedVehicleIds), targetVehicles, true);

        Set<String> impactedDriverIds = new LinkedHashSet<>();
        impactedDriverIds.add(driver.getId());
        impactedDriverIds.addAll(findOtherDriversBoundToVehicles(companyId, appendVehicleIds, driver.getId()));
        impactedDriverIds.addAll(syncVehicleBindingsForDriver(driver.getId(), companyId, targetVehicles));
        syncDriverVehicleRelationsByDriverIds(companyId, impactedDriverIds);
        return true;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public Boolean unbindVehicles(HotDriverBatchBindVehicleBo bo) {
        HotDriver driver = baseMapper.selectById(bo.getDriverId());
        if (driver == null || Long.valueOf(1L).equals(driver.getIsDeleted())) {
            throw new ServiceException("驾驶员不存在");
        }
        Long companyId = driver.getCompanyId();
        if (companyId == null) {
            throw new ServiceException("驾驶员所属公司不能为空");
        }

        List<String> currentVehicleIds = getBoundVehicleIds(driver);
        List<String> unbindVehicleIds = splitCsv(bo.getVehicleIds());
        if (CollUtil.isEmpty(currentVehicleIds)) {
            if (CollUtil.isNotEmpty(unbindVehicleIds)) {
                throw new ServiceException("该驾驶员当前无绑定车辆，不能解绑");
            }
            return true;
        }
        List<String> selectedUnbindVehicleIds = CollUtil.isEmpty(unbindVehicleIds)
                ? new ArrayList<>(currentVehicleIds)
                : new ArrayList<>(new LinkedHashSet<>(unbindVehicleIds));
        List<HotVehicle> selectedUnbindVehicles = new ArrayList<>();
        if (CollUtil.isNotEmpty(selectedUnbindVehicleIds)) {
            selectedUnbindVehicles = vehicleMapper.selectList(Wrappers.<HotVehicle>lambdaQuery()
                    .eq(HotVehicle::getCompanyId, companyId)
                    .in(HotVehicle::getId, selectedUnbindVehicleIds)
                    .eq(HotVehicle::getIsDeleted, 0L));
            validateVehicleSelection(selectedUnbindVehicleIds, selectedUnbindVehicles, true);
            validateVehiclesBelongToDriverForUnbind(driver.getId(), currentVehicleIds, selectedUnbindVehicles);
            validateVehiclesCanUnbind(selectedUnbindVehicles);
        }

        Set<String> remainingVehicleIds = new LinkedHashSet<>(currentVehicleIds);
        if (CollUtil.isEmpty(selectedUnbindVehicleIds)) {
            remainingVehicleIds.clear();
        } else {
            remainingVehicleIds.removeAll(selectedUnbindVehicleIds);
        }

        List<HotVehicle> targetVehicles = new ArrayList<>();
        if (CollUtil.isNotEmpty(remainingVehicleIds)) {
            targetVehicles = vehicleMapper.selectList(Wrappers.<HotVehicle>lambdaQuery()
                    .eq(HotVehicle::getCompanyId, companyId)
                    .in(HotVehicle::getId, remainingVehicleIds)
                    .eq(HotVehicle::getIsDeleted, 0L));
            validateVehicleSelection(new ArrayList<>(remainingVehicleIds), targetVehicles, true);
        }

        Set<String> impactedDriverIds = new LinkedHashSet<>();
        impactedDriverIds.add(driver.getId());
        impactedDriverIds.addAll(syncVehicleBindingsForDriver(driver.getId(), companyId, targetVehicles));
        syncDriverVehicleRelationsByDriverIds(companyId, impactedDriverIds);
        return true;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public Boolean switchVehicle(HotDriverSwitchVehicleBo bo) {
        HotDriver driver = DriverLoginContextHelper.getCurrentDriver();
        if (driver == null || Long.valueOf(1L).equals(driver.getIsDeleted())) {
            throw new ServiceException("驾驶员不存在");
        }
        if (driver.getCompanyId() == null) {
            throw new ServiceException("驾驶员所属公司不能为空");
        }

        String targetVehicleId = StringUtils.trimToNull(bo.getVehicleId());
        if (StringUtils.isBlank(targetVehicleId)) {
            throw new ServiceException("目标车辆ID不能为空");
        }

        if (StringUtils.equals(driver.getVehicleId(), targetVehicleId)) {
            return true;
        }
        if (StringUtils.isNotBlank(driver.getVehicleId())) {
            hotVehicleThreeInspectService.validateNoUnfinishedSwitchVehicleProcess(driver.getVehicleId(),
                    "请先完成'" + StringUtils.defaultIfBlank(driver.getPlateNumber(), "当前车辆") + "'的车辆三检");
        }

        HotVehicle targetVehicle = vehicleMapper.selectOne(Wrappers.<HotVehicle>lambdaQuery()
                .eq(HotVehicle::getId, targetVehicleId)
                .eq(HotVehicle::getCompanyId, driver.getCompanyId())
                .eq(HotVehicle::getIsDeleted, 0L)
                .last("limit 1"));
        if (targetVehicle == null) {
            throw new ServiceException("目标车辆不存在");
        }

        return baseMapper.update(null, new LambdaUpdateWrapper<HotDriver>()
                .set(HotDriver::getVehicleId, targetVehicle.getId())
                .set(HotDriver::getPlateNumber, targetVehicle.getPlateNumber())
                .eq(HotDriver::getId, driver.getId())
                .eq(HotDriver::getCompanyId, driver.getCompanyId())) > 0;
    }

    /**
     * 移除用户在特定企业的司机端登录权限
     */
    private void removeDriverPortFromUser(String phone, Long companyId) {
        if (StringUtils.isBlank(phone) || companyId == null) {
            return;
        }
        SysUserVo user = sysUserService.selectUserByPhonenumber(phone);
        if (user != null) {
            sysUserLoginPortService.remove(new LambdaQueryWrapper<SysUserLoginPort>()
                    .eq(SysUserLoginPort::getUserId, user.getUserId())
                    .eq(SysUserLoginPort::getCompanyId, companyId)
                    .eq(SysUserLoginPort::getLoginPort, ISysUserLoginPortService.DRIVER_PORT));
        }
    }

    /**
     * 保存前的数据校验
     */
    private void validEntityBeforeSave(HotDriver entity) {
        if (StringUtils.isBlank(entity.getIdCardNo())) {
            return;
        }
        LambdaQueryWrapper<HotDriver> wrapper = Wrappers.lambdaQuery();
        wrapper.eq(HotDriver::getIdCardNo, entity.getIdCardNo())
                .eq(HotDriver::getIsDeleted, 0L)
                .ne(StringUtils.isNotBlank(entity.getId()), HotDriver::getId, entity.getId())
                .last("limit 1");
        HotDriver existsDriver = baseMapper.selectOne(wrapper);
        if (existsDriver != null) {
            if (existsDriver.getCompanyId() != null
                    && entity.getCompanyId() != null
                    && !Objects.equals(existsDriver.getCompanyId(), entity.getCompanyId())) {
                throw new ServiceException("同一身份证号的驾驶员不能存在于不同企业");
            }
            throw new ServiceException("身份证号已被录入");
        }
    }

    /**
     * 校验并批量删除驾驶员基本信息信息
     *
     * @param ids     待删除的主键集合
     * @param isValid 是否进行有效性校验
     * @return 是否删除成功
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public Boolean deleteWithValidByIds(Collection<Long> ids, Boolean isValid) {
        if (isValid) {
            //TODO 做一些业务上的校验,判断是否需要校验
        }
        if (CollUtil.isNotEmpty(ids)) {
            List<String> driverIds = ids.stream().map(String::valueOf).collect(Collectors.toList());

            // 删除奖惩记录
            rewardPunishmentMapper.delete(Wrappers.<HotDriverRewardPunishment>lambdaQuery()
                    .in(HotDriverRewardPunishment::getDriverId, driverIds));

            // 删除技能考核
            skillAssessmentMapper.delete(Wrappers.<HotDriverSkillAssessment>lambdaQuery()
                    .in(HotDriverSkillAssessment::getDriverId, driverIds));

            // 删除年度考核
            annualAssessmentMapper.delete(Wrappers.<HotDriverAnnualAssessment>lambdaQuery()
                    .in(HotDriverAnnualAssessment::getDriverId, driverIds));
        }
        return baseMapper.deleteByIds(ids) > 0;
    }

    @Override
    public java.util.List<com.hotwj.platform.driverManagement.driver.domain.vo.HotDriverCategoryStatVo> queryDriverCategoryStat(Long companyId) {
        return driverMapper.selectDriverCategoryStat(companyId);
    }


    /**
     * 校验手机号唯一性
     *
     * @param phone           手机号
     * @param excludeDriverId 排除的驾驶员ID（用于编辑时）
     */
    private void checkPhoneUnique(String phone, String excludeDriverId) {
        if (StringUtils.isBlank(phone)) {
            return;
        }
        LambdaQueryWrapper<HotDriver> wrapper = new LambdaQueryWrapper<>();
        wrapper.eq(HotDriver::getPhone, phone)
                .eq(HotDriver::getIsDeleted, 0); // 仅校验未删除的

        if (StringUtils.isNotBlank(excludeDriverId)) {
            wrapper.ne(HotDriver::getId, excludeDriverId);
        }

        long count = baseMapper.selectCount(wrapper);
        if (count > 0) {
            throw new ServiceException("该手机号已存在，请检查！");
        }
    }

    private List<HotVehicle> resolveDriverTargetVehicles(HotDriverBo bo, Long companyId) {
        List<String> vehicleIds = splitCsv(bo.getVehicleIds());
        if (CollUtil.isEmpty(vehicleIds)) {
            vehicleIds = splitCsv(bo.getVehicleId());
        }
        if (CollUtil.isNotEmpty(vehicleIds)) {
            List<HotVehicle> vehicles = vehicleMapper.selectList(Wrappers.<HotVehicle>lambdaQuery()
                    .eq(HotVehicle::getCompanyId, companyId)
                    .in(HotVehicle::getId, vehicleIds)
                    .eq(HotVehicle::getIsDeleted, 0L));
            validateVehicleSelection(vehicleIds, vehicles, true);
            return vehicles;
        }

        List<String> plateNumbers = splitCsv(bo.getPlateNumber());
        if (CollUtil.isEmpty(plateNumbers)) {
            return new ArrayList<>();
        }
        List<HotVehicle> vehicles = vehicleMapper.selectList(Wrappers.<HotVehicle>lambdaQuery()
                .eq(HotVehicle::getCompanyId, companyId)
                .in(HotVehicle::getPlateNumber, plateNumbers)
                .eq(HotVehicle::getIsDeleted, 0L));
        validateVehicleSelection(plateNumbers, vehicles, false);
        return vehicles;
    }

    private void validateVehicleSelection(List<String> expectedValues, List<HotVehicle> vehicles, boolean useVehicleId) {
        Set<String> actualValues = vehicles.stream()
                .map(vehicle -> useVehicleId ? vehicle.getId() : vehicle.getPlateNumber())
                .filter(StringUtils::isNotBlank)
                .collect(Collectors.toSet());
        List<String> missingValues = expectedValues.stream()
                .filter(value -> !actualValues.contains(value))
                .collect(Collectors.toList());
        if (CollUtil.isNotEmpty(missingValues)) {
            throw new ServiceException(useVehicleId
                    ? "存在未找到的车辆ID：" + String.join(",", missingValues)
                    : "存在未找到的车牌号：" + String.join(",", missingValues));
        }
    }

    private void validateVehiclesCanChangeBinding(Collection<String> currentVehicleIds, Collection<HotVehicle> targetVehicles) {
        Set<String> currentIds = new LinkedHashSet<>();
        if (CollUtil.isNotEmpty(currentVehicleIds)) {
            currentIds.addAll(currentVehicleIds);
        }
        Set<String> targetIds = new LinkedHashSet<>();
        if (CollUtil.isNotEmpty(targetVehicles)) {
            targetIds.addAll(targetVehicles.stream()
                    .map(HotVehicle::getId)
                    .filter(StringUtils::isNotBlank)
                    .toList());
        }
        if (currentIds.equals(targetIds)) {
            return;
        }
        Set<String> relatedVehicleIds = new LinkedHashSet<>(currentIds);
        relatedVehicleIds.addAll(targetIds);
        for (String vehicleId : relatedVehicleIds) {
            hotVehicleThreeInspectService.validateNoUnfinishedProcess(vehicleId, "当前车辆三检流程未完成，不可进行换绑操作");
        }
    }

    private void validateAppendVehiclesCanBind(Collection<HotVehicle> appendVehicles, Collection<String> currentVehicleIds) {
        Set<String> currentIds = new LinkedHashSet<>();
        if (CollUtil.isNotEmpty(currentVehicleIds)) {
            currentIds.addAll(currentVehicleIds);
        }
        if (CollUtil.isEmpty(appendVehicles)) {
            return;
        }
        for (HotVehicle vehicle : appendVehicles) {
            if (vehicle == null || StringUtils.isBlank(vehicle.getId()) || currentIds.contains(vehicle.getId())) {
                continue;
            }
            hotVehicleThreeInspectService.validateNoUnfinishedProcess(vehicle.getId(), "当前车辆三检流程未完成，不可进行换绑操作");
        }
    }

    private void validateVehiclesBelongToDriverForUnbind(String driverId,
                                                         Collection<String> currentVehicleIds,
                                                         Collection<HotVehicle> vehicles) {
        Set<String> currentIds = new LinkedHashSet<>();
        if (CollUtil.isNotEmpty(currentVehicleIds)) {
            currentIds.addAll(currentVehicleIds);
        }
        List<String> invalidVehicleIds = new ArrayList<>();
        for (HotVehicle vehicle : vehicles) {
            if (vehicle == null || StringUtils.isBlank(vehicle.getId())) {
                continue;
            }
            boolean existsInDriverBinding = currentIds.contains(vehicle.getId());
            boolean existsInVehicleBinding = splitCsv(vehicle.getCurrentDriver()).contains(driverId);
            if (!existsInDriverBinding || !existsInVehicleBinding) {
                invalidVehicleIds.add(vehicle.getId());
            }
        }
        if (CollUtil.isNotEmpty(invalidVehicleIds)) {
            throw new ServiceException("存在未绑定到该驾驶员的车辆，不能解绑：" + String.join(",", invalidVehicleIds));
        }
    }

    private void validateVehiclesCanUnbind(Collection<HotVehicle> vehicles) {
        if (CollUtil.isEmpty(vehicles)) {
            return;
        }
        for (HotVehicle vehicle : vehicles) {
            if (vehicle == null || StringUtils.isBlank(vehicle.getId())) {
                continue;
            }
            hotVehicleThreeInspectService.validateNoUnfinishedProcess(vehicle.getId(), "当前车辆三检流程未完成，不可解除绑定操作");
        }
    }

    private Set<String> syncVehicleBindingsForDriver(String driverId, Long companyId, List<HotVehicle> targetVehicles) {
        Set<String> impactedDriverIds = new LinkedHashSet<>();
        impactedDriverIds.add(driverId);
        if (StringUtils.isBlank(driverId) || companyId == null) {
            return impactedDriverIds;
        }

        Set<String> targetVehicleIds = targetVehicles.stream()
                .map(HotVehicle::getId)
                .filter(StringUtils::isNotBlank)
                .collect(Collectors.toCollection(LinkedHashSet::new));
        List<HotVehicle> companyVehicles = vehicleMapper.selectList(Wrappers.<HotVehicle>lambdaQuery()
                .eq(HotVehicle::getCompanyId, companyId)
                .eq(HotVehicle::getIsDeleted, 0L));

        for (HotVehicle vehicle : companyVehicles) {
            List<String> currentDrivers = splitCsv(vehicle.getCurrentDriver());
            boolean currentlyBoundToDriver = currentDrivers.contains(driverId);
            boolean shouldBindToDriver = targetVehicleIds.contains(vehicle.getId());

            if (!currentlyBoundToDriver && !shouldBindToDriver) {
                continue;
            }

            if (shouldBindToDriver) {
                impactedDriverIds.addAll(currentDrivers);
                if (!currentlyBoundToDriver || currentDrivers.size() != 1) {
                    vehicleMapper.update(null, new LambdaUpdateWrapper<HotVehicle>()
                            .set(HotVehicle::getCurrentDriver, driverId)
                            .eq(HotVehicle::getId, vehicle.getId())
                            .eq(HotVehicle::getCompanyId, companyId));
                }
                continue;
            }

            List<String> remainingDrivers = new ArrayList<>(currentDrivers);
            remainingDrivers.removeIf(driverId::equals);
            impactedDriverIds.addAll(remainingDrivers);
            vehicleMapper.update(null, new LambdaUpdateWrapper<HotVehicle>()
                    .set(HotVehicle::getCurrentDriver, normalizeSingleBindingValue(remainingDrivers))
                    .eq(HotVehicle::getId, vehicle.getId())
                    .eq(HotVehicle::getCompanyId, companyId));
        }
        return impactedDriverIds;
    }

    private Set<String> findOtherDriversBoundToVehicles(Long companyId, Collection<String> vehicleIds, String excludeDriverId) {
        Set<String> driverIds = new LinkedHashSet<>();
        if (companyId == null || CollUtil.isEmpty(vehicleIds)) {
            return driverIds;
        }
        List<HotVehicle> vehicles = vehicleMapper.selectList(Wrappers.<HotVehicle>lambdaQuery()
                .eq(HotVehicle::getCompanyId, companyId)
                .in(HotVehicle::getId, vehicleIds)
                .eq(HotVehicle::getIsDeleted, 0L));
        for (HotVehicle vehicle : vehicles) {
            for (String driverId : splitCsv(vehicle.getCurrentDriver())) {
                if (!StringUtils.equals(driverId, excludeDriverId)) {
                    driverIds.add(driverId);
                }
            }
        }
        return driverIds;
    }

    private void syncDriverVehicleRelationsByDriverIds(Long companyId, Collection<String> driverIds) {
        if (companyId == null || CollUtil.isEmpty(driverIds)) {
            return;
        }
        List<HotVehicle> vehicles = vehicleMapper.selectList(Wrappers.<HotVehicle>lambdaQuery()
                .eq(HotVehicle::getCompanyId, companyId)
                .eq(HotVehicle::getIsDeleted, 0L));
        for (String driverId : driverIds) {
            if (StringUtils.isBlank(driverId)) {
                continue;
            }
            List<String> vehicleIds = new ArrayList<>();
            List<HotVehicle> boundVehicles = new ArrayList<>();
            for (HotVehicle vehicle : vehicles) {
                if (!splitCsv(vehicle.getCurrentDriver()).contains(driverId)) {
                    continue;
                }
                boundVehicles.add(vehicle);
                vehicleIds.add(vehicle.getId());
            }
            HotDriver driver = baseMapper.selectById(driverId);
            String primaryVehicleId = resolvePrimaryVehicleId(driver, vehicleIds);
            String primaryPlateNumber = resolvePrimaryPlateNumber(primaryVehicleId, boundVehicles);
            driverMapper.update(null, new LambdaUpdateWrapper<HotDriver>()
                    .set(HotDriver::getVehicleId, primaryVehicleId)
                    .set(HotDriver::getVehicleIds, joinCsv(vehicleIds))
                    .set(HotDriver::getPlateNumber, primaryPlateNumber)
                    .eq(HotDriver::getId, driverId)
                    .eq(HotDriver::getCompanyId, companyId));
        }
    }

    private List<String> getBoundVehicleIds(HotDriver driver) {
        if (driver == null) {
            return new ArrayList<>();
        }
        List<String> vehicleIds = splitCsv(driver.getVehicleIds());
        if (CollUtil.isNotEmpty(vehicleIds)) {
            return vehicleIds;
        }
        return splitCsv(driver.getVehicleId());
    }

    private String resolvePrimaryVehicleId(HotDriver driver, Collection<String> boundVehicleIds) {
        if (CollUtil.isEmpty(boundVehicleIds)) {
            return null;
        }
        if (driver != null && StringUtils.isNotBlank(driver.getVehicleId()) && boundVehicleIds.contains(driver.getVehicleId())) {
            return driver.getVehicleId();
        }
        return boundVehicleIds.stream()
                .filter(StringUtils::isNotBlank)
                .findFirst()
                .orElse(null);
    }

    private String resolvePrimaryPlateNumber(String primaryVehicleId, Collection<HotVehicle> boundVehicles) {
        if (StringUtils.isBlank(primaryVehicleId) || CollUtil.isEmpty(boundVehicles)) {
            return null;
        }
        return boundVehicles.stream()
                .filter(vehicle -> StringUtils.equals(primaryVehicleId, vehicle.getId()))
                .map(HotVehicle::getPlateNumber)
                .filter(StringUtils::isNotBlank)
                .findFirst()
                .orElse(null);
    }

    private List<String> splitCsv(String value) {
        if (StringUtils.isBlank(value)) {
            return new ArrayList<>();
        }
        return Arrays.stream(value.split(","))
                .map(String::trim)
                .filter(StringUtils::isNotBlank)
                .distinct()
                .collect(Collectors.toList());
    }

    private String joinCsv(Collection<String> values) {
        if (CollUtil.isEmpty(values)) {
            return null;
        }
        return values.stream()
                .filter(StringUtils::isNotBlank)
                .distinct()
                .collect(Collectors.joining(","));
    }

    private String normalizeNullableText(String value) {
        if (value == null) {
            return null;
        }
        String trimmed = value.trim();
        return trimmed.isEmpty() ? null : trimmed;
    }

    private String normalizeSingleBindingValue(Collection<String> values) {
        if (CollUtil.isEmpty(values)) {
            return null;
        }
        return values.stream()
                .filter(StringUtils::isNotBlank)
                .findFirst()
                .orElse(null);
    }

    /**
     * 保存驾驶员家庭成员
     */
    private void insertDriverFamilyMembers(HotDriverBo bo, String driverId) {
        if (CollUtil.isNotEmpty(bo.getDriverFamilyMemberList())) {
            List<HotDriverFamilyMember> members = MapstructUtils.convert(bo.getDriverFamilyMemberList(), HotDriverFamilyMember.class);
            for (HotDriverFamilyMember m : members) {
                m.setId(IdWorker.getId());
                m.setDriverId(driverId);
                m.setCompanyId(bo.getCompanyId());
                m.setIsDeleted(0L);
                driverFamilyMemberMapper.insert(m);
            }
        }
    }

    private void insertDriverWorkExperiences(HotDriverBo bo, String driverId) {
        if (CollUtil.isNotEmpty(bo.getDriverWorkExperienceList())) {
            List<HotDriverWorkExperience> works = MapstructUtils.convert(bo.getDriverWorkExperienceList(), HotDriverWorkExperience.class);
            for (HotDriverWorkExperience w : works) {
                w.setId(IdWorker.getId());
                w.setDriverId(driverId);
                w.setCompanyId(bo.getCompanyId());
                w.setIsDeleted(0L);
                driverWorkExperienceMapper.insert(w);
            }
        }
    }

    private void insertDriverLaborContracts(HotDriverBo bo, String driverId) {
        if (CollUtil.isNotEmpty(bo.getDriverLaborContractList())) {
            List<HotDriverLaborContract> labors = MapstructUtils.convert(bo.getDriverLaborContractList(), HotDriverLaborContract.class);
            for (HotDriverLaborContract c : labors) {
                c.setId(IdWorker.getId());
                c.setDriverId(driverId);
                c.setCompanyId(bo.getCompanyId());
                c.setIsDeleted(0L);
                driverLaborContractMapper.insert(c);
            }
        }
    }

    private void insertDriverHealthReports(HotDriverBo bo, String driverId) {
        if (CollUtil.isNotEmpty(bo.getDriverHealthReportList())) {
            List<HotDriverHealthReport> reports = MapstructUtils.convert(bo.getDriverHealthReportList(), HotDriverHealthReport.class);
            for (HotDriverHealthReport r : reports) {
                r.setId(IdWorker.getId());
                r.setDriverId(driverId);
                r.setCompanyId(bo.getCompanyId());
                r.setIsDeleted(0L);
                driverHealthReportMapper.insert(r);
            }
        }
    }

    /**
     * 处理驾驶员离职或审核未通过
     * 1. 人员分组也要将该驾驶员删除
     */
    private void handleDriverResignation(String driverId, String phone, Long companyId) {
        if (StringUtils.isBlank(driverId) || companyId == null) {
            return;
        }

        Set<String> impactedDriverIds = new LinkedHashSet<>();
        impactedDriverIds.add(driverId);
        List<HotVehicle> vehicles = vehicleMapper.selectList(Wrappers.<HotVehicle>lambdaQuery()
                .eq(HotVehicle::getCompanyId, companyId)
                .eq(HotVehicle::getIsDeleted, 0L));
        for (HotVehicle vehicle : vehicles) {
            List<String> driverIds = splitCsv(vehicle.getCurrentDriver());
            if (!driverIds.contains(driverId)) {
                continue;
            }
            driverIds.removeIf(driverId::equals);
            impactedDriverIds.addAll(driverIds);
            vehicleMapper.update(null, new LambdaUpdateWrapper<HotVehicle>()
                    .set(HotVehicle::getCurrentDriver, normalizeSingleBindingValue(driverIds))
                    .eq(HotVehicle::getId, vehicle.getId())
                    .eq(HotVehicle::getCompanyId, companyId));
        }
        syncDriverVehicleRelationsByDriverIds(companyId, impactedDriverIds);

        // 2. 将该驾驶员从所有组中移除
        // 查找包含该驾驶员的所有组
        List<HotDriverGroup> groups = groupMapper.selectList(
                new LambdaQueryWrapper<HotDriverGroup>()
                        .eq(HotDriverGroup::getCompanyId, companyId)
                        .like(HotDriverGroup::getMemberIds, driverId)
                        .eq(HotDriverGroup::getIsDeleted, 0L)
        );

        if (CollUtil.isNotEmpty(groups)) {
            for (HotDriverGroup group : groups) {
                String memberIds = group.getMemberIds();
                if (StringUtils.isBlank(memberIds)) {
                    continue;
                }

                List<String> memberList = new ArrayList<>(Arrays.asList(memberIds.split(",")));
                // 确保移除的是当前驾驶员ID
                boolean removed = false;
                while (memberList.remove(driverId)) {
                    removed = true;
                }

                if (removed) {
                    String newMemberIds = String.join(",", memberList);
                    // 只更新memberIds字段
                    groupMapper.update(null,
                            new LambdaUpdateWrapper<HotDriverGroup>()
                                    .set(HotDriverGroup::getMemberIds, newMemberIds)
                                    .eq(HotDriverGroup::getId, group.getId())
                    );
                }
            }
        }
    }
}
