package com.hotent.project.manager.impl;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.core.toolkit.StringUtils;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.hotent.base.manager.impl.BaseManagerImpl;
import com.hotent.base.query.PageList;
import com.hotent.base.query.QueryFilter;
import com.hotent.base.util.AuthenticationUtil;
import com.hotent.base.util.StringUtil;
import com.hotent.baseInfo.manager.AuditedUnitManager;
import com.hotent.baseInfo.manager.CostCatalogManager;
import com.hotent.baseInfo.manager.CostDictDataManager;
import com.hotent.baseInfo.manager.CostDistrictManager;
import com.hotent.baseInfo.model.AuditedUnit;
import com.hotent.baseInfo.model.CostCatalog;
import com.hotent.baseInfo.model.CostDictData;
import com.hotent.baseInfo.model.CostDistrict;
import com.hotent.baseInfo.req.CostTaskSearchReq;
import com.hotent.constant.NodeConstant;
import com.hotent.constant.TaskStatusConstant;
import com.hotent.enterpriseDeclare.req.CostTaskPageReq;
import com.hotent.enterpriseDeclare.req.CostTaskReviewPageReq;
import com.hotent.project.dao.CostProjectTaskDao;
import com.hotent.project.manager.*;
import com.hotent.project.model.*;
import com.hotent.project.resp.CostProjectApprovalDetailResp;
import com.hotent.surveyinfo.manager.CostSurveyTemplateUploadManager;
import com.hotent.surveyinfo.model.CostSurveyTemplateUpload;
import com.hotent.sys.persistence.manager.DataDictManager;
import com.hotent.sys.persistence.model.DataDict;
import com.hotent.uc.api.model.IUser;
import com.hotent.uc.manager.OrgManager;
import com.hotent.uc.manager.UserManager;
import com.hotent.uc.model.Org;
import com.hotent.uc.model.User;
import com.hotent.uc.util.ContextUtil;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;
import java.time.LocalDateTime;
import java.util.*;
import java.util.stream.Collectors;

import static com.hotent.base.util.AuthenticationUtil.getCurrentUserMainOrgId;

/**
 * 项目任务表 服务实现类
 *
 * @author 超级管理员
 * @company 山西清众科技股份有限公司
 * @since 2025-10-03
 */
@Service
public class CostProjectTaskManagerImpl extends BaseManagerImpl<CostProjectTaskDao, CostProjectTask> implements CostProjectTaskManager {


    @Autowired
    private CostDistrictManager costDistrictManager;

    @Autowired
    private CostProjectTaskProccessManager costProjectTaskProccessManager;

    @Autowired
    private CostProjectTaskManager costProjectTaskManager;

    @Autowired
    private CostNoticeManager costNoticeManager;

    @Resource
    DataDictManager dataDictManager;

    @Autowired
    private CostProjectApprovalManager costProjectApprovalManager;

    @Autowired
    private CostProjectTaskPreliminaryOpinionManager preliminaryOpinionManager;


    @Autowired
    private CostProjectTaskApprovalManager costProjectTaskApprovalManager;

    @Autowired
    private CostProjectProccessNodeManager costProjectProccessNodeManager;

    @Autowired
    private CostProjectProccessManager costProjectProccessManager;
    @Autowired
    private CostProjectTaskMaterialManager costProjectTaskMaterialManager;

    @Autowired
    private CostSurveyTemplateUploadManager costSurveyTemplateUploadManager;

    @Autowired
    private CostProjectTaskNodeManager costProjectTaskNodeManager;

    @Autowired
    private OrgManager orgManager;

    @Autowired
    private CostCatalogManager costCatalogManager;

    @Autowired
    private AuditedUnitManager auditedUnitManager;

    @Autowired
    private CostProjectTaskMaterialSummaryManager costProjectTaskMaterialSummaryManager;

    @Autowired
    private com.hotent.project.service.AsyncMaterialSummaryService asyncMaterialSummaryService;


    @Override
    public List<CostProjectTask> getTaskList(CostTaskSearchReq req) throws Exception {
        // 获取当前用户
        IUser currentUser = ContextUtil.getCurrentUser();
        String currentUserId = currentUser.getUserId();

        // 1. 先查询当前用户有权限的立项（负责人或项目组成员）
        LambdaQueryWrapper<CostProjectApproval> approvalQueryWrapper = new LambdaQueryWrapper<>();
        approvalQueryWrapper.eq(CostProjectApproval::getIsDeleted, "0");
        approvalQueryWrapper.and(wrapper -> wrapper
                .eq(CostProjectApproval::getLeaderId, currentUserId)
                .or(projectMembersWrapper -> {
                    projectMembersWrapper.like(CostProjectApproval::getProjectMembers, currentUserId);
                })
        );

        List<CostProjectApproval> accessibleApprovals = costProjectApprovalManager.list(approvalQueryWrapper);
        // 如果没有权限的立项，返回空结果
        if (accessibleApprovals.isEmpty()) {
            return new ArrayList<>();
        }
        // 提取有权限的立项ID列表
        List<String> accessibleProjectIds = accessibleApprovals.stream()
                .map(CostProjectApproval::getProjectId)
                .distinct()
                .collect(java.util.stream.Collectors.toList());

        // 2. 构建任务查询条件
        LambdaQueryWrapper<CostProjectTask> queryWrapper = new LambdaQueryWrapper<>();

        // 查询未删除的记录
        queryWrapper.eq(CostProjectTask::getIsDeleted, "0");

        // 只查询当前用户有权限的立项对应的任务
        queryWrapper.in(CostProjectTask::getProjectId, accessibleProjectIds);

        // 按创建时间倒序排列
        queryWrapper.orderByDesc(CostProjectTask::getCreateTime);

        return costProjectTaskManager.list(queryWrapper);
    }

    /**
     * 计算任务预警状态
     *
     * @param task 任务对象
     * @return 预警状态：green-绿色预警(在办理期限内) yellow-黄色预警(超过环节期限但没超过流程期限) red-红色预警(超过流程期限)
     */
    private String calculateWarningStatus(CostProjectTask task) {
        // 获取任务对应的流程信息
        CostProjectTaskProccess process = costProjectTaskProccessManager.getOne(
                new LambdaQueryWrapper<CostProjectTaskProccess>()
                        .eq(CostProjectTaskProccess::getTaskId, task.getId())
        );

        if (process == null) {
            return "green"; // 默认绿色预警
        }

        // 获取当前环节的节点信息
        CostProjectTaskNode currentNode = costProjectTaskNodeManager.getOne(
                new LambdaQueryWrapper<CostProjectTaskNode>()
                        .eq(CostProjectTaskNode::getTaskId, task.getId())
                        .eq(CostProjectTaskNode::getProcessNodeKey, task.getCurrentNode())
        );

        // 获取当前时间
        LocalDateTime now = LocalDateTime.now();

        // 1. 如果超过流程期限，红色预警
        if (process.getPlannedAuditEndDate() != null &&
                now.toLocalDate().isAfter(process.getPlannedAuditEndDate())) {
            return "red";
        }

        // 2. 如果当前环节有截止时间且已超过，但未超过流程期限，黄色预警
        if (currentNode != null && currentNode.getEndTime() != null &&
                now.isAfter(currentNode.getEndTime())) {
            // 检查是否超过流程期限
            if (process.getPlannedAuditEndDate() != null &&
                    now.toLocalDate().isAfter(process.getPlannedAuditEndDate())) {
                return "red"; // 超过流程期限，红色预警
            } else {
                return "yellow"; // 超过环节期限但未超过流程期限，黄色预警
            }
        }

        // 3. 默认绿色预警（在办理期限内）
        return "green";
    }

    @Override
    public IPage<CostProjectTask> pageListForReviewTask(CostTaskReviewPageReq req) throws Exception {
        // 获取当前用户
        IUser currentUser = ContextUtil.getCurrentUser();
        String currentUserId = currentUser.getUserId();

        // 1. 先查询当前用户有权限的立项（负责人或项目组成员）
        LambdaQueryWrapper<CostProjectApproval> approvalQueryWrapper = new LambdaQueryWrapper<>();
        approvalQueryWrapper.eq(CostProjectApproval::getIsDeleted, "0");
        approvalQueryWrapper.and(wrapper -> wrapper
                .eq(CostProjectApproval::getLeaderId, currentUserId)
                .or(projectMembersWrapper -> {
                    projectMembersWrapper.like(CostProjectApproval::getProjectMembers, currentUserId);
                })
        );


        if (StringUtil.isNotEmpty(req.getAuditedUnitName())) {
            approvalQueryWrapper.like(CostProjectApproval::getAuditedUnitName,req.getAuditedUnitName());
        }
        if (StringUtil.isNotEmpty(req.getAuditedUnitId())) {
            approvalQueryWrapper.like(CostProjectApproval::getAuditedUnitId,req.getAuditedUnitId());
        }
        if (StringUtil.isNotEmpty(req.getProjectName())) {
            approvalQueryWrapper.like(CostProjectApproval::getProjectName,req.getProjectName());
        }
        if (StringUtil.isNotEmpty(req.getEndYear()) && StringUtil.isNotEmpty(req.getStartYear())) {
            List<String> years = new ArrayList<>();
            int startYear =Integer.parseInt(req.getStartYear());
            int endYear =Integer.parseInt(req.getEndYear());
            for (int year = startYear; year <=endYear; year++) {
                years.add(String.valueOf(year));
            }
            String sql = "(" +
                    years.stream()
                            .map(y -> "FIND_IN_SET('" + y + "', audit_period) > 0")
                            .collect(Collectors.joining(" OR ")) +
                    ")";

            approvalQueryWrapper.apply(sql);

        }


        List<CostProjectApproval> accessibleApprovals = costProjectApprovalManager.list(approvalQueryWrapper);

        // 如果没有权限的立项，返回空结果
        if (accessibleApprovals.isEmpty()) {
            return new Page<>(req.getPageNum(), req.getPageSize());
        }


        // 提取有权限的立项ID列表
        List<String> accessibleProjectIds = accessibleApprovals.stream()
                .map(CostProjectApproval::getProjectId)
                .distinct()
                .collect(java.util.stream.Collectors.toList());

        if (StringUtil.isNotEmpty(req.getAreaCode())) {
            List<CostProjectTaskApproval> list = costProjectTaskApprovalManager.list(
                    new LambdaQueryWrapper<CostProjectTaskApproval>().eq(CostProjectTaskApproval::getAreaCode, req.getAreaCode())
            );
            if (list.isEmpty()) {
                return new Page<>(req.getPageNum(), req.getPageSize());
            }
            List<String> projectIds =
                    list.stream().map(CostProjectTaskApproval::getProjectId).collect(Collectors.toList());
            accessibleProjectIds.addAll(projectIds);
        }

        // 2. 构建任务查询条件
        LambdaQueryWrapper<CostProjectTask> queryWrapper = new LambdaQueryWrapper<>();

        // 查询未删除的记录
        queryWrapper.eq(CostProjectTask::getIsDeleted, "0");

        // 查询根任务（pid为0）
        queryWrapper.eq(CostProjectTask::getPid, "0");

        // 只查询当前用户有权限的立项对应的任务
        queryWrapper.in(CostProjectTask::getProjectId, accessibleProjectIds);

        // 根据请求参数添加查询条件
        if (StringUtil.isNotEmpty(req.getProjectName())) {
            queryWrapper.like(CostProjectTask::getProjectName, req.getProjectName());
        }
        if (StringUtil.isNotEmpty(req.getAuditedUnitName())) {
            queryWrapper.like(CostProjectTask::getAuditedUnitName, req.getAuditedUnitName());
        }
        if (StringUtil.isNotEmpty(req.getStatus())) {
            queryWrapper.eq(CostProjectTask::getStatus, req.getStatus());
        }
        if (StringUtil.isNotEmpty(req.getYear())) {
            queryWrapper.eq(CostProjectTask::getYear, req.getYear());
        }
        if (StringUtil.isNotEmpty(req.getIsGd())) {
            queryWrapper.eq(CostProjectTask::getIsGd, req.getIsGd());
        }
        if (StringUtil.isNotEmpty(req.getArchiveNo())) {
            queryWrapper.eq(CostProjectTask::getArchiveNo, req.getArchiveNo());
        }
        if (StringUtil.isNotEmpty(req.getCurrentNode())) {
            queryWrapper.eq(CostProjectTask::getCurrentNode, req.getCurrentNode());
        }
        if (StringUtil.isNotEmpty(req.getNCurrentNode())) {
            queryWrapper.ne(CostProjectTask::getCurrentNode, req.getNCurrentNode());
        }
        if (StringUtil.isNotEmpty(req.getNStatus())) {
            queryWrapper.ne(CostProjectTask::getStatus, req.getNStatus());
        }
        // 按创建时间倒序排列
        queryWrapper.orderByDesc(CostProjectTask::getCreateTime);

        Page<CostProjectTask> page = new Page<>(req.getPageNum(), req.getPageSize());
        IPage<CostProjectTask> result = costProjectTaskManager.page(page, queryWrapper);

        List<CostProjectTask> rootList = result.getRecords();
        if (rootList == null || rootList.isEmpty()) {
            return result;
        }



        List<String> rootIds = rootList.stream()
                .map(CostProjectTask::getId)
                .collect(Collectors.toList());
        List<CostProjectTask> allChildTasks = costProjectTaskManager.list(
                new LambdaQueryWrapper<CostProjectTask>()
                        .in(CostProjectTask::getPid, rootIds)
                        .eq(CostProjectTask::getIsDeleted, "0")
                        .orderByAsc(CostProjectTask::getOrderNum)
        );
        Map<String, List<CostProjectTask>> childGroup =
                allChildTasks.stream()
                        .collect(Collectors.groupingBy(CostProjectTask::getPid));
        Set<String> allProjectIds = new HashSet<>();
        rootList.forEach(t -> allProjectIds.add(t.getProjectId()));
        allChildTasks.forEach(t -> allProjectIds.add(t.getProjectId()));
        List<CostProjectApproval> approvalList = costProjectApprovalManager.list(
                new LambdaQueryWrapper<CostProjectApproval>()
                        .in(CostProjectApproval::getProjectId, allProjectIds)
        );
        Map<String, CostProjectApproval> approvalMap =
                approvalList.stream().collect(
                        Collectors.toMap(CostProjectApproval::getProjectId, v -> v)
                );
        List<String> list = rootList.stream().map(CostProjectTask::getAuditType).distinct().collect(Collectors.toList());
        //List<CostDictData> costDictDatas= costDictDataManager.getValueByDictType(list,null,"sys_audit_type");

        QueryWrapper<DataDict> wrapper = new QueryWrapper<>();
        wrapper.eq("TYPE_ID_","1970328589832323072");
        wrapper.in("KEY_",list);
        List<DataDict>  costDictDatas= dataDictManager.list(wrapper);
        List<String> collect = accessibleApprovals.stream().map(CostProjectApproval::getOrgId).distinct().collect(Collectors.toList());
        List<Org> orgs = orgManager.getOrgByIds(collect);
        for (CostProjectTask rootTask : rootList) {
            costDictDatas.stream()
                    .filter(c -> rootTask.getAuditType() != null &&
                            rootTask.getAuditType().equals(String.valueOf(c.getKey())))
                    .findAny().ifPresent(costDictData -> rootTask.setAuditTypeName(costDictData.getName()));
            // 根任务状态
            rootTask.setStatusName(TaskStatusConstant.getStatusNameByCode(rootTask.getStatus()));
            rootTask.setCurrentNodeName(NodeConstant.getNodeValueByKey(rootTask.getCurrentNode()));
            rootTask.setWarningStatus(calculateWarningStatus(rootTask));
            // 设置目录
            CostProjectApproval rootDetail = approvalMap.get(rootTask.getProjectId());
            if (rootDetail != null) {

                orgs.stream()
                        .filter(c -> rootDetail.getOrgId() != null &&
                                rootDetail.getOrgId().equals(c.getId()))
                        .findAny().ifPresent(costDictData -> rootTask.setOrgName(costDictData.getName()));


                rootTask.setCatalogId(rootDetail.getCatalogId());
                if (StringUtil.isNotEmpty(rootDetail.getAreaCode())) {
                    CostDistrict district = costDistrictManager.getOne(
                            new LambdaQueryWrapper<CostDistrict>()
                                    .eq(CostDistrict::getCode, rootDetail.getAreaCode())
                    );
                    rootTask.setAreaName(district != null ? district.getName() : "山西省");
                }
            }
            // 子任务
            List<CostProjectTask> childTasks =
                    childGroup.getOrDefault(rootTask.getId(), Collections.emptyList());
            for (CostProjectTask childTask : childTasks) {
                childTask.setStatusName(TaskStatusConstant.getStatusNameByCode(childTask.getStatus()));
                CostProjectApproval detail = approvalMap.get(childTask.getProjectId());
                if (detail != null) {
                    childTask.setCatalogId(detail.getCatalogId());
                }
            }
            rootTask.setChildTasks(childTasks);
        }

        return result;

    }


    @Override
    @Transactional
    public void createOrUpdate(CostProjectTask costProjectTask) {
        //新建或更新
        this.saveOrUpdate(costProjectTask);
    }

    @Override
    @Transactional
    public String saveTask(CostTaskPageReq costTaskPageReq) {
        // 1.校验内容是否填写完毕！t
        List<CostProjectTaskMaterial> costProjectTaskMaterials = costProjectTaskMaterialManager.listByTaskId(costTaskPageReq.getTaskId());
        boolean c = costProjectTaskMaterials.stream()
                .filter(item -> "1".equals(item.getIsRequired()))
                .allMatch(
                        item -> "1".equals(item.getIsUpload())
                );
        if (!c) {
            throw new RuntimeException("报送资料必填文件未全部填写完成！");
        }
        List<CostSurveyTemplateUpload> costSurveyTemplateUploads = costSurveyTemplateUploadManager.listByTaskId(costTaskPageReq.getTaskId());
        boolean d = costSurveyTemplateUploads.stream()
                .filter(item -> "1".equals(item.getIsRequired()))
                .allMatch(
                        item -> "1".equals(item.getIsUpload())
                );
        if (!d) {
            throw new RuntimeException("成本调查必填文件未全部填写完成！");
        }
        // 2. 子流程状态改为审核中
        CostProjectTask task = this.getById(costTaskPageReq.getTaskId());
        String currentNode = task.getCurrentNode();

        // 如果当前节点不是tjcl，则保持当前节点不变，只修改状态
        if (!"tjcl".equals(currentNode)) {
            task.setStatus(TaskStatusConstant.AUDITING.getStatusCode());
        } else {
            task.setCurrentNode(NodeConstant.clcs.getNodeKey());
            task.setStatus(TaskStatusConstant.AUDITING.getStatusCode());
            CostProjectTask parentTask = this.getById(task.getPid());
            String parentCurrentNode = parentTask.getCurrentNode();
            parentTask.setCurrentNode(NodeConstant.clcs.getNodeKey());
            parentTask.setStatus(TaskStatusConstant.AUDITING.getStatusCode());
            this.updateById(parentTask);
        }
        this.updateById(task);

        // 发送通知
        String title = NodeConstant.getNodeValueByKey(task.getCurrentNode()) + "材料已提交";
        // 操作人
        String content = "[" + NodeConstant.getNodeValueByKey(task.getCurrentNode()) + "]" + AuthenticationUtil.getCurrentUserFullname() + "材料已提交" + task.getAuditedUnitName() + "的项目(" + task.getProjectName() + ")";
        String enterpriseId = task.getAuditedUnitId() == null ? "" : task.getAuditedUnitId();
        String orgId = getCurrentUserMainOrgId();
        Org org = orgManager.getById(orgId);
        String noticeSource = (org.getName()) + " " + AuthenticationUtil.getCurrentUserFullname();
        String sendTarget = task.getCreateBy() == null ? "" : task.getCreateBy();
        costNoticeManager.sendNotice(task.getProjectId(), task.getId(), "1", title, content, enterpriseId, noticeSource, sendTarget);

        return "任务提交成功";
    }

    @Override
    public String saveYjTask(CostProjectTaskPreliminaryOpinion costProjectTaskPreliminaryOpinion) {
        // 1.校验内容是否填写完毕！todo

        preliminaryOpinionManager.createOrUpdate(costProjectTaskPreliminaryOpinion);
        // 2. 子流程状态改为已反馈
        CostProjectTask task = this.getById(costProjectTaskPreliminaryOpinion.getTaskId());
        task.setStatus(TaskStatusConstant.FEEDBACKED.getStatusCode());
        this.updateById(task);
        // 发送通知
        String title = NodeConstant.getNodeValueByKey(task.getCurrentNode()) + "意见已反馈";
        // 操作人
        String content = "[" + NodeConstant.getNodeValueByKey(task.getCurrentNode()) + "]" + AuthenticationUtil.getCurrentUserFullname() + "意见已反馈" + task.getAuditedUnitName() + "的项目(" + task.getProjectName() + ")";
        String enterpriseId = task.getAuditedUnitId() == null ? "" : task.getAuditedUnitId();
        String orgId = getCurrentUserMainOrgId();
        Org org = orgManager.getById(orgId);
        String noticeSource = (org.getName()) + " " + AuthenticationUtil.getCurrentUserFullname();
        String sendTarget = task.getCreateBy() == null ? "" : task.getCreateBy();
        costNoticeManager.sendNotice(task.getProjectId(), task.getId(), "1", title, content, enterpriseId, noticeSource, sendTarget);
        return "意见反馈完成";

    }

    @Override
    public String doProcessBtn(CostTaskPageReq req) {

        CostProjectTask task = costProjectTaskManager.getById(req.getTaskId());
        String resultMessage = "";
        switch (req.getKey()) {
            case "1":
                // 补充材料
                resultMessage = supplementMaterial(task, req);
                break;
            case "2":
                // 中止/恢复
                resultMessage = suspendTask(task, req);
                break;
            case "3":
                // 通过
                resultMessage = completeTask(task);
                break;
            case "4":
                // 退回
                resultMessage = returnToSubmit(task, req);
                break;
            case "5":
                // 催办
                resultMessage = remindTask(task, req);
                break;
            case "6":
                // 退回上一步
                resultMessage = backPreToSubmit(task, req);
                break;
            case "7":
                // 扭转下一步
                resultMessage = toNextSubmit(task, req);
                break;
            case "8":
                // 复核
                resultMessage = reviewTask(task, req);
                break;
            case "10":
                // 催报
                resultMessage = remindUnitTask(task, req);
                break;
            case "9":
                // 归档(没有这个东西)
                resultMessage = archiveTask(task, req);
                break;

            default:
                return "未知的操作类型";
        }
        return resultMessage;
    }

    /**
     * 通过，填写原因 修改状态
     */
    private String completeTask(CostProjectTask task) {
        CostProjectTask nTask = costProjectTaskManager.getById(task.getId());
        if (!"0".equals(task.getPid())) {
            // 子任务 所有“是否必填”为“是”的资料“初审结果”均为“通过”.
            List<CostProjectTaskMaterial> costProjectTaskMaterials = costProjectTaskMaterialManager.listByTaskId(nTask.getId());
            boolean c = costProjectTaskMaterials.stream()
                    .filter(item -> "1".equals(item.getIsRequired()) && "1".equals(item.getIsUpload()))
                    .allMatch(
                            item -> "1".equals(item.getAuditedStatus())
                    );
            if (!c) {
                throw new RuntimeException("报送资料未全部通过！");
            }
            List<CostSurveyTemplateUpload> costSurveyTemplateUploads = costSurveyTemplateUploadManager.listByTaskId(nTask.getId());
            boolean d = costSurveyTemplateUploads.stream()
                    .filter(item -> "1".equals(item.getIsRequired()) && "1".equals(item.getIsUpload()))
                    .allMatch(
                            item -> "1".equals(item.getAuditedStatus())
                    );
            if (!d) {
                throw new RuntimeException("成本调查表未全部通过！");
            }
        } else {
            List<CostProjectTask> children = costProjectTaskManager.list(
                    new LambdaQueryWrapper<CostProjectTask>()
                            .eq(CostProjectTask::getPid, nTask.getId())
            );
            // 主任务：检查所有非中止的子任务是否都已办结
            boolean allChildrenCompleted = children.stream()
                    .filter(child -> !TaskStatusConstant.SUSPENDED.getStatusCode().equals(child.getStatus()))
                    .allMatch(child -> TaskStatusConstant.COMPLETED.getStatusCode().equals(child.getStatus()));
            if (!allChildrenCompleted) {
                throw new RuntimeException("子任务未全部办结，主任务无法办结");
            }
        }
        task.setStatus(TaskStatusConstant.COMPLETED.getStatusCode());
        costProjectTaskManager.updateById(task);

        // 发送通知
        String title = NodeConstant.getNodeValueByKey(task.getCurrentNode()) + "通过";
        // 操作人
        String content = "[" + NodeConstant.getNodeValueByKey(task.getCurrentNode()) + "]" + AuthenticationUtil.getCurrentUserFullname() + "已通过" + task.getAuditedUnitName() + "的项目(" + task.getProjectName() + ")";
        String enterpriseId = task.getAuditedUnitId() == null ? "" : task.getAuditedUnitId();
        String orgId = getCurrentUserMainOrgId();
        Org org = orgManager.getById(orgId);
        String noticeSource = (org.getName()) + " " + AuthenticationUtil.getCurrentUserFullname();
        String sendTarget = task.getCreateBy() == null ? "" : task.getCreateBy();
        costNoticeManager.sendNotice(task.getProjectId(), task.getId(), "1", title, content, enterpriseId, noticeSource, sendTarget);
        return title;
    }

    /**
     * 退回，只修改状态为不通过，不修改节点（子任务操作）
     */
    private String returnToSubmit(CostProjectTask task, CostTaskPageReq req) {
        if ("0".equals(task.getPid())) {
            return "仅支持子任务进行此操作！";
        }
        // 通知内容组装
        String title = NodeConstant.getNodeValueByKey(task.getCurrentNode()) + "退回";
        String enterpriseId = task.getAuditedUnitId() == null ? "" : task.getAuditedUnitId();
        String orgId = getCurrentUserMainOrgId();
        Org org = orgManager.getById(orgId);
        String noticeSource = (org.getName()) + " " + AuthenticationUtil.getCurrentUserFullname();
        String sendTarget = task.getCreateBy() == null ? "" : task.getCreateBy();

        String content = "[" + NodeConstant.getNodeValueByKey(task.getCurrentNode()) + "]" + AuthenticationUtil.getCurrentUserFullname() + "已退回" + task.getAuditedUnitName() + "的项目(" + task.getProjectName() + ")";
        if (StringUtil.isNotEmpty(req.getContent())) {
            content += "，原因：" + req.getContent();
        }
        costNoticeManager.sendNotice(task.getProjectId(), task.getId(), "1", title, content, enterpriseId, noticeSource, sendTarget);

        task.setStatus(TaskStatusConstant.NOT_PASSED.getStatusCode());
        costProjectTaskManager.updateById(task);

        return title;
    }

    /**
     * 中止/恢复，如果是主任务中止，所有子任务同步中止；如果是主任务恢复，所有子任务同步恢复
     */
    private String suspendTask(CostProjectTask task, CostTaskPageReq req) {
        // 判断是中止还是恢复
        String status = req.getStatus() == null || TaskStatusConstant.SUSPENDED.getStatusCode().equals(req.getStatus()) ? TaskStatusConstant.SUSPENDED.getStatusCode() : TaskStatusConstant.AUDITING.getStatusCode();

        // 如果是主任务 同步所有子任务的中止/恢复状态
        if ("0".equals(task.getPid())) {
            List<CostProjectTask> children = costProjectTaskManager.list(
                    new LambdaQueryWrapper<CostProjectTask>()
                            .eq(CostProjectTask::getPid, task.getId())
                            .eq(CostProjectTask::getIsDeleted, "0")
            );
            for (CostProjectTask child : children) {
                child.setStatus(status);
                costProjectTaskManager.updateById(child);
            }
        }
        // 更新任务状态
        task.setStatus(status);
        costProjectTaskManager.updateById(task);

        // 通知内容组装
        String title = NodeConstant.getNodeValueByKey(task.getCurrentNode()) + TaskStatusConstant.getStatusNameByCode(status);
        String content = "[" + NodeConstant.getNodeValueByKey(task.getCurrentNode()) + "]" + AuthenticationUtil.getCurrentUserFullname() + "已" + TaskStatusConstant.getStatusNameByCode(status) + task.getAuditedUnitName() + "的项目(" + task.getProjectName() + ")";
        if (StringUtil.isNotEmpty(req.getContent())) {
            content += "，原因：" + req.getContent();
        }
        String enterpriseId = task.getAuditedUnitId() == null ? "" : task.getAuditedUnitId();
        String orgId = getCurrentUserMainOrgId();
        Org org = orgManager.getById(orgId);
        String noticeSource = (org.getName()) + " " + AuthenticationUtil.getCurrentUserFullname();
        String sendTarget = task.getCreateBy() == null ? "" : task.getCreateBy();
        costNoticeManager.sendNotice(task.getProjectId(), task.getId(), "1", title, content, enterpriseId, noticeSource, sendTarget);
        return title;
    }

    /**
     * 补充材料，发送通知+修改任务状态
     */
    private String supplementMaterial(CostProjectTask task, CostTaskPageReq req) {
        String currentNode = task.getCurrentNode();
        String title = NodeConstant.getNodeValueByKey(currentNode) + TaskStatusConstant.BCCL.getStatusName();
        String orgId = getCurrentUserMainOrgId();
        Org org = orgManager.getById(orgId);
        String noticeSource = (org.getName()) + " " + AuthenticationUtil.getCurrentUserFullname();
        switch (currentNode) {
            // 集体审议节点：支持指定多个子任务补充材料
            case "jtsy":
                if (StringUtil.isNotEmpty(req.getAuditedUnitIds())) {
                    String[] childUnitIds = req.getAuditedUnitIds().split(",");
                    List<String> unitNames = new java.util.ArrayList<>();

                    for (String auditedUnitId : childUnitIds) {
                        CostProjectTask childTask = costProjectTaskManager.getOne(
                                new LambdaQueryWrapper<CostProjectTask>()
                                        .eq(CostProjectTask::getPid, task.getId())
                                        .eq(CostProjectTask::getAuditedUnitId, auditedUnitId)
                        );
                        if (childTask == null) {
                            throw new RuntimeException("未知的子任务");
                        }
                        // 检查子任务是否已中止
                        if (TaskStatusConstant.SUSPENDED.getStatusCode().equals(childTask.getStatus())) {
                            throw new RuntimeException("子任务已中止，无法补充材料：" + childTask.getAuditedUnitName());
                        }
                        // 更新子任务状态为补充材料
                        childTask.setStatus(TaskStatusConstant.BCCL.getStatusCode());
                        costProjectTaskManager.updateById(childTask);
                        // 通知内容组装（针对子任务对应的单位）
                        String childContent = "[" + NodeConstant.getNodeValueByKey(task.getCurrentNode()) + "]" + AuthenticationUtil.getCurrentUserFullname() + "要求" + childTask.getAuditedUnitName() + "补充材料，项目(" + task.getProjectName() + ")";
                        String childEnterpriseId = childTask.getAuditedUnitId() == null ? "" : childTask.getAuditedUnitId();
                        String childSendTarget = childTask.getCreateBy() == null ? "" : childTask.getCreateBy();
                        costNoticeManager.sendNotice(task.getProjectId(), task.getId(), "1", title, childContent, childEnterpriseId, noticeSource, childSendTarget);
                        // 收集单位名称
                        if (StringUtil.isNotEmpty(childTask.getAuditedUnitName())) {
                            unitNames.add(childTask.getAuditedUnitName());
                        }
                    }
                    // 返回结果，包含所有单位名称
                    String unitNamesStr = unitNames.isEmpty() ? "" : String.join("、", unitNames);
                    return title + "（单位：" + unitNamesStr + "）";
                }
            default:
                // 检查任务是否已中止
                if (TaskStatusConstant.SUSPENDED.getStatusCode().equals(task.getStatus())) {
                    throw new RuntimeException("任务已中止，无法补充材料");
                }
                task.setStatus(TaskStatusConstant.BCCL.getStatusCode());
                costProjectTaskManager.updateById(task);
                String content = "[" + NodeConstant.getNodeValueByKey(task.getCurrentNode()) + "]" + AuthenticationUtil.getCurrentUserFullname() + "要求" + task.getAuditedUnitName() + "补充材料，项目(" + task.getProjectName() + ")";
                String enterpriseId = task.getAuditedUnitId() == null ? "" : task.getAuditedUnitId();
                String sendTarget = task.getCreateBy() == null ? "" : task.getCreateBy();
                costNoticeManager.sendNotice(task.getProjectId(), task.getId(), "1", title, content, enterpriseId, noticeSource, sendTarget);
                return title;
        }
    }

    /**
     * 退回上一步，修改状态和节点（主任务操作，子任务同步节点流转）
     */
    private String backPreToSubmit(CostProjectTask task, CostTaskPageReq req) {
        CostProjectTask nTask = costProjectTaskManager.getById(task.getId());
        if (!"0".equals(task.getPid())) {
            return "仅支持主任务进行此操作";
        }
        // 获取退回后的上一节点
        NodeConstant prevNode = NodeConstant.getPrevNode(nTask.getCurrentNode());
        if (prevNode == null) {
            throw new RuntimeException("当前节点已是第一步，无法退回");
        }
        String prevNodeStatus = prevNode.getNodeKey();

        // 更新流程节点时间：清空当前节点的结束时间，重置上一节点的开始时间
        CostProjectProccess proccess = costProjectProccessManager.getOne(
                new LambdaQueryWrapper<CostProjectProccess>().eq(CostProjectProccess::getProjectId, task.getProjectId())
        );

        // 清空当前节点的实际结束时间和操作信息
        CostProjectProccessNode currentNode = costProjectProccessNodeManager.getOne(
                new LambdaQueryWrapper<CostProjectProccessNode>()
                        .eq(CostProjectProccessNode::getProcessId, proccess.getProcessId())
                        .eq(CostProjectProccessNode::getProcessNodeKey, task.getCurrentNode())
        );
        if (currentNode != null) {
            currentNode.setActEndTime(null);
            currentNode.setActUserIds(null);
            currentNode.setActUserNames(null);
            currentNode.setActRemarks(null);
            costProjectProccessNodeManager.updateById(currentNode);
        }

        // 重置上一节点的开始时间
        CostProjectProccessNode prevNodeObj = costProjectProccessNodeManager.getOne(
                new LambdaQueryWrapper<CostProjectProccessNode>()
                        .eq(CostProjectProccessNode::getProcessId, proccess.getProcessId())
                        .eq(CostProjectProccessNode::getProcessNodeKey, prevNodeStatus)
        );
        if (prevNodeObj != null) {
            prevNodeObj.setActStartTime(LocalDateTime.now());
            costProjectProccessNodeManager.updateById(prevNodeObj);
        }

        // 主任务退回上一步，重置归档状态
        nTask.setStatus(TaskStatusConstant.AUDITING.getStatusCode());
        nTask.setCurrentNode(prevNodeStatus);
        nTask.setIsGd("0");
        costProjectTaskManager.updateById(nTask);

        // 子任务同步节点流转，并根据退回后的节点设置正确的状态
        List<CostProjectTask> children = costProjectTaskManager.list(
                new LambdaQueryWrapper<CostProjectTask>()
                        .eq(CostProjectTask::getPid, nTask.getId())
                        .eq(CostProjectTask::getIsDeleted, "0")
        );

        // 根据退回后的节点，设置子任务状态
        String childStatus = "";
        switch (prevNodeStatus) {
            case "yjfk":
                childStatus = TaskStatusConstant.WAIT_FEEDBACK.getStatusCode();
                break;
            case "jtsy":
            case "cjbg":
            case "gd":
                childStatus = TaskStatusConstant.COMPLETED.getStatusCode();
                break;
            default:
                childStatus = TaskStatusConstant.AUDITING.getStatusCode();
                break;
        }

        // 同步所有非中止状态的子任务
        for (CostProjectTask child : children) {
            if (!child.getStatus().equals(TaskStatusConstant.SUSPENDED.getStatusCode())) {
                child.setStatus(childStatus);
                child.setCurrentNode(prevNodeStatus);
                costProjectTaskManager.updateById(child);

                // 如果退回到意见反馈节点，通知企业
                if ("yjfk".equals(prevNodeStatus) && StringUtil.isNotEmpty(child.getAuditedUnitId())) {
                    AuditedUnit auditedUnit = auditedUnitManager.getOne(
                            new LambdaQueryWrapper<AuditedUnit>()
                                    .eq(AuditedUnit::getUnitId, child.getAuditedUnitId())
                                    .eq(AuditedUnit::getIsDeleted, "0")
                    );
                    if (auditedUnit != null && StringUtil.isNotEmpty(auditedUnit.getAccount())) {
                        String noticeTitle = "意见反馈通知";
                        String noticeContent = "您的项目(" + child.getProjectName() + ")需要反馈意见，请及时处理";
                        String orgId = getCurrentUserMainOrgId();
                        Org org = orgManager.getById(orgId);
                        String noticeSource = (org != null ? org.getName() : "系统") + " " + AuthenticationUtil.getCurrentUserFullname();
                        costNoticeManager.sendNotice(
                                child.getProjectId(),
                                child.getId(),
                                "1",
                                noticeTitle,
                                noticeContent,
                                child.getAuditedUnitId(),
                                noticeSource,
                                auditedUnit.getAccount()
                        );
                    }
                }
            }
        }

        // 通知内容组装
        String title = "已退回至" + NodeConstant.getNodeValueByKey(prevNodeStatus);
        String enterpriseId = task.getAuditedUnitId() == null ? "" : task.getAuditedUnitId();
        String orgId = getCurrentUserMainOrgId();
        Org org = orgManager.getById(orgId);
        String noticeSource = (org.getName()) + " " + AuthenticationUtil.getCurrentUserFullname();
        String sendTarget = task.getCreateBy() == null ? "" : task.getCreateBy();
        String content = "[" + NodeConstant.getNodeValueByKey(task.getCurrentNode()) + "]已退回至[" + NodeConstant.getNodeValueByKey(prevNodeStatus) + "]，" + task.getProjectName();
        if (StringUtil.isNotEmpty(req.getContent())) {
            content += "，原因：" + req.getContent();
        }
        costNoticeManager.sendNotice(task.getProjectId(), task.getId(), "1", title, content, enterpriseId, noticeSource, sendTarget);
        return title;
    }

    /**
     * 扭转下一步，修改状态和节点（主任务操作，子任务同步节点流转）
     * 自动完成办结操作并扭转到下一步
     */
    private String toNextSubmit(CostProjectTask task, CostTaskPageReq req) {
        CostProjectTask nTask = costProjectTaskManager.getById(task.getId());
        if (!"0".equals(task.getPid())) {
            return "仅支持主任务进行此操作";
        }

        // 获取下一节点
        NodeConstant nextNode = NodeConstant.getNextNode(nTask.getCurrentNode());
        if (nextNode == null) {
            throw new RuntimeException("当前节点已是最后一步，无法扭转");
        }
        String nextNodeStatus = nextNode.getNodeKey();

        // 获取所有子任务
        List<CostProjectTask> children = costProjectTaskManager.list(
                new LambdaQueryWrapper<CostProjectTask>()
                        .eq(CostProjectTask::getPid, nTask.getId())
                        .eq(CostProjectTask::getIsDeleted, "0")
        );

        // 检查所有非中止的子任务是否都已办结
        boolean allChildrenCompleted = children.stream()
                .filter(child -> !TaskStatusConstant.SUSPENDED.getStatusCode().equals(child.getStatus()))
                .allMatch(child -> TaskStatusConstant.COMPLETED.getStatusCode().equals(child.getStatus()));
        if (!allChildrenCompleted) {
            throw new RuntimeException("子任务未全部办结，主任务无法扭转");
        }

        // 先完成当前节点的办结操作（如果未办结）
        if (!nTask.getStatus().equals(TaskStatusConstant.COMPLETED.getStatusCode())) {
            nTask.setStatus(TaskStatusConstant.COMPLETED.getStatusCode());
            costProjectTaskManager.updateById(nTask);
        }

        // 修改当前节点的结束时间
        CostProjectProccess proccess = costProjectProccessManager.getOne(
                new LambdaQueryWrapper<CostProjectProccess>().eq(CostProjectProccess::getProjectId, task.getProjectId())
        );
        CostProjectProccessNode one = costProjectProccessNodeManager.getOne(
                new LambdaQueryWrapper<CostProjectProccessNode>()
                        .eq(CostProjectProccessNode::getProcessId, proccess.getProcessId())
                        .eq(CostProjectProccessNode::getProcessNodeKey, task.getCurrentNode())
        );
        one.setActUserIds(req.getUserIds());
        one.setActUserNames(req.getUserIdNames());
        one.setActRemarks(req.getContent());
        one.setActEndTime(LocalDateTime.now());
        costProjectProccessNodeManager.updateById(one);

        // 主任务扭转到下一节点
        nTask.setStatus(TaskStatusConstant.AUDITING.getStatusCode());
        nTask.setCurrentNode(nextNodeStatus);
        nTask.setIsGd("0");
        costProjectTaskManager.updateById(nTask);

        // 设置下一节点的开始时间
        CostProjectProccessNode two = costProjectProccessNodeManager.getOne(
                new LambdaQueryWrapper<CostProjectProccessNode>()
                        .eq(CostProjectProccessNode::getProcessId, proccess.getProcessId())
                        .eq(CostProjectProccessNode::getProcessNodeKey, nextNodeStatus)
        );
        two.setActStartTime(LocalDateTime.now());
        costProjectProccessNodeManager.updateById(two);

        // 子任务同步节点流转，根据节点设置对应状态
        String childStatus = "";
        switch (nextNodeStatus) {
            case "yjfk":
                childStatus = TaskStatusConstant.WAIT_FEEDBACK.getStatusCode();
                break;
            case "jtsy":
            case "cjbg":
            case "gd":
                childStatus = TaskStatusConstant.COMPLETED.getStatusCode();
                break;
            default:
                childStatus = TaskStatusConstant.AUDITING.getStatusCode();
                break;
        }

        // 同步所有非中止状态的子任务
        for (CostProjectTask child : children) {
            if (!child.getStatus().equals(TaskStatusConstant.SUSPENDED.getStatusCode())) {
                child.setStatus(childStatus);
                child.setCurrentNode(nextNodeStatus);
                costProjectTaskManager.updateById(child);

                // 如果扭转到意见反馈节点，通知企业
                if ("yjfk".equals(nextNodeStatus) && StringUtil.isNotEmpty(child.getAuditedUnitId())) {
                    AuditedUnit auditedUnit = auditedUnitManager.getOne(
                            new LambdaQueryWrapper<AuditedUnit>()
                                    .eq(AuditedUnit::getUnitId, child.getAuditedUnitId())
                                    .eq(AuditedUnit::getIsDeleted, "0")
                    );
                    if (auditedUnit != null && StringUtil.isNotEmpty(auditedUnit.getAccount())) {
                        String noticeTitle = "意见反馈通知";
                        String noticeContent = "您的项目(" + child.getProjectName() + ")需要反馈意见，请及时处理";
                        String orgId = getCurrentUserMainOrgId();
                        Org org = orgManager.getById(orgId);
                        String noticeSource = (org != null ? org.getName() : "系统") + " " + AuthenticationUtil.getCurrentUserFullname();
                        costNoticeManager.sendNotice(
                                child.getProjectId(),
                                child.getId(),
                                "1",
                                noticeTitle,
                                noticeContent,
                                child.getAuditedUnitId(),
                                noticeSource,
                                auditedUnit.getAccount()
                        );
                    }
                }
            }
        }

        // 通知内容组装
        String title = NodeConstant.getNodeValueByKey(nextNodeStatus) + "已开始";
        String enterpriseId = task.getAuditedUnitId() == null ? "" : task.getAuditedUnitId();
        String orgId = getCurrentUserMainOrgId();
        Org org = orgManager.getById(orgId);
        String noticeSource = (org.getName()) + " " + AuthenticationUtil.getCurrentUserFullname();
        String sendTarget = task.getCreateBy() == null ? "" : task.getCreateBy();
        String content = "[" + NodeConstant.getNodeValueByKey(task.getCurrentNode()) + "]已办结并扭转至[" + NodeConstant.getNodeValueByKey(nextNodeStatus) + "]，" + task.getProjectName();
        if (StringUtil.isNotEmpty(req.getContent())) {
            content += "，备注：" + req.getContent();
        }
        costNoticeManager.sendNotice(task.getProjectId(), task.getId(), "1", title, content, enterpriseId, noticeSource, sendTarget);
        return title;
    }


    @Override
    public List<CostProjectTask> getDoList(String projectId) {
        // 获取当前用户
        IUser currentUser = ContextUtil.getCurrentUser();
        String currentUserId = currentUser.getUserId();

        // 1. 先查询当前用户有权限的立项（负责人或项目组成员）
        LambdaQueryWrapper<CostProjectApproval> approvalQueryWrapper = new LambdaQueryWrapper<>();
        approvalQueryWrapper.eq(CostProjectApproval::getIsDeleted, "0");
        approvalQueryWrapper.and(wrapper -> wrapper
                .eq(CostProjectApproval::getLeaderId, currentUserId)
                .or(projectMembersWrapper -> {
                    projectMembersWrapper.like(CostProjectApproval::getProjectMembers, currentUserId);
                })
        );

        List<CostProjectApproval> accessibleApprovals = costProjectApprovalManager.list(approvalQueryWrapper);

        // 如果没有权限的立项，返回空结果
        if (accessibleApprovals.isEmpty()) {
            return new ArrayList<>();
        }

        // 提取有权限的立项ID列表
        List<String> accessibleProjectIds = accessibleApprovals.stream()
                .map(CostProjectApproval::getProjectId)
                .distinct()
                .collect(java.util.stream.Collectors.toList());

        // 2. 构建任务查询条件
        LambdaQueryWrapper<CostProjectTask> queryWrapper = new LambdaQueryWrapper<>();

        // 查询未删除的记录
        queryWrapper.eq(CostProjectTask::getIsDeleted, "0");

        // 查询子任务
        queryWrapper.ne(CostProjectTask::getPid, "0");

        // 只查询当前用户有权限的立项对应的任务
        queryWrapper.in(CostProjectTask::getProjectId, accessibleProjectIds);

        // 根据请求参数添加查询条件
        queryWrapper.eq(projectId != null, CostProjectTask::getProjectId, projectId);

        // 按创建时间倒序排列
        queryWrapper.orderByDesc(CostProjectTask::getCreateTime);

        List<CostProjectTask> list = costProjectTaskManager.list(queryWrapper);

        for (CostProjectTask rootTask : list) {
            rootTask.setStatusName(TaskStatusConstant.getStatusNameByCode(rootTask.getStatus()));
            rootTask.setCurrentNodeName(NodeConstant.getNodeValueByKey(rootTask.getCurrentNode()));
        }
        return list;

    }

    @Override
    public List<Map<String, Object>> getDoChartList(String year, String region) {
        List<CostCatalog> list = costCatalogManager.list(
                new LambdaQueryWrapper<CostCatalog>().eq(CostCatalog::getParentId, "1969351600934948833")
        );
        List<Map<String, Object>> maps = new ArrayList<>();

        for (CostCatalog costCatalog : list) {
            // 递归获取所有下级目录ID
            List<String> allCatalogIds = getAllChildCatalogIds(costCatalog.getCatalogId());

            // 通过项目立项表关联查询目录
            List<CostProjectApproval> approvals = costProjectApprovalManager.list(
                    new LambdaQueryWrapper<CostProjectApproval>()
                            .in(CostProjectApproval::getCatalogId, allCatalogIds)
                            .eq(CostProjectApproval::getIsDeleted, "0")
            );

            if (approvals.isEmpty()) {
                Map<String, Object> map = new HashMap<>();
                map.put("name", costCatalog.getCatalogName());
                map.put("finish", 0);
                map.put("nFinish", 0);
                maps.add(map);
                continue;
            }

            List<String> projectIds = approvals.stream()
                    .map(CostProjectApproval::getProjectId)
                    .collect(Collectors.toList());

            // 查询子任务
            LambdaQueryWrapper<CostProjectTask> taskQuery = new LambdaQueryWrapper<>();
            taskQuery.eq(CostProjectTask::getIsDeleted, "0")
                    .ne(CostProjectTask::getPid, "0")
                    .in(CostProjectTask::getProjectId, projectIds);
            if (StringUtil.isNotEmpty(year)) {
                taskQuery.eq(CostProjectTask::getYear, year);
            }

            List<CostProjectTask> tasks = this.list(taskQuery);

            // 统计完成和未完成的任务
            long finishCount = tasks.stream()
                    .filter(task -> TaskStatusConstant.COMPLETED.getStatusCode().equals(task.getStatus()))
                    .count();
            long nFinishCount = tasks.size() - finishCount;

            Map<String, Object> map = new HashMap<>();
            map.put("name", costCatalog.getCatalogName());
            map.put("finish", finishCount);
            map.put("nFinish", nFinishCount);
            maps.add(map);
        }
        return maps;
    }

    @Override
    public List<CostNotice> getDoMsgList() {
        IUser currentUser = ContextUtil.getCurrentUser();
        String currentUserId = currentUser.getUserId();

        AuditedUnit unit = auditedUnitManager.getOne(
                new LambdaQueryWrapper<AuditedUnit>()
                        .eq(AuditedUnit::getAccount, currentUserId)
                        .last("limit 1")
        );

        LambdaQueryWrapper<CostNotice> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(CostNotice::getIsDeleted, "0");

        if (unit != null) {
            queryWrapper.and(q -> q.eq(CostNotice::getEnterpriseId, unit.getUnitId())
                    .or()
                    .eq(CostNotice::getSendTarget, currentUserId));
        } else {
            // unit 为空时，只看是否发给当前用户
            queryWrapper.eq(CostNotice::getSendTarget, currentUserId);
        }

        queryWrapper.orderByDesc(CostNotice::getCreateTime)
                .last("limit 8");

        return costNoticeManager.list(queryWrapper);
    }


    @Override
    public IPage<CostProjectTask> pageListForReviewTaskChild(CostTaskReviewPageReq req) {
        // 获取当前用户
        IUser currentUser = ContextUtil.getCurrentUser();
        String currentUserId = currentUser.getUserId();

        // 1. 先查询当前用户有权限的立项（负责人或项目组成员）
        LambdaQueryWrapper<CostProjectApproval> approvalQueryWrapper = new LambdaQueryWrapper<>();
        approvalQueryWrapper.eq(CostProjectApproval::getIsDeleted, "0");
        approvalQueryWrapper.and(wrapper -> wrapper
                .eq(CostProjectApproval::getLeaderId, currentUserId)
                .or(projectMembersWrapper -> {
                    projectMembersWrapper.like(CostProjectApproval::getProjectMembers, currentUserId);
                })
        );

        List<CostProjectApproval> accessibleApprovals = costProjectApprovalManager.list(approvalQueryWrapper);

        // 如果没有权限的立项，返回空结果
        if (accessibleApprovals.isEmpty()) {
            return new Page<>(req.getPageNum(), req.getPageSize());
        }

        // 提取有权限的立项ID列表
        List<String> accessibleProjectIds = accessibleApprovals.stream()
                .map(CostProjectApproval::getProjectId)
                .distinct()
                .collect(java.util.stream.Collectors.toList());

        if (req.getAreaCode() != null) {
            List<CostProjectTaskApproval> list = costProjectTaskApprovalManager.list(
                    new LambdaQueryWrapper<CostProjectTaskApproval>().eq(CostProjectTaskApproval::getAreaCode, req.getAreaCode())
            );
            if (list.isEmpty()) {
                return new Page<>(req.getPageNum(), req.getPageSize());
            }
            List<String> projectIds =
                    list.stream().map(CostProjectTaskApproval::getProjectId).collect(Collectors.toList());
            accessibleProjectIds.addAll(projectIds);
        }

        // 2. 构建任务查询条件
        LambdaQueryWrapper<CostProjectTask> queryWrapper = new LambdaQueryWrapper<>();

        // 查询未删除的记录
        queryWrapper.eq(CostProjectTask::getIsDeleted, "0");

        // 查询根任务（pid为0）
        queryWrapper.ne(CostProjectTask::getPid, "0");

        // 只查询当前用户有权限的立项对应的任务
        queryWrapper.in(CostProjectTask::getProjectId, accessibleProjectIds);

        // 根据请求参数添加查询条件
        if (StringUtil.isNotEmpty(req.getProjectName())) {
            queryWrapper.like(CostProjectTask::getProjectName, req.getProjectName());
        }
        if (StringUtil.isNotEmpty(req.getAuditedUnitName())) {
            queryWrapper.like(CostProjectTask::getAuditedUnitName, req.getAuditedUnitName());
        }
        if (StringUtil.isNotEmpty(req.getStatus())) {
            queryWrapper.eq(CostProjectTask::getStatus, req.getStatus());
        }
        if (StringUtil.isNotEmpty(req.getYear())) {
            queryWrapper.eq(CostProjectTask::getYear, req.getYear());
        }
        queryWrapper.eq(req.getCurrentNode() != null, CostProjectTask::getCurrentNode, req.getCurrentNode());
        queryWrapper.ne(req.getNCurrentNode() != null, CostProjectTask::getCurrentNode, req.getNCurrentNode());
        queryWrapper.ne(req.getNStatus() != null, CostProjectTask::getStatus, req.getNStatus());
        // 按创建时间倒序排列
        queryWrapper.orderByDesc(CostProjectTask::getCreateTime);

        Page<CostProjectTask> page = new Page<>(req.getPageNum(), req.getPageSize());
        IPage<CostProjectTask> result = costProjectTaskManager.page(page, queryWrapper);
        List<CostProjectTask> rootList = result.getRecords();
        if (rootList == null || rootList.isEmpty()) {
            return result;
        }
        Set<String> allProjectIds = new HashSet<>();
        rootList.forEach(t -> allProjectIds.add(t.getProjectId()));
        List<CostProjectApproval> approvalList = costProjectApprovalManager.list(
                new LambdaQueryWrapper<CostProjectApproval>()
                        .in(CostProjectApproval::getProjectId, allProjectIds)
        );
        Map<String, CostProjectApproval> approvalMap =
                approvalList.stream().collect(
                        Collectors.toMap(CostProjectApproval::getProjectId, v -> v)
                );

        for (CostProjectTask rootTask : rootList) {
            // 任务状态
            rootTask.setStatusName(TaskStatusConstant.getStatusNameByCode(rootTask.getStatus()));
            rootTask.setCurrentNodeName(NodeConstant.getNodeValueByKey(rootTask.getCurrentNode()));
            rootTask.setWarningStatus(calculateWarningStatus(rootTask));
            // 找根任务
            String pid = rootTask.getPid();
            if (StringUtils.isNotBlank(pid)) {
                CostProjectTask rrootTask = this.getById(pid);
                if (rrootTask != null) {
                    rootTask.setAuditPeriod(rrootTask.getAuditPeriod());
                }
            }
            // 设置目录
            CostProjectApproval rootDetail = approvalMap.get(rootTask.getProjectId());
            if (rootDetail != null) {
                rootTask.setCatalogId(rootDetail.getCatalogId());
                if (StringUtil.isNotEmpty(rootDetail.getAreaCode())) {
                    CostDistrict district = costDistrictManager.getOne(
                            new LambdaQueryWrapper<CostDistrict>()
                                    .eq(CostDistrict::getCode, rootDetail.getAreaCode())
                    );
                    rootTask.setAreaName(district != null ? district.getName() : "山西省");
                }
            }
        }

        return result;
    }

    @Override
    public List<CostProjectTask> findTaskByProjectId(String projectId, String enterpriseId) {
        QueryWrapper<CostProjectTask> wrapper = new QueryWrapper<>();
        wrapper.eq("project_id",projectId);
        wrapper.eq("audited_unit_id",enterpriseId);
        return this.list(wrapper);
    }

    private List<String> getAllChildCatalogIds(String catalogId) {
        List<String> result = new ArrayList<>();
        result.add(catalogId);

        List<CostCatalog> children = costCatalogManager.list(
                new LambdaQueryWrapper<CostCatalog>().eq(CostCatalog::getParentId, catalogId)
        );

        for (CostCatalog child : children) {
            result.addAll(getAllChildCatalogIds(child.getCatalogId()));
        }

        return result;
    }

    /**
     * 催办任务，仅记录消息
     *
     * @param task 任务对象
     * @param req  请求参数
     * @return 催办结果消息
     */
    private String remindTask(CostProjectTask task, CostTaskPageReq req) {
        // 检查是否提供了用户ID
        if (StringUtil.isEmpty(req.getUserIds())) {
            throw new RuntimeException("未指定催办人员");
        }
        String title = NodeConstant.getNodeValueByKey(task.getCurrentNode()) + "催办";
        // 分割用户ID并逐个发送通知
        for (String userId : req.getUserIds().split(",")) {

            // 发送催办通知
            String content = "[" + NodeConstant.getNodeValueByKey(task.getCurrentNode()) + "]" + AuthenticationUtil.getCurrentUserFullname() + "催办" + task.getAuditedUnitName() + "的项目(" + task.getProjectName() + ")";
            if (StringUtil.isNotEmpty(req.getContent())) {
                content += "，原因：" + req.getContent();
            }
            String enterpriseId = task.getAuditedUnitId() == null ? "" : task.getAuditedUnitId();
            String orgId = getCurrentUserMainOrgId();
            Org org = orgManager.getById(orgId);
            String noticeSource = (org.getName()) + " " + AuthenticationUtil.getCurrentUserFullname();
            String sendTarget = task.getCreateBy() == null ? "" : task.getCreateBy();
            // 使用传入的用户ID作为发送目标
            costNoticeManager.sendNotice(task.getProjectId(), task.getId(), "1", title, content, enterpriseId, noticeSource, sendTarget);
        }
        return title;
    }

    /**
     * 催办任务，仅记录消息
     *
     * @param task 任务对象
     * @param req  请求参数
     * @return 催办结果消息
     */
    private String remindUnitTask(CostProjectTask task, CostTaskPageReq req) {
        // 检查是否提供了用户ID
        if (StringUtil.isEmpty(req.getAuditedUnitIds())) {
            throw new RuntimeException("未指定催报企业");
        }
        String title = NodeConstant.getNodeValueByKey(task.getCurrentNode()) + "催办";
        // 分割用户ID并逐个发送通知
        for (String unitId : req.getAuditedUnitIds().split(",")) {

            // 发送催办通知
            String content = "[" + NodeConstant.getNodeValueByKey(task.getCurrentNode()) + "]" + AuthenticationUtil.getCurrentUserFullname() + "催报" + task.getAuditedUnitName() + "的项目(" + task.getProjectName() + ")";
            if (StringUtil.isNotEmpty(req.getContent())) {
                content += "，原因：" + req.getContent();
            }
            String enterpriseId = task.getAuditedUnitId() == null ? "" : task.getAuditedUnitId();
            String orgId = getCurrentUserMainOrgId();
            Org org = orgManager.getById(orgId);
            String noticeSource = (org.getName()) + " " + AuthenticationUtil.getCurrentUserFullname();
            String sendTarget = task.getCreateBy() == null ? "" : task.getCreateBy();
            // 使用传入的用户ID作为发送目标
            costNoticeManager.sendNotice(task.getProjectId(), task.getId(), "1", title, content, enterpriseId, noticeSource, sendTarget);
        }
        return title;
    }

    /**
     * 复核，主任务退回到实地审核节点，子任务恢复到流程初始状态
     *
     * @param task 任务对象
     * @param req  请求参数
     * @return 复核结果消息
     */
    private String reviewTask(CostProjectTask task, CostTaskPageReq req) {
        CostProjectTask nTask = costProjectTaskManager.getById(task.getId());
        if (!"0".equals(task.getPid())) {
            return "仅支持主任务进行此操作";
        }

        // 获取实地审核节点
        String reviewNodeKey = NodeConstant.sdshenhe.getNodeKey();

        // 更新流程节点时间：清空当前节点及之后节点的时间，重置实地审核节点的开始时间
        CostProjectProccess proccess = costProjectProccessManager.getOne(
                new LambdaQueryWrapper<CostProjectProccess>().eq(CostProjectProccess::getProjectId, task.getProjectId())
        );

        if (proccess != null) {
            // 清空当前节点的实际结束时间和操作信息
            CostProjectProccessNode currentNode = costProjectProccessNodeManager.getOne(
                    new LambdaQueryWrapper<CostProjectProccessNode>()
                            .eq(CostProjectProccessNode::getProcessId, proccess.getProcessId())
                            .eq(CostProjectProccessNode::getProcessNodeKey, task.getCurrentNode())
            );
            if (currentNode != null) {
                currentNode.setActEndTime(null);
                currentNode.setActUserIds(null);
                currentNode.setActUserNames(null);
                currentNode.setActRemarks(null);
                costProjectProccessNodeManager.updateById(currentNode);
            }

            // 清空实地审核之后所有节点的时间和操作信息
            boolean foundReviewNode = false;
            for (NodeConstant nodeConstant : NodeConstant.values()) {
                if (nodeConstant.getNodeKey().equals(reviewNodeKey)) {
                    foundReviewNode = true;
                    continue;
                }
                if (foundReviewNode) {
                    CostProjectProccessNode node = costProjectProccessNodeManager.getOne(
                            new LambdaQueryWrapper<CostProjectProccessNode>()
                                    .eq(CostProjectProccessNode::getProcessId, proccess.getProcessId())
                                    .eq(CostProjectProccessNode::getProcessNodeKey, nodeConstant.getNodeKey())
                    );
                    if (node != null) {
                        node.setActStartTime(null);
                        node.setActEndTime(null);
                        node.setActUserIds(null);
                        node.setActUserNames(null);
                        node.setActRemarks(null);
                        costProjectProccessNodeManager.updateById(node);
                    }
                }
            }

            // 重置实地审核节点的开始时间
            CostProjectProccessNode reviewNode = costProjectProccessNodeManager.getOne(
                    new LambdaQueryWrapper<CostProjectProccessNode>()
                            .eq(CostProjectProccessNode::getProcessId, proccess.getProcessId())
                            .eq(CostProjectProccessNode::getProcessNodeKey, reviewNodeKey)
            );
            if (reviewNode != null) {
                reviewNode.setActStartTime(LocalDateTime.now());
                costProjectProccessNodeManager.updateById(reviewNode);
            }
        }

        // 主任务退回到实地审核节点
        nTask.setStatus(TaskStatusConstant.AUDITING.getStatusCode());
        nTask.setCurrentNode(reviewNodeKey);
        nTask.setIsGd("0");
        costProjectTaskManager.updateById(nTask);

        // 子任务恢复到流程初始状态（实地审核节点，审核中状态）
        List<CostProjectTask> children = costProjectTaskManager.list(
                new LambdaQueryWrapper<CostProjectTask>()
                        .eq(CostProjectTask::getPid, nTask.getId())
                        .eq(CostProjectTask::getIsDeleted, "0")
        );

        String initialNodeKey = NodeConstant.sdshenhe.getNodeKey();
        for (CostProjectTask child : children) {
            // 非中止状态的子任务恢复到初始状态
            if (!child.getStatus().equals(TaskStatusConstant.SUSPENDED.getStatusCode())) {
                child.setStatus(TaskStatusConstant.AUDITING.getStatusCode());
                child.setCurrentNode(initialNodeKey);
                costProjectTaskManager.updateById(child);
            }
        }

        // 发送通知
        String title = "复核-已退回至" + NodeConstant.getNodeValueByKey(reviewNodeKey);
        String enterpriseId = task.getAuditedUnitId() == null ? "" : task.getAuditedUnitId();
        String orgId = getCurrentUserMainOrgId();
        Org org = orgManager.getById(orgId);
        String noticeSource = (org.getName()) + " " + AuthenticationUtil.getCurrentUserFullname();
        String sendTarget = task.getCreateBy() == null ? "" : task.getCreateBy();
        String content = "[" + NodeConstant.getNodeValueByKey(task.getCurrentNode()) + "]" + AuthenticationUtil.getCurrentUserFullname() + "要求复核，已退回至[" + NodeConstant.getNodeValueByKey(reviewNodeKey) + "]，" + task.getProjectName();
        if (StringUtil.isNotEmpty(req.getContent())) {
            content += "，原因：" + req.getContent();
        }
        costNoticeManager.sendNotice(task.getProjectId(), task.getId(), "1", title, content, enterpriseId, noticeSource, sendTarget);

        return title;
    }

    /**
     * 归档任务，修改任务归档状态并异步生成资料归纳主表
     *
     * @param task 任务对象
     * @param req  请求参数
     * @return 归档结果消息
     */
    private String archiveTask(CostProjectTask task, CostTaskPageReq req) {
        CostProjectTask nTask = costProjectTaskManager.getById(task.getId());
        if (!"0".equals(task.getPid())) {
            return "仅支持主任务进行归档操作";
        }

        // 检查任务是否已办结
        if (!TaskStatusConstant.COMPLETED.getStatusCode().equals(nTask.getStatus())) {
            throw new RuntimeException("任务未办结，无法归档");
        }

        // 检查所有子任务是否都已办结
        List<CostProjectTask> children = costProjectTaskManager.list(
                new LambdaQueryWrapper<CostProjectTask>()
                        .eq(CostProjectTask::getPid, nTask.getId())
                        .eq(CostProjectTask::getIsDeleted, "0")
        );
        boolean allChildrenCompleted = children.stream()
                .filter(child -> !TaskStatusConstant.SUSPENDED.getStatusCode().equals(child.getStatus()))
                .allMatch(child -> TaskStatusConstant.COMPLETED.getStatusCode().equals(child.getStatus()));
        if (!allChildrenCompleted) {
            throw new RuntimeException("子任务未全部办结，主任务无法归档");
        }

        // 更新主任务归档状态
        nTask.setIsGd("1");
        costProjectTaskManager.updateById(nTask);


        // 发送通知
        String title = "任务已归档";
        String content = "[" + NodeConstant.getNodeValueByKey(task.getCurrentNode()) + "]" + AuthenticationUtil.getCurrentUserFullname() + "已归档" + task.getProjectName();
        if (StringUtil.isNotEmpty(req.getContent())) {
            content += "，备注：" + req.getContent();
        }
        String enterpriseId = task.getAuditedUnitId() == null ? "" : task.getAuditedUnitId();
        String orgId = getCurrentUserMainOrgId();
        Org org = orgManager.getById(orgId);
        String noticeSource = (org.getName()) + " " + AuthenticationUtil.getCurrentUserFullname();
        String sendTarget = task.getCreateBy() == null ? "" : task.getCreateBy();
        costNoticeManager.sendNotice(task.getProjectId(), task.getId(), "1", title, content, enterpriseId, noticeSource, sendTarget);

        return title;
    }

}
