package com.hotwj.platform.flow.service.impl;

import cn.hutool.core.util.StrUtil;
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.hotwj.platform.driverManagement.driver.domain.HotDriver;
import com.hotwj.platform.driverManagement.driver.mapper.HotDriverMapper;
import com.hotwj.platform.flow.callback.FlowCallbackFactory;
import com.hotwj.platform.flow.callback.IFlowCallback;
import com.hotwj.platform.flow.domain.SysFlowInstance;
import com.hotwj.platform.flow.domain.SysFlowTask;
import com.hotwj.platform.flow.domain.SysFlowTaskHis;
import com.hotwj.platform.flow.domain.dto.FlowNextDto;
import com.hotwj.platform.flow.mapper.SysFlowInstanceMapper;
import com.hotwj.platform.flow.mapper.SysFlowTaskHisMapper;
import com.hotwj.platform.flow.mapper.SysFlowTaskMapper;
import com.hotwj.platform.flow.service.ISysFlowService;
import com.hotwj.platform.flow.strategy.FlowStrategyFactory;
import com.hotwj.platform.flow.strategy.IFlowStrategy;
import com.hotwj.platform.resourceManagement.companySafetyManager.domain.HotCompanySafetyManager;
import com.hotwj.platform.resourceManagement.companySafetyManager.mapper.HotCompanySafetyManagerMapper;
import com.hotwj.platform.securityManagement.hiddenDangerInspection.domain.HotHiddenDangerInspection;
import com.hotwj.platform.securityManagement.hiddenDangerInspection.mapper.HotHiddenDangerInspectionMapper;
import com.hotwj.platform.securityManagement.securityMeeting.domain.HotSecurityMeeting;
import com.hotwj.platform.securityManagement.securityMeeting.mapper.HotSecurityMeetingMapper;
import com.hotwj.platform.securityManagement.training.domain.HotTraining;
import com.hotwj.platform.securityManagement.training.mapper.HotTrainingMapper;
import com.hotwj.platform.securityManagement.trainingParticipant.domain.HotTrainingParticipant;
import com.hotwj.platform.securityManagement.trainingParticipant.mapper.HotTrainingParticipantMapper;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.dromara.common.core.domain.model.LoginUser;
import org.dromara.common.core.exception.ServiceException;
import org.dromara.common.mybatis.core.page.PageQuery;
import org.dromara.common.mybatis.core.page.TableDataInfo;
import org.dromara.common.satoken.utils.LoginHelper;
import org.dromara.warm.flow.core.utils.CollUtil;
import org.dromara.warm.flow.core.utils.ObjectUtil;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

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

/**
 * 流程引擎服务实现
 */
@Slf4j
@RequiredArgsConstructor
@Service
public class SysFlowServiceImpl implements ISysFlowService {

    private final SysFlowInstanceMapper instanceMapper;
    private final SysFlowTaskMapper taskMapper;
    private final SysFlowTaskHisMapper taskHisMapper;

    private final FlowStrategyFactory flowStrategyFactory;
    private final FlowCallbackFactory flowCallbackFactory;

    private final HotCompanySafetyManagerMapper hotCompanySafetyManagerMapper;
    private final HotDriverMapper hotDriverMapper;
    private final HotHiddenDangerInspectionMapper hotHiddenDangerInspectionMapper;
    private final HotSecurityMeetingMapper hotSecurityMeetingMapper;
    private final HotTrainingParticipantMapper hotTrainingParticipantMapper;
    private final HotTrainingMapper hotTrainingMapper;

    // 状态常量
    private static final int STATUS_RUNNING = 0;
    private static final int STATUS_FINISHED = 1;
    private static final int STATUS_REVOKED = 2; // 撤销
    private static final int STATUS_TERMINATED = 9; // 终止

    private static final int TASK_STATUS_PASS = 1;
    private static final int TASK_STATUS_REJECT = 2;

    @Override
    @Transactional(rollbackFor = Exception.class)
    public String startFlow(String flowCode, String businessId, Long companyId, String initiatorId, String approverId) {
        // 1. 创建流程实例
        SysFlowInstance instance = new SysFlowInstance();
        instance.setFlowCode(flowCode);
        instance.setBusinessId(businessId);
        instance.setCompanyId(companyId);
        instance.setInitiatorId(initiatorId);
        instance.setStatus(STATUS_RUNNING);
        instance.setCreateTime(new Date());

        LoginUser loginUser = getLoginUser();
        if (ObjectUtil.isNotNull(loginUser)) {
            Long userId = loginUser.getUserId();
            instance.setCreateBy(String.valueOf(userId));
            instance.setUpdateBy(String.valueOf(userId));
        }

        instanceMapper.insert(instance);

        // 2. 创建第一个任务 (开始节点 -> 下一个节点)
        SysFlowTask task = new SysFlowTask();
        task.setInstanceId(instance.getInstanceId());

        // 获取初始节点策略
        IFlowStrategy strategy = flowStrategyFactory.getStrategy(flowCode);
        FlowNextDto initialNode;
        if (strategy != null) {
            initialNode = strategy.getInitialNode(businessId);
        } else {
            initialNode = new FlowNextDto("NODE_1", "一级审批", null);
        }

        task.setNodeCode(initialNode.getNodeCode());
        task.setNodeName(initialNode.getNodeName());
        // 优先使用 startFlow 传入的审批人，如果为空则尝试使用策略返回的审批人
        if (StrUtil.isNotBlank(approverId)) {
            task.setApproverId(approverId);
        } else {
            task.setApproverId(initialNode.getApproverId());
        }
        
        task.setCompanyId(companyId);
        task.setCreateTime(new Date());
        if (ObjectUtil.isNotNull(loginUser)) {
            Long userId = loginUser.getUserId();
            task.setCreateBy(String.valueOf(userId));
            task.setUpdateBy(String.valueOf(userId));
        }
        taskMapper.insert(task);

        return instance.getInstanceId();
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void audit(String taskId, boolean pass, String comment, String auditorId) {
        // 1. 获取任务
        SysFlowTask task = taskMapper.selectById(taskId);
        if (task == null) {
            throw new ServiceException("任务不存在或已处理");
        }

        // 校验审核人
        if (!auditorId.equals(task.getApproverId())) {
            throw new ServiceException("您不是当前节点的审批人");
        }

        SysFlowInstance instance = instanceMapper.selectById(task.getInstanceId());
        if (instance == null) {
            throw new ServiceException("流程实例不存在");
        }

        // 修正：避免空指针和类型错误
        if (instance.getStatus() != null && instance.getStatus() != STATUS_RUNNING) {
            throw new ServiceException("流程已结束或非运行状态");
        }

        // 2. 归档当前任务到历史
        SysFlowTaskHis his = new SysFlowTaskHis();
        his.setTaskId(task.getTaskId());
        his.setInstanceId(task.getInstanceId());
        his.setNodeCode(task.getNodeCode());
        his.setNodeName(task.getNodeName());
        his.setApproverId(task.getApproverId());
        his.setStatus(pass ? TASK_STATUS_PASS : TASK_STATUS_REJECT);
        his.setComment(comment);
        his.setAuditTime(new Date());
        his.setCompanyId(task.getCompanyId());
        taskHisMapper.insert(his);

        // 删除待办任务
        taskMapper.deleteById(taskId);

        // 3. 决策下一步
        boolean processEnd = false;
        boolean processSuccess = false;

        if (!pass) {
            // 驳回
            IFlowStrategy strategy = flowStrategyFactory.getStrategy(instance.getFlowCode());
			// 如果驳回返回的下一节点不为空，则继续流程
            FlowNextDto rejectNode = (strategy != null) ? strategy.reject(instance, task.getNodeCode()) : null;

            if (rejectNode != null) {
                // 策略返回了驳回节点，流程回退到该节点
                SysFlowTask newTask = new SysFlowTask();
                newTask.setInstanceId(instance.getInstanceId());
                newTask.setNodeCode(rejectNode.getNodeCode());
                newTask.setNodeName(rejectNode.getNodeName());
                newTask.setApproverId(rejectNode.getApproverId());
                newTask.setCompanyId(instance.getCompanyId());
                newTask.setCreateTime(new Date());
                if (ObjectUtil.isNotNull(getLoginUser())) {
                    newTask.setCreateBy(String.valueOf(getLoginUser().getUserId()));
                    newTask.setUpdateBy(String.valueOf(getLoginUser().getUserId()));
                }
                taskMapper.insert(newTask);
            } else {
                // 默认处理：流程直接结束 (简单模式)
                instance.setStatus(STATUS_TERMINATED); // 或者 REVOKED，视业务定义，这里用9表示审核不通过终止
                instance.setFinishTime(new Date());
                instanceMapper.updateById(instance);
                processEnd = true;
                processSuccess = false;
            }
        } else {
            // 通过，获取下一步
            IFlowStrategy strategy = flowStrategyFactory.getStrategy(instance.getFlowCode());
            FlowNextDto nextNode = null;
            if (strategy != null) {
                nextNode = strategy.next(instance, task.getNodeCode());
            }
            
            if (nextNode == null) {
                // 没有下一步，流程结束
                instance.setStatus(STATUS_FINISHED);
                instance.setFinishTime(new Date());
                instanceMapper.updateById(instance);
                processEnd = true;
                processSuccess = true;
            } else {
                // 有下一步，创建新任务
                SysFlowTask newTask = new SysFlowTask();
                newTask.setInstanceId(instance.getInstanceId());
                newTask.setNodeCode(nextNode.getNodeCode());
                newTask.setNodeName(nextNode.getNodeName());
                newTask.setApproverId(nextNode.getApproverId()); // 策略返回的审批人
                newTask.setCompanyId(instance.getCompanyId());
                newTask.setCreateTime(new Date());
                taskMapper.insert(newTask);
            }
        }

        // 4. 触发回调
        if (processEnd) {
            Optional<IFlowCallback> callback = flowCallbackFactory.getCallback(instance.getFlowCode());
            if (callback.isPresent()) {
                IFlowCallback iFlowCallback = callback.get();
                iFlowCallback.onProcessEnd(instance.getInstanceId(),
                        instance.getBusinessId(),
                        instance.getFlowCode(),
                        processSuccess);
            }
        }
    }

    @Override
    public TableDataInfo<SysFlowTask> getTodoList(String userId, PageQuery pageQuery, String isRead) {
        LambdaQueryWrapper<SysFlowTask> lqw = new LambdaQueryWrapper<>();
        lqw.eq(SysFlowTask::getApproverId, userId);
        if (StrUtil.isNotBlank(isRead)) {
            lqw.eq(SysFlowTask::getIsRead, Integer.valueOf(isRead));
        }
        lqw.orderByDesc(SysFlowTask::getCreateTime);
        List<SysFlowTask> records = taskMapper.selectList(lqw);
        fillFlowInfo(records);
        filterInvalidTrainingStudyTodos(records);
        return buildTodoPage(records, pageQuery);
    }

    @Override
    public TableDataInfo<SysFlowTask> getEnterpriseTodoList(Long companyId, PageQuery pageQuery) {
        LambdaQueryWrapper<SysFlowTask> lqw = new LambdaQueryWrapper<>();
        lqw.eq(SysFlowTask::getCompanyId, companyId);
        LoginUser loginUser = getLoginUser();
        if (loginUser != null && cn.hutool.core.util.StrUtil.isNotBlank(loginUser.getBusinessUserId())) {
            lqw.ne(SysFlowTask::getApproverId, loginUser.getBusinessUserId());
        }
        lqw.orderByDesc(SysFlowTask::getCreateTime);
        List<SysFlowTask> records = taskMapper.selectList(lqw);
        fillFlowInfo(records);
        filterInvalidTrainingStudyTodos(records);
        if (CollUtil.isNotEmpty(records)) {
            List<String> approverIds = records.stream()
                .map(SysFlowTask::getApproverId)
                .filter(id -> StrUtil.isNotBlank(id))
                .distinct()
                .toList();

            if (CollUtil.isNotEmpty(approverIds)) {
                Map<String, String> approverNameMap = new HashMap<>();

                List<Long> managerIds = approverIds.stream()
                    .filter(StrUtil::isNumeric)
                    .map(Long::valueOf)
                    .distinct()
                    .toList();

                if (CollUtil.isNotEmpty(managerIds)) {
                    List<HotCompanySafetyManager> managers = hotCompanySafetyManagerMapper.selectList(
                        Wrappers.<HotCompanySafetyManager>lambdaQuery()
                            .eq(HotCompanySafetyManager::getCompanyId, companyId)
                            .in(HotCompanySafetyManager::getId, managerIds)
                    );
                    for (HotCompanySafetyManager manager : managers) {
                        approverNameMap.put(String.valueOf(manager.getId()), manager.getName());
                    }
                }

                List<HotDriver> drivers = hotDriverMapper.selectList(
                    Wrappers.<HotDriver>lambdaQuery()
                        .eq(HotDriver::getCompanyId, companyId)
                        .in(HotDriver::getId, approverIds)
                );
                for (HotDriver driver : drivers) {
                    approverNameMap.put(driver.getId(), driver.getName());
                }

                for (SysFlowTask task : records) {
                    task.setApproverName(approverNameMap.get(task.getApproverId()));
                }
            }
        }

        return buildTodoPage(records, pageQuery);
    }

    private TableDataInfo<SysFlowTask> buildTodoPage(List<SysFlowTask> records, PageQuery pageQuery) {
        if (CollUtil.isEmpty(records)) {
            return new TableDataInfo<>(Collections.emptyList(), 0);
        }
        Integer pageNum = pageQuery.getPageNum();
        Integer pageSize = pageQuery.getPageSize();
        if (pageNum == null || pageNum <= 0) {
            pageNum = PageQuery.DEFAULT_PAGE_NUM;
        }
        if (pageSize == null || pageSize <= 0) {
            pageSize = PageQuery.DEFAULT_PAGE_SIZE;
        }
        int total = records.size();
        int fromIndex = Math.min((pageNum - 1) * pageSize, total);
        int toIndex = Math.min(fromIndex + pageSize, total);
        return new TableDataInfo<>(records.subList(fromIndex, toIndex), total);
    }

    /**
     * 填充流程信息 (名称、编码)
     */
    private void fillFlowInfo(List<SysFlowTask> taskList) {
        if (CollUtil.isEmpty(taskList)) {
            return;
        }

        // 获取所有实例ID
        List<String> instanceIds = taskList.stream()
                .map(SysFlowTask::getInstanceId)
                .distinct()
                .toList();

        if (CollUtil.isEmpty(instanceIds)) {
            return;
        }

        // 查询实例信息
        List<SysFlowInstance> instances = instanceMapper.selectBatchIds(instanceIds);
        Map<String, SysFlowInstance> instanceMap = instances.stream()
                .collect(java.util.stream.Collectors.toMap(SysFlowInstance::getInstanceId, i -> i));

        // 填充信息
        for (SysFlowTask task : taskList) {
            SysFlowInstance instance = instanceMap.get(task.getInstanceId());
            if (instance != null) {
                task.setBusinessId(instance.getBusinessId());
                String flowCode = instance.getFlowCode();
                if (StrUtil.isNotBlank(flowCode)) {
                    task.setFlowCode(flowCode);
                    IFlowStrategy strategy = flowStrategyFactory.getStrategy(flowCode);
                    if (strategy != null) {
                        task.setFlowName(strategy.getFlowName());
                    } else if ("VIOLATION_HANDLE".equals(flowCode)) {
                        task.setFlowName("违规处理");
                    } else if ("SIGN_FILE".equals(flowCode)) {
                        task.setFlowName("文件签署");
                    } else if ("TRAINING_STUDY".equals(flowCode)) {
                        task.setFlowName("安全教育培训");
                    }
                }
            }
        }

        // 分组处理特定业务信息
        Map<String, List<SysFlowTask>> tasksByFlowCode = taskList.stream()
            .filter(t -> StrUtil.isNotBlank(t.getFlowCode()) && StrUtil.isNotBlank(t.getBusinessId()))
            .collect(Collectors.groupingBy(SysFlowTask::getFlowCode));

        // 隐患排查
        if (tasksByFlowCode.containsKey("HIDDEN_DANGER_CHECK")) {
            fillHiddenDangerInfo(tasksByFlowCode.get("HIDDEN_DANGER_CHECK"));
        }

        // 安全会议
        if (tasksByFlowCode.containsKey("MEETING_SIGN")) {
            fillMeetingInfo(tasksByFlowCode.get("MEETING_SIGN"));
        }

        if (tasksByFlowCode.containsKey("TRAINING_STUDY")) {
            fillTrainingStudyInfo(tasksByFlowCode.get("TRAINING_STUDY"));
        }
    }

    /**
     * 填充隐患排查相关信息
     */
    private void fillHiddenDangerInfo(List<SysFlowTask> tasks) {
        if (CollUtil.isEmpty(tasks)) return;

        Set<Long> inspectionIds = new HashSet<>();
        for (SysFlowTask task : tasks) {
            try {
                inspectionIds.add(Long.valueOf(task.getBusinessId()));
            } catch (NumberFormatException e) {
                // ignore
            }
        }

        if (CollUtil.isNotEmpty(inspectionIds)) {
            List<HotHiddenDangerInspection> inspections = hotHiddenDangerInspectionMapper.selectBatchIds(inspectionIds);
            if (CollUtil.isNotEmpty(inspections)) {
                Map<Long, Long> planIdMap = inspections.stream()
                    .filter(i -> i.getPlanId() != null)
                    .collect(Collectors.toMap(HotHiddenDangerInspection::getId, HotHiddenDangerInspection::getPlanId));

                for (SysFlowTask task : tasks) {
                    try {
                        Long inspectionId = Long.valueOf(task.getBusinessId());
                        Long planId = planIdMap.get(inspectionId);
                        if (planId != null) {
                            task.setPlanId(planId);
                        }
                    } catch (NumberFormatException e) {
                        // ignore
                    }
                }
            }
        }
    }

    /**
     * 填充安全会议相关信息
     */
    private void fillMeetingInfo(List<SysFlowTask> tasks) {
        if (CollUtil.isEmpty(tasks)) return;

        Set<Long> meetingIds = new HashSet<>();
        for (SysFlowTask task : tasks) {
            try {
                meetingIds.add(Long.valueOf(task.getBusinessId()));
            } catch (NumberFormatException e) {
                // ignore
            }
        }

        if (CollUtil.isNotEmpty(meetingIds)) {
            List<HotSecurityMeeting> meetings = hotSecurityMeetingMapper.selectBatchIds(meetingIds);
            if (CollUtil.isNotEmpty(meetings)) {
                Map<Long, HotSecurityMeeting> meetingMap = meetings.stream()
                        .collect(Collectors.toMap(HotSecurityMeeting::getId, m -> m));

                for (SysFlowTask task : tasks) {
                    try {
                        Long meetingId = Long.valueOf(task.getBusinessId());
                        HotSecurityMeeting meeting = meetingMap.get(meetingId);
                        if (meeting != null) {
                            if (StrUtil.isNotBlank(meeting.getMeetingType())) {
                                task.setMeetingType(meeting.getMeetingType());
                            }
                            if (meeting.getStartTime() != null) {
                                task.setStartTime(meeting.getStartTime());
                                // 覆盖创建时间为会议开始时间，以便前端展示
                                task.setCreateTime(meeting.getStartTime());
                            }
                        }
                    } catch (NumberFormatException e) {
                        // ignore
                    }
                }
            }
        }
    }

    private void fillTrainingStudyInfo(List<SysFlowTask> tasks) {
        if (CollUtil.isEmpty(tasks)) return;

        Set<Long> trainingIds = new HashSet<>();
        Set<String> userIds = new HashSet<>();
        for (SysFlowTask task : tasks) {
            if (StrUtil.isNotBlank(task.getApproverId())) {
                userIds.add(task.getApproverId());
            }
            try {
                trainingIds.add(Long.valueOf(task.getBusinessId()));
            } catch (Exception ignored) {
            }
        }
        if (CollUtil.isEmpty(trainingIds) || CollUtil.isEmpty(userIds)) {
            return;
        }

        List<HotTrainingParticipant> participants = hotTrainingParticipantMapper.selectList(
                Wrappers.<HotTrainingParticipant>lambdaQuery()
                        .in(HotTrainingParticipant::getTrainingId, trainingIds)
                        .in(HotTrainingParticipant::getUserId, userIds)
                        .eq(HotTrainingParticipant::getIsDeleted, 0L)
        );
        if (CollUtil.isEmpty(participants)) {
            return;
        }

        Map<String, Long> participantIdMap = new HashMap<>();
        for (HotTrainingParticipant participant : participants) {
            if (participant == null || participant.getTrainingId() == null || StrUtil.isBlank(participant.getUserId()) || participant.getId() == null) {
                continue;
            }
            String key = participant.getTrainingId() + "_" + participant.getUserId();
            participantIdMap.put(key, participant.getId());
        }

        for (SysFlowTask task : tasks) {
            if (StrUtil.isBlank(task.getBusinessId()) || StrUtil.isBlank(task.getApproverId())) {
                continue;
            }
            try {
                Long trainingId = Long.valueOf(task.getBusinessId());
                Long participantId = participantIdMap.get(trainingId + "_" + task.getApproverId());
                if (participantId != null) {
                    task.setPlanId(participantId);
                }
            } catch (Exception ignored) {
            }
        }
    }

    private int filterInvalidTrainingStudyTodos(List<SysFlowTask> tasks) {
        if (CollUtil.isEmpty(tasks)) {
            return 0;
        }
        List<SysFlowTask> trainingTasks = tasks.stream()
                .filter(task -> "TRAINING_STUDY".equals(task.getFlowCode()))
                .filter(task -> StrUtil.isNotBlank(task.getBusinessId()) && StrUtil.isNotBlank(task.getApproverId()))
                .toList();
        if (CollUtil.isEmpty(trainingTasks)) {
            return 0;
        }

        Set<Long> trainingIds = new HashSet<>();
        Set<String> userIds = new HashSet<>();
        for (SysFlowTask task : trainingTasks) {
            try {
                trainingIds.add(Long.valueOf(task.getBusinessId()));
                userIds.add(task.getApproverId());
            } catch (Exception ignored) {
            }
        }
        if (CollUtil.isEmpty(trainingIds) || CollUtil.isEmpty(userIds)) {
            return 0;
        }

        Map<Long, HotTraining> trainingMap = hotTrainingMapper.selectBatchIds(trainingIds).stream()
                .filter(Objects::nonNull)
                .collect(Collectors.toMap(HotTraining::getId, training -> training));
        Set<String> participantKeys = hotTrainingParticipantMapper.selectList(
                        Wrappers.<HotTrainingParticipant>lambdaQuery()
                                .in(HotTrainingParticipant::getTrainingId, trainingIds)
                                .in(HotTrainingParticipant::getUserId, userIds)
                                .eq(HotTrainingParticipant::getIsDeleted, 0L)
                ).stream()
                .filter(Objects::nonNull)
                .filter(item -> item.getTrainingId() != null && StrUtil.isNotBlank(item.getUserId()))
                .map(item -> item.getTrainingId() + "_" + item.getUserId())
                .collect(Collectors.toSet());

        Date now = new Date();
        List<SysFlowTask> invalidTasks = new ArrayList<>();
        for (SysFlowTask task : trainingTasks) {
            Long trainingId;
            try {
                trainingId = Long.valueOf(task.getBusinessId());
            } catch (Exception ignored) {
                invalidTasks.add(task);
                continue;
            }
            if (!participantKeys.contains(trainingId + "_" + task.getApproverId())) {
                invalidTasks.add(task);
                continue;
            }
            HotTraining training = trainingMap.get(trainingId);
            if (!isTrainingStudyAccessible(training, now)) {
                invalidTasks.add(task);
            }
        }

        if (CollUtil.isEmpty(invalidTasks)) {
            return 0;
        }
        tasks.removeIf(task -> invalidTasks.stream().anyMatch(invalid ->
                Objects.equals(invalid.getTaskId(), task.getTaskId())));
        return invalidTasks.size();
    }

    private boolean isTrainingStudyAccessible(HotTraining training, Date now) {
        if (training == null) {
            return false;
        }
        if (!Objects.equals(training.getIsEnabled(), 1L)) {
            return false;
        }
        if (training.getStartTime() == null || training.getEndTime() == null) {
            return false;
        }
        if (training.getStartTime().compareTo(now) > 0) {
            return false;
        }
        if (training.getEndTime().compareTo(now) >= 0) {
            return true;
        }
        return Objects.equals(training.getIsMakeUp(), 1L);
    }

    @Override
    public void readTask(String taskId, String userId) {
        SysFlowTask task = taskMapper.selectById(taskId);
        if (task == null) {
            throw new ServiceException("任务不存在");
        }
        // 简单校验：只有任务审批人可以标记已读
        // 如果是企业管理员查看企业待办，通常是监控，不一定需要标记已读（或者标记已读意味着管理员已审阅）
        // 这里暂时限制为审批人本人
        if (!userId.equals(task.getApproverId())) {
            throw new ServiceException("您无权操作此任务");
        }
        task.setIsRead(1);
        taskMapper.updateById(task);
    }

    @Override
    public List<SysFlowTaskHis> getHistory(String instanceId) {
        LambdaQueryWrapper<SysFlowTaskHis> lqw = new LambdaQueryWrapper<>();
        lqw.eq(SysFlowTaskHis::getInstanceId, instanceId);
        lqw.orderByAsc(SysFlowTaskHis::getAuditTime);
        return taskHisMapper.selectList(lqw);
    }

    @Override
    public SysFlowInstance getInstance(String instanceId) {
        return instanceMapper.selectById(instanceId);
    }

    @Override
    public boolean isApprover(String instanceId, String userId) {
        if (instanceId == null || userId == null) {
            return false;
        }
        // 查询当前实例是否有该用户的待办任务
        Long count = taskMapper.selectCount(new LambdaQueryWrapper<SysFlowTask>()
                .eq(SysFlowTask::getInstanceId, instanceId)
                .eq(SysFlowTask::getApproverId, userId));
        return count != null && count > 0;
    }

    @Override
    public String getTaskId(String instanceId, String userId) {
        if (instanceId == null || userId == null) {
            return null;
        }
        SysFlowTask task = taskMapper.selectOne(new LambdaQueryWrapper<SysFlowTask>()
                .eq(SysFlowTask::getInstanceId, instanceId)
                .eq(SysFlowTask::getApproverId, userId)
                .last("limit 1"));
        return task != null ? task.getTaskId() : null;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public String pushDirectTodo(String flowCode, String businessId, String title, Long companyId, String userId) {
        // 1. 创建虚拟流程实例
        SysFlowInstance instance = new SysFlowInstance();
        instance.setFlowCode(flowCode);
        instance.setBusinessId(businessId);
        instance.setCompanyId(companyId);
        instance.setInitiatorId("SYSTEM"); // 系统推送
        instance.setStatus(STATUS_RUNNING);
        instance.setCreateTime(new Date());

        LoginUser loginUser = getLoginUser();
        if (loginUser != null) {
            instance.setCreateBy(String.valueOf(loginUser.getUserId()));
        } else {
            instance.setCreateBy("SYSTEM");
        }

        instanceMapper.insert(instance);

        // 2. 创建任务
        SysFlowTask task = new SysFlowTask();
        task.setInstanceId(instance.getInstanceId());
        task.setNodeCode("DIRECT_TODO");
        task.setNodeName(title); // 使用标题作为节点名称显示
        task.setApproverId(userId);
        task.setCompanyId(companyId);
        task.setCreateTime(new Date());
        task.setIsRead(0);

        if (loginUser != null) {
            task.setCreateBy(String.valueOf(loginUser.getUserId()));
        } else {
            task.setCreateBy("SYSTEM");
        }

        taskMapper.insert(task);

        return task.getTaskId();
    }

    @Override
    public String getTaskIdByBusinessId(String flowCode, String businessId, String userId) {
        // 1. 查找相关的运行中流程实例
        List<SysFlowInstance> instances = instanceMapper.selectList(
                Wrappers.<SysFlowInstance>lambdaQuery()
                        .eq(SysFlowInstance::getFlowCode, flowCode)
                        .eq(SysFlowInstance::getBusinessId, businessId)
                        .eq(SysFlowInstance::getStatus, STATUS_RUNNING)
        );

        if (instances.isEmpty()) {
            return null;
        }

        List<String> instanceIds = instances.stream()
                .map(SysFlowInstance::getInstanceId)
                .collect(Collectors.toList());

        // 2. 检查是否有该用户的待办任务
        SysFlowTask task = taskMapper.selectOne(
                Wrappers.<SysFlowTask>lambdaQuery()
                        .in(SysFlowTask::getInstanceId, instanceIds)
                        .eq(SysFlowTask::getApproverId, userId)
                        .last("limit 1")
        );
        return task != null ? task.getTaskId() : null;
    }

    @Override
    public String getCurrentTaskIdByBusinessId(String flowCode, String businessId) {
        List<SysFlowInstance> instances = instanceMapper.selectList(
                Wrappers.<SysFlowInstance>lambdaQuery()
                        .eq(SysFlowInstance::getFlowCode, flowCode)
                        .eq(SysFlowInstance::getBusinessId, businessId)
                        .eq(SysFlowInstance::getStatus, STATUS_RUNNING)
        );

        if (instances.isEmpty()) {
            return null;
        }

        List<String> instanceIds = instances.stream()
                .map(SysFlowInstance::getInstanceId)
                .collect(Collectors.toList());

        SysFlowTask task = taskMapper.selectOne(
                Wrappers.<SysFlowTask>lambdaQuery()
                        .in(SysFlowTask::getInstanceId, instanceIds)
                        .orderByDesc(SysFlowTask::getCreateTime)
                        .last("limit 1")
        );
        return task != null ? task.getTaskId() : null;
    }

    @Override
    public boolean hasPendingTask(String flowCode, String businessId, String userId) {
        // 1. 查找相关的运行中流程实例
        List<SysFlowInstance> instances = instanceMapper.selectList(
                Wrappers.<SysFlowInstance>lambdaQuery()
                        .eq(SysFlowInstance::getFlowCode, flowCode)
                        .eq(SysFlowInstance::getBusinessId, businessId)
                        .eq(SysFlowInstance::getStatus, STATUS_RUNNING)
        );

        if (instances.isEmpty()) {
            return false;
        }

        List<String> instanceIds = instances.stream()
                .map(SysFlowInstance::getInstanceId)
                .collect(Collectors.toList());

        // 2. 检查是否有该用户的待办任务
        return taskMapper.selectCount(
                Wrappers.<SysFlowTask>lambdaQuery()
                        .in(SysFlowTask::getInstanceId, instanceIds)
                        .eq(SysFlowTask::getApproverId, userId)
        ) > 0;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void deleteDirectTodo(String flowCode, String businessId, String userId) {
        // 1. 查找相关的运行中流程实例
        List<SysFlowInstance> instances = instanceMapper.selectList(
                Wrappers.<SysFlowInstance>lambdaQuery()
                        .eq(SysFlowInstance::getFlowCode, flowCode)
                        .eq(SysFlowInstance::getBusinessId, businessId)
                        .eq(SysFlowInstance::getStatus, STATUS_RUNNING)
        );

        if (instances.isEmpty()) {
            return;
        }

        List<String> instanceIds = instances.stream()
                .map(SysFlowInstance::getInstanceId)
                .collect(Collectors.toList());

        // 2. 查找该用户的待办任务
        List<SysFlowTask> tasks = taskMapper.selectList(
                Wrappers.<SysFlowTask>lambdaQuery()
                        .in(SysFlowTask::getInstanceId, instanceIds)
                        .eq(SysFlowTask::getApproverId, userId)
        );

        if (tasks.isEmpty()) {
            return;
        }

        // 3. 删除任务
        List<String> taskIds = tasks.stream().map(SysFlowTask::getTaskId).collect(Collectors.toList());
        taskMapper.deleteByIds(taskIds);

        // 4. 删除对应的流程实例（如果这些实例是为了DirectTodo创建的，通常是一对一）
        // 这里为了安全起见，只删除那些关联了被删任务的实例，且假设这些实例只服务于这些任务
        // 对于 DIRECT_TODO，实例和任务是一对一创建的
        Set<String> affectedInstanceIds = tasks.stream()
                .map(SysFlowTask::getInstanceId)
                .collect(Collectors.toSet());

        if (!affectedInstanceIds.isEmpty()) {
            instanceMapper.delete(
                    Wrappers.<SysFlowInstance>lambdaQuery()
                            .in(SysFlowInstance::getInstanceId, affectedInstanceIds)
            );
        }
    }

    @Override
    public SysFlowTask getTaskById(String taskId) {
        return taskMapper.selectById(taskId);
    }

    @Override
    public SysFlowInstance getInstanceByTaskId(String taskId) {
        SysFlowTask task = taskMapper.selectById(taskId);
        if (task == null) {
            return null;
        }
        return instanceMapper.selectById(task.getInstanceId());
    }

    @Override
    public List<String> getApproverIdsByInstance(String instanceId) {
        if (StrUtil.isBlank(instanceId)) {
            return Collections.emptyList();
        }
        List<SysFlowTask> tasks = taskMapper.selectList(
                new LambdaQueryWrapper<SysFlowTask>()
                        .eq(SysFlowTask::getInstanceId, instanceId)
        );
        if (CollUtil.isEmpty(tasks)) {
            return Collections.emptyList();
        }
        return tasks.stream()
                .map(SysFlowTask::getApproverId)
                .filter(StrUtil::isNotBlank)
                .distinct()
                .toList();
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void deleteTodosByInstanceIds(Collection<String> instanceIds) {
        if (CollUtil.isEmpty(instanceIds)) {
            return;
        }
        List<SysFlowInstance> instances = instanceMapper.selectList(
                Wrappers.<SysFlowInstance>lambdaQuery()
                        .in(SysFlowInstance::getInstanceId, instanceIds)
        );
        if (CollUtil.isEmpty(instances)) {
            return;
        }
        Set<String> idSet = instances.stream().map(SysFlowInstance::getInstanceId).collect(Collectors.toSet());
        taskMapper.delete(
                Wrappers.<SysFlowTask>lambdaQuery()
                        .in(SysFlowTask::getInstanceId, idSet)
        );
        Date now = new Date();
        for (SysFlowInstance ins : instances) {
            ins.setStatus(STATUS_TERMINATED);
            ins.setFinishTime(now);
            instanceMapper.updateById(ins);
        }
    }

    private LoginUser getLoginUser() {
        LoginUser loginUser;
        try {
            loginUser = LoginHelper.getLoginUser();
        } catch (Exception e) {
            return null;
        }
        return loginUser;
    }
}
