package com.hotwj.platform.config.vehicleThreeInspect.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.fasterxml.jackson.core.type.TypeReference;
import com.hotwj.platform.common.helper.DriverLoginContextHelper;
import com.hotwj.platform.config.vehicleThreeInspect.domain.HotVehicleThreeInspect;
import com.hotwj.platform.config.vehicleThreeInspect.domain.bo.HotVehicleThreeInspectBatchAuditBo;
import com.hotwj.platform.config.vehicleThreeInspect.domain.bo.HotVehicleThreeInspectBo;
import com.hotwj.platform.config.vehicleThreeInspect.domain.bo.HotVehicleThreeInspectVehicleQueryBo;
import com.hotwj.platform.config.vehicleThreeInspect.domain.vo.HotVehicleThreeInspectProcessVo;
import com.hotwj.platform.config.vehicleThreeInspect.domain.vo.HotVehicleThreeInspectReceivedVehicleVo;
import com.hotwj.platform.config.vehicleThreeInspect.domain.vo.HotVehicleThreeInspectUnreceivedVehicleVo;
import com.hotwj.platform.config.vehicleThreeInspect.domain.vo.HotVehicleThreeInspectVo;
import com.hotwj.platform.config.vehicleThreeInspectConfig.domain.HotVehicleThreeInspectConfig;
import com.hotwj.platform.config.vehicleThreeInspectConfig.mapper.HotVehicleThreeInspectConfigMapper;
import com.hotwj.platform.config.vehicleThreeInspect.mapper.HotVehicleThreeInspectMapper;
import com.hotwj.platform.config.vehicleThreeInspect.service.IHotVehicleThreeInspectService;
import com.hotwj.platform.flow.service.ISysFlowService;
import com.hotwj.platform.integration.ocr.SignatureVerifyService;
import com.hotwj.platform.noticeManagerment.systemNotification.domain.bo.HotSystemNotificationGroupBo;
import com.hotwj.platform.noticeManagerment.systemNotification.service.IHotSystemNotificationService;
import com.hotwj.platform.resourceManagement.vehicleManagement.domain.HotVehicle;
import com.hotwj.platform.resourceManagement.vehicleManagement.domain.vo.HotVehicleVo;
import com.hotwj.platform.resourceManagement.vehicleManagement.mapper.HotVehicleMapper;
import com.hotwj.platform.securityManagement.hiddenDanger.mapper.HotHiddenDangerMapper;
import com.hotwj.platform.securityManagement.vehicleInoutCheck.domain.HotVehicleInoutCheck;
import com.hotwj.platform.securityManagement.vehicleInoutCheck.mapper.HotVehicleInoutCheckMapper;
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.json.utils.JsonUtils;
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.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.Collections;
import java.util.Collection;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Objects;

/**
 * 车辆三检Service业务层处理
 *
 * @author shihongwei
 * @date 2025-12-29
 */
@Slf4j
@RequiredArgsConstructor
@Service
public class HotVehicleThreeInspectServiceImpl implements IHotVehicleThreeInspectService {

    private final HotVehicleThreeInspectMapper baseMapper;
    private final HotVehicleMapper hotVehicleMapper;
    private final HotHiddenDangerMapper hotHiddenDangerMapper;
    private final HotVehicleInoutCheckMapper hotVehicleInoutCheckMapper;
    private final ISysFlowService flowService;
    private final IHotSystemNotificationService notificationService;
    private final SignatureVerifyService signatureVerifyService;
    private final HotVehicleThreeInspectConfigMapper hotVehicleThreeInspectConfigMapper;

    /**
     * 查询可进行三检的车辆列表（无历史记录或上一轮已完结）
     *
     * @param companyId 公司ID
     * @return 车辆列表
     */
    @Override
    public List<HotVehicleVo> queryAvailableVehicles(Long companyId) {
        return hotVehicleMapper.selectAvailableForThreeInspect(companyId);
    }

    @Override
    public List<HotVehicleThreeInspectUnreceivedVehicleVo> queryUnreceivedVehicles(HotVehicleThreeInspectVehicleQueryBo bo) {
        return baseMapper.queryUnreceivedVehicles(bo);
    }

    @Override
    public List<HotVehicleThreeInspectReceivedVehicleVo> queryReceivedVehicles(HotVehicleThreeInspectVehicleQueryBo bo) {
        return baseMapper.queryReceivedVehicles(bo);
    }

    @Override
    public boolean hasUnfinishedProcess(String vehicleId) {
        Long parsedVehicleId = parseVehicleId(vehicleId);
        if (parsedVehicleId == null) {
            return false;
        }
        HotVehicleThreeInspect latestInspect = selectLatestInspect(parsedVehicleId);
        if (latestInspect == null) {
            return false;
        }
        boolean finishedPhase = Long.valueOf(3L).equals(latestInspect.getInspectPhase());
        boolean finishedFlow = "APPROVED".equals(latestInspect.getFlowStatus())
                || "REJECTED".equals(latestInspect.getFlowStatus());
        return !(finishedPhase && finishedFlow);
    }

    @Override
    public void validateNoUnfinishedProcess(String vehicleId, String actionMessage) {
        if (hasUnfinishedProcess(vehicleId)) {
            throw new ServiceException(actionMessage);
        }
    }

    @Override
    public void validateNoUnfinishedSwitchVehicleProcess(String vehicleId, String actionMessage) {
        Long parsedVehicleId = parseVehicleId(vehicleId);
        if (parsedVehicleId == null) {
            return;
        }
        HotVehicleThreeInspect latestInspect = selectLatestInspect(parsedVehicleId);
        if (latestInspect == null) {
            return;
        }
        if (!Long.valueOf(3L).equals(latestInspect.getInspectPhase())) {
            throw new ServiceException(actionMessage);
        }
    }

    @Override
    public boolean checkSelectableVehicle(String driverId, String vehicleId) {
        String trimmedDriverId = StringUtils.trimToNull(driverId);
        String trimmedVehicleId = StringUtils.trimToNull(vehicleId);
        if (StringUtils.isBlank(trimmedDriverId)) {
            throw new ServiceException("驾驶员ID不能为空");
        }
        Long parsedVehicleId = parseVehicleId(trimmedVehicleId);
        if (parsedVehicleId == null) {
            return true;
        }
        HotVehicleThreeInspect latestInspect = selectLatestInspect(parsedVehicleId);
        if (latestInspect == null || Objects.equals(latestInspect.getInspectPhase(), 3L)) {
            return true;
        }
        if (StringUtils.equals(trimmedDriverId, StringUtils.trimToEmpty(latestInspect.getDriverId()))) {
            return true;
        }
        throw new ServiceException(buildVehicleOccupiedMessage(parsedVehicleId));
    }

    /**
     * 查询车辆三检
     *
     * @param id 主键
     * @return 车辆三检
     */
    @Override
    public HotVehicleThreeInspectVo queryById(Long id) {
        HotVehicleThreeInspectVo vo = baseMapper.selectVoById(id);
        if (vo != null && StringUtils.isNotBlank(vo.getInstanceId())) {
            String userId = LoginHelper.getBusinessUserId();
            vo.setTaskId(flowService.getTaskId(vo.getInstanceId(), userId));
        }
        return vo;
    }

    /**
     * 分页查询车辆三检列表
     *
     * @param bo        查询条件
     * @param pageQuery 分页参数
     * @return 车辆三检分页列表
     */
    @Override
    public TableDataInfo<HotVehicleThreeInspectVo> queryPageList(HotVehicleThreeInspectBo bo, PageQuery pageQuery) {
        LambdaQueryWrapper<HotVehicleThreeInspect> lqw = buildQueryWrapper(bo);
        Page<HotVehicleThreeInspectVo> result = baseMapper.selectVoPage(pageQuery.build(), lqw);
        // 填充taskId
        String businessUserId = LoginHelper.getBusinessUserId();
        for (HotVehicleThreeInspectVo vo : result.getRecords()) {
            if (StringUtils.isNotBlank(vo.getInstanceId())) {
                String taskId = flowService.getTaskId(vo.getInstanceId(), businessUserId);
                vo.setTaskId(taskId);
            }
        }
        return TableDataInfo.build(result);
    }

    /**
     * 分页查询车辆三检流程列表
     *
     * @param bo        查询条件
     * @param pageQuery 分页参数
     * @return 车辆三检流程分页列表
     */
    @Override
    public TableDataInfo<HotVehicleThreeInspectProcessVo> queryProcessPageList(HotVehicleThreeInspectBo bo, PageQuery pageQuery) {
        Page<HotVehicleThreeInspectProcessVo> result = baseMapper.queryProcessPageList(pageQuery.build(), bo);
        return TableDataInfo.build(result);
    }

    /**
     * 查询符合条件的车辆三检列表
     *
     * @param bo 查询条件
     * @return 车辆三检列表
     */
    @Override
    public List<HotVehicleThreeInspectVo> queryList(HotVehicleThreeInspectBo bo) {
        LambdaQueryWrapper<HotVehicleThreeInspect> lqw = buildQueryWrapper(bo);
        return baseMapper.selectVoList(lqw);
    }

    private LambdaQueryWrapper<HotVehicleThreeInspect> buildQueryWrapper(HotVehicleThreeInspectBo bo) {
        Map<String, Object> params = bo.getParams();
        LambdaQueryWrapper<HotVehicleThreeInspect> lqw = Wrappers.lambdaQuery();
        lqw.orderByDesc(HotVehicleThreeInspect::getCreateTime);
        Object beginTime = params == null ? null : params.get("beginTime");
        Object endTime = params == null ? null : params.get("endTime");
        if (beginTime != null && endTime != null) {
            lqw.apply(
                    "EXISTS (SELECT 1 FROM hot_vehicle_three_inspect t2 " +
                            "WHERE t2.inspect_id = hot_vehicle_three_inspect.inspect_id " +
                            "AND t2.inspect_time BETWEEN {0} AND {1})",
                    beginTime,
                    endTime
            );
        } else if (beginTime != null) {
            lqw.apply(
                    "EXISTS (SELECT 1 FROM hot_vehicle_three_inspect t2 " +
                            "WHERE t2.inspect_id = hot_vehicle_three_inspect.inspect_id " +
                            "AND t2.inspect_time >= {0})",
                    beginTime
            );
        } else if (endTime != null) {
            lqw.apply(
                    "EXISTS (SELECT 1 FROM hot_vehicle_three_inspect t2 " +
                            "WHERE t2.inspect_id = hot_vehicle_three_inspect.inspect_id " +
                            "AND t2.inspect_time <= {0})",
                    endTime
            );
        }
        lqw.eq(bo.getCompanyId() != null, HotVehicleThreeInspect::getCompanyId, bo.getCompanyId());
        lqw.eq(bo.getVehicleId() != null, HotVehicleThreeInspect::getVehicleId, bo.getVehicleId());
        lqw.eq(bo.getDriverId() != null, HotVehicleThreeInspect::getDriverId, bo.getDriverId());
        lqw.like(StringUtils.isNotBlank(bo.getDriverName()), HotVehicleThreeInspect::getDriverName, bo.getDriverName());
        lqw.eq(bo.getInspectPhase() != null, HotVehicleThreeInspect::getInspectPhase, bo.getInspectPhase());
        lqw.eq(bo.getInspectTime() != null, HotVehicleThreeInspect::getInspectTime, bo.getInspectTime());
        lqw.eq(bo.getInspectId() != null, HotVehicleThreeInspect::getInspectId, bo.getInspectId());
        lqw.eq(bo.getAuditorId() != null, HotVehicleThreeInspect::getAuditorId, bo.getAuditorId());
        lqw.like(StringUtils.isNotBlank(bo.getAuditorName()), HotVehicleThreeInspect::getAuditorName, bo.getAuditorName());
        lqw.eq(StringUtils.isNotBlank(bo.getInspectResultJson()), HotVehicleThreeInspect::getInspectResultJson, bo.getInspectResultJson());
        lqw.eq(StringUtils.isNotBlank(bo.getAttachImgUrl()), HotVehicleThreeInspect::getAttachImgUrl, bo.getAttachImgUrl());
        lqw.eq(StringUtils.isNotBlank(bo.getInspectorSignImgUrl()), HotVehicleThreeInspect::getInspectorSignImgUrl, bo.getInspectorSignImgUrl());
        lqw.eq(bo.getIsDeleted() != null, HotVehicleThreeInspect::getIsDeleted, bo.getIsDeleted());
        return lqw;
    }

    /**
     * 新增车辆三检
     *
     * @param bo 车辆三检
     * @return 是否新增成功
     */
    @Override
    public Boolean insertByBo(HotVehicleThreeInspectBo bo) {
        validateAttachImgUrlRequiredWhenAbnormal(bo);
        HotVehicleThreeInspect add = MapstructUtils.convert(bo, HotVehicleThreeInspect.class);
        validEntityBeforeSave(add);

        if (DriverLoginContextHelper.isDriverPort() && StringUtils.isNotBlank(bo.getInspectorSignImgUrl())) {
            validateInspectorSignatureByPhase(bo);
        }

        // 校验该车辆三检流程逻辑
        if (add.getVehicleId() != null) {
            Long currentPhase = add.getInspectPhase();
            // 获取该车辆最近的一条三检记录
            HotVehicleThreeInspect last = selectLatestInspect(add.getVehicleId());
            validateOutboundVehicleDriver(add, last);

            if (last != null) {
                Long lastPhase = last.getInspectPhase();
                // 1. 如果上一条是收车检查(第3阶段)，则本次必须是新一轮的出车检查(第1阶段)
                if (lastPhase == 3) {
                    if (currentPhase != 1) {
                        throw new ServiceException("上一轮检查已完成（已收车），请开始新的出车检查（第一阶段）");
                    }
                }
                // 2. 如果上一条是出车检查(第1阶段)
                else if (lastPhase == 1) {
                    if (currentPhase == 1) {
                        throw new ServiceException("当前已有出车检查记录，请进行行车检查或收车检查");
                    }
                    // 可以是行车检查(2) 或 收车检查(3)
                    // 如果是收车检查(3)，需要判断时间间隔
                    if (currentPhase == 3) {
                        // 检查出车时间与当前时间间隔
                        // 如果 last.getInspectTime() 为空，使用 createTime
                        java.util.Date lastTime = last.getInspectTime() != null ? last.getInspectTime() : last.getCreateTime();
                        long diff = System.currentTimeMillis() - lastTime.getTime();
                        long hours = diff / (60 * 60 * 1000);
                        if (hours > 4) {
                            throw new ServiceException("距离出车检查已超过4小时，必须先进行行车检查（第二阶段），才能进行收车检查");
                        }
                    }
                }
                // 3. 如果上一条是行车检查(第2阶段)
                else if (lastPhase == 2) {
                    if (currentPhase == 1) {
                        throw new ServiceException("当前轮次尚未完成收车检查，不能开始新一轮出车检查");
                    }
                    if (currentPhase == 2) {
                        // 允许连续多次行车检查? 需求未明确禁止，通常行车检查可以有多次，但这里假设按顺序走
                        // 如果严格按1-2-3走，这里可能需要限制。根据需求描述 "三次检查依次是..."，倾向于 1->2->3
                        // 但需求也说 "收车检查也不用等到行车检查审核完结"，意味着 1->2 后必须接 3
                        throw new ServiceException("当前已完成行车检查，请进行收车检查（第三阶段）");
                    }
                    // 必须是收车检查(3)
                }
            } else {
                // 没有历史记录，必须从第一阶段开始
                if (currentPhase != 1) {
                    throw new ServiceException("新的一轮检查必须从出车检查（第一阶段）开始");
                }
            }
        }

        boolean flag = baseMapper.insert(add) > 0;
        if (flag) {
            bo.setId(add.getId());

            // 开启车辆三检的流程
            String initiator = String.valueOf(LoginHelper.getBusinessUserId());

            // 下一步审核人
            String approverId = bo.getAuditorId() != null ? String.valueOf(bo.getAuditorId()) : null;

            if (StringUtils.isBlank(approverId)) {
                throw new ServiceException("请选择审核人");
            }

            String instanceId = flowService.startFlow(
                    "VEHICLE_THREE_INSPECT",
                    String.valueOf(add.getId()),
                    add.getCompanyId(),
                    initiator,
                    approverId
            );

            // 更新流程状态
            add.setInstanceId(instanceId);
            add.setFlowStatus("SUBMITTED");
            baseMapper.updateById(add);
            try {
                sendSubmitNotification(add, approverId);
            } catch (Exception e) {
                log.warn("发送车辆三检提交通知失败 inspectId={} approverId={}", add.getId(), approverId, e);
            }
        }
        return flag;
    }

    private void validateOutboundVehicleDriver(HotVehicleThreeInspect currentInspect, HotVehicleThreeInspect latestInspect) {
        if (currentInspect == null || !Objects.equals(currentInspect.getInspectPhase(), 1L) || latestInspect == null) {
            return;
        }
        if (Objects.equals(latestInspect.getInspectPhase(), 3L)) {
            return;
        }
        if (StringUtils.equals(StringUtils.trimToEmpty(currentInspect.getDriverId()),
                StringUtils.trimToEmpty(latestInspect.getDriverId()))) {
            return;
        }
        throw new ServiceException(buildVehicleOccupiedMessage(currentInspect.getVehicleId()));
    }

    private String buildVehicleOccupiedMessage(Long vehicleId) {
        if (vehicleId == null) {
            return "该车辆已出任务，请重新选择其他车辆";
        }
        HotVehicle vehicle = hotVehicleMapper.selectById(String.valueOf(vehicleId));
        String plateNumber = vehicle == null ? null : StringUtils.trimToNull(vehicle.getPlateNumber());
        if (plateNumber == null) {
            return "该车辆已出任务，请重新选择其他车辆";
        }
        return "'" + plateNumber + "'车辆已出任务，请重新选择其他车辆";
    }

    private boolean isVehicleOutbound(Long vehicleId) {
        if (vehicleId == null) {
            return false;
        }
        return hotVehicleInoutCheckMapper.selectCount(
                Wrappers.<HotVehicleInoutCheck>lambdaQuery()
                        .eq(HotVehicleInoutCheck::getVehicleId, vehicleId)
                        .eq(HotVehicleInoutCheck::getIsDeleted, 0L)
                        .isNotNull(HotVehicleInoutCheck::getDepartureTime)
                        .isNull(HotVehicleInoutCheck::getReturnTime)
        ) > 0;
    }

    private void validateInspectorSignatureByPhase(HotVehicleThreeInspectBo bo) {
        Long inspectPhase = bo.getInspectPhase();
        if (inspectPhase == null) {
            throw new ServiceException("检查阶段不能为空");
        }
        if (StringUtils.isBlank(bo.getDriverName())) {
            throw new ServiceException("检查员姓名不能为空");
        }
        if (inspectPhase == 1L || inspectPhase == 2L || inspectPhase == 3L) {
            Long ossId = parseSignatureOssId(bo.getInspectorSignImgUrl());
            signatureVerifyService.validateSelfSignature(ossId, bo.getDriverName());
            return;
        }
        throw new ServiceException("检查阶段错误");
    }

    private Long parseSignatureOssId(String signImgUrl) {
        String first = signImgUrl.split(",")[0].trim();
        if (!first.matches("^\\d+$")) {
            throw new ServiceException("签名文件格式错误");
        }
        return Long.parseLong(first);
    }

    private void sendSubmitNotification(HotVehicleThreeInspect inspect, String approverId) {
        if (inspect == null || StringUtils.isBlank(approverId)) {
            return;
        }
        HotSystemNotificationGroupBo bos = new HotSystemNotificationGroupBo();
        bos.setLevel("普通");
        bos.setContent(buildSubmitNotificationContent(inspect));
        bos.setSourceType("车辆管理");
        bos.setSenderType("SYSTEM");
        bos.setReceiverType("管理员");
        bos.setReceiverIds(java.util.Collections.singletonList(approverId));
        bos.setIsDeleted(0L);
        notificationService.insertByBo(bos);
    }

    private String buildSubmitNotificationContent(HotVehicleThreeInspect inspect) {
        String driverName = StringUtils.blankToDefault(StringUtils.trim(inspect.getDriverName()), "驾驶员");
        return driverName + "提交了车辆三检【" + getPhaseName(inspect.getInspectPhase()) + "】记录，请及时审核。";
    }

    private String getPhaseName(Long phase) {
        if (phase == null) {
            return "未知阶段";
        }
        if (phase == 1L) {
            return "出车前检查";
        }
        if (phase == 2L) {
            return "行车中检查";
        }
        if (phase == 3L) {
            return "收车后检查";
        }
        return "未知阶段";
    }

    /**
     * 修改车辆三检
     *
     * @param bo 车辆三检
     * @return 是否修改成功
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public Boolean updateByBo(HotVehicleThreeInspectBo bo) {
        validateAttachImgUrlRequiredWhenAbnormal(bo);
        HotVehicleThreeInspect update = MapstructUtils.convert(bo, HotVehicleThreeInspect.class);
        validEntityBeforeSave(update);
        boolean flag = baseMapper.updateById(update) > 0;
        return flag;
    }

    private void validateAttachImgUrlRequiredWhenAbnormal(HotVehicleThreeInspectBo bo) {
        if (!hasAbnormalInspectItem(bo)) {
            return;
        }
        if (StringUtils.isBlank(bo.getAttachImgUrl())) {
            throw new ServiceException("检查项存在异常时，检查附件不能为空");
        }
    }

    private boolean hasAbnormalInspectItem(HotVehicleThreeInspectBo bo) {
        if (bo == null || StringUtils.isBlank(bo.getInspectResultJson())) {
            return false;
        }
        Map<String, Object> inspectResultMap;
        try {
            inspectResultMap = JsonUtils.parseObject(bo.getInspectResultJson(), new TypeReference<Map<String, Object>>() {
            });
        } catch (RuntimeException e) {
            throw new ServiceException("检查项目结果JSON格式错误");
        }
        if (inspectResultMap == null || inspectResultMap.isEmpty()) {
            return false;
        }

        Map<Long, String> abnormalTextMap = queryAbnormalTextMap(bo, inspectResultMap);
        for (Map.Entry<String, Object> entry : inspectResultMap.entrySet()) {
            String resultText = StringUtils.trimToNull(Objects.toString(entry.getValue(), null));
            if (resultText == null) {
                continue;
            }
            Long configId = parseConfigId(entry.getKey());
            String abnormalText = configId == null ? "异常" : abnormalTextMap.getOrDefault(configId, "异常");
            if (StringUtils.equals(resultText, abnormalText)) {
                return true;
            }
        }
        return false;
    }

    private Map<Long, String> queryAbnormalTextMap(HotVehicleThreeInspectBo bo, Map<String, Object> inspectResultMap) {
        List<Long> configIds = inspectResultMap.keySet().stream()
                .map(this::parseConfigId)
                .filter(Objects::nonNull)
                .toList();
        if (configIds.isEmpty()) {
            return Collections.emptyMap();
        }
        List<HotVehicleThreeInspectConfig> configList = hotVehicleThreeInspectConfigMapper.selectList(
                Wrappers.<HotVehicleThreeInspectConfig>lambdaQuery()
                        .in(HotVehicleThreeInspectConfig::getId, configIds)
                        .eq(bo.getCompanyId() != null, HotVehicleThreeInspectConfig::getCompanyId, bo.getCompanyId())
                        .eq(bo.getInspectPhase() != null, HotVehicleThreeInspectConfig::getInspectType, bo.getInspectPhase())
        );
        if (configList == null || configList.isEmpty()) {
            return Collections.emptyMap();
        }
        Map<Long, String> abnormalTextMap = new HashMap<>(configList.size());
        for (HotVehicleThreeInspectConfig config : configList) {
            String abnormalText = StringUtils.trimToNull(config.getAbnormalText());
            abnormalTextMap.put(config.getId(), abnormalText == null ? "异常" : abnormalText);
        }
        return abnormalTextMap;
    }

    private Long parseConfigId(String configIdText) {
        String value = StringUtils.trimToNull(configIdText);
        if (value == null || !value.matches("\\d+")) {
            return null;
        }
        return Long.parseLong(value);
    }

    /**
     * 保存前的数据校验
     */
    private void validEntityBeforeSave(HotVehicleThreeInspect entity) {
        //TODO 做一些数据校验,如唯一约束
    }

    /**
     * 校验并批量删除车辆三检信息
     *
     * @param ids     待删除的主键集合
     * @param isValid 是否进行有效性校验
     * @return 是否删除成功
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public Boolean deleteWithValidByIds(Collection<Long> ids, Boolean isValid) {
        if (isValid) {

        }
        List<HotVehicleThreeInspect> list = baseMapper.selectList(
                Wrappers.<HotVehicleThreeInspect>lambdaQuery()
                        .in(HotVehicleThreeInspect::getId, ids)
        );
        if (list != null && !list.isEmpty()) {
            java.util.Set<String> instanceIds = new java.util.HashSet<>();
            for (HotVehicleThreeInspect e : list) {
                if (org.dromara.common.core.utils.StringUtils.isNotBlank(e.getInstanceId())) {
                    instanceIds.add(e.getInstanceId());
                }
            }
            if (!instanceIds.isEmpty()) {
                flowService.deleteTodosByInstanceIds(instanceIds);
            }
        }
        return baseMapper.deleteByIds(ids) > 0;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void audit(HotVehicleThreeInspectBo bo) {
        doAudit(bo);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void batchAudit(HotVehicleThreeInspectBatchAuditBo bo) {
        validateBatchAuditAuditor(bo);
        for (HotVehicleThreeInspectBo item : bo.getAuditItems()) {
            if (item == null) {
                continue;
            }
            doAudit(item);
        }
    }

    private void validateBatchAuditAuditor(HotVehicleThreeInspectBatchAuditBo bo) {
        Long expectedAuditorId = null;
        String expectedAuditorName = null;
        for (HotVehicleThreeInspectBo item : bo.getAuditItems()) {
            if (item == null) {
                continue;
            }
            if (item.getAuditorId() == null) {
                throw new ServiceException("批量审核时审核人不能为空");
            }
            String currentAuditorName = StringUtils.trimToNull(item.getAuditorName());
            if (StringUtils.isBlank(currentAuditorName)) {
                throw new ServiceException("批量审核时审核人姓名不能为空");
            }
            if (expectedAuditorId == null) {
                expectedAuditorId = item.getAuditorId();
                expectedAuditorName = currentAuditorName;
                continue;
            }
            if (!Objects.equals(expectedAuditorId, item.getAuditorId())
                    || !StringUtils.equals(expectedAuditorName, currentAuditorName)) {
                throw new ServiceException("批量审核时审核人必须是同一个人");
            }
        }
    }

    private void doAudit(HotVehicleThreeInspectBo bo) {
        // 1. 校验参数
        if (bo.getTaskId() == null) {
            throw new ServiceException("流程任务ID不能为空");
        }
        if (bo.getId() == null) {
            throw new ServiceException("三检记录ID不能为空");
        }
        HotVehicleThreeInspect current = baseMapper.selectById(bo.getId());
        if (current == null) {
            throw new ServiceException("三检记录不存在");
        }
        validateAuditTimeNotBeforeInspectTime(bo, current);
        if (StringUtils.isNotBlank(bo.getAuditorSignImgUrl())) {
            String auditorName = resolveAuditorName(bo);
            signatureVerifyService.validateSelfSignature(parseSignatureOssId(bo.getAuditorSignImgUrl()), auditorName);
        }
        normalizeRejectReason(bo);
        // 2. 更新业务数据
        HotVehicleThreeInspect update = MapstructUtils.convert(bo, HotVehicleThreeInspect.class);
        boolean flag = baseMapper.updateById(update) > 0;

        if (flag) {
            // 只有审核人员签名了，才完成流程任务
            if (StringUtils.isNotBlank(bo.getAuditorSignImgUrl())) {
                // 4. 完成流程任务
                // 如果有隐患，我们认为流程是"驳回"的（需要整改）
                boolean auditPass = bo.getHasHiddenDanger() != null && bo.getHasHiddenDanger() == 0L;
                flowService.audit(
                    bo.getTaskId(),
                    auditPass,
                    bo.getAuditResult(),
                    LoginHelper.getBusinessUserId()
                );
            }
        }

    }

    private void normalizeRejectReason(HotVehicleThreeInspectBo bo) {
        boolean rejected = Objects.equals(bo.getHasHiddenDanger(), 1L);
        if (!rejected) {
            bo.setRejectReason(null);
            return;
        }
        bo.setRejectReason(StringUtils.trimToNull(bo.getRejectReason()));
//        if (StringUtils.isBlank(bo.getRejectReason())) {
//            throw new ServiceException("审核不通过时，不通过原因不能为空");
//        }
    }

    private void validateAuditTimeNotBeforeInspectTime(HotVehicleThreeInspectBo bo, HotVehicleThreeInspect current) {
        java.util.Date auditTime = bo.getAuditTime();
        if (auditTime == null) {
            return;
        }
        java.util.Date inspectTime = bo.getInspectTime() != null ? bo.getInspectTime() : current.getInspectTime();
        if (inspectTime != null && auditTime.before(inspectTime)) {
            throw new ServiceException("审核日期不能早于检查日期");
        }
    }

    private String resolveAuditorName(HotVehicleThreeInspectBo bo) {
        if (StringUtils.isNotBlank(bo.getAuditorName())) {
            return bo.getAuditorName().trim();
        }
        if (bo.getId() != null) {
            HotVehicleThreeInspect current = baseMapper.selectById(bo.getId());
            if (current != null && StringUtils.isNotBlank(current.getAuditorName())) {
                return current.getAuditorName().trim();
            }
        }
        throw new ServiceException("审核人姓名不能为空");
    }

    private Long parseVehicleId(String vehicleId) {
        if (StringUtils.isBlank(vehicleId)) {
            return null;
        }
        if (!vehicleId.matches("^\\d+$")) {
            log.warn("车辆三检校验跳过非数字车辆ID vehicleId={}", vehicleId);
            return null;
        }
        return Long.valueOf(vehicleId);
    }

    private HotVehicleThreeInspect selectLatestInspect(Long vehicleId) {
        return baseMapper.selectOne(
                Wrappers.<HotVehicleThreeInspect>lambdaQuery()
                        .eq(HotVehicleThreeInspect::getVehicleId, vehicleId)
                        .eq(HotVehicleThreeInspect::getIsDeleted, 0L)
                        .orderByDesc(HotVehicleThreeInspect::getCreateTime)
                        .last("LIMIT 1")
        );
    }
}
