package com.dayou.workflow.handler;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.util.StrUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.dayou.common.BaseEntity;
import com.dayou.dto.HandlerPermissionDTO;
import com.dayou.dto.WorkNodeCommit;
import com.dayou.dto.WorkNodeDTO;
import com.dayou.entity.*;
import com.dayou.enums.MainBusinessEnum;
import com.dayou.enums.ProductionEnum;
import com.dayou.enums.workflow.CallbackEnum;
import com.dayou.enums.workflow.HandlerPermissionEnum;
import com.dayou.enums.workflow.WorkflowNodeEnum;
import com.dayou.exception.ErrorCode;
import com.dayou.mapper.*;
import com.dayou.service.*;
import com.dayou.service.workflow.IWorkFlowNodeInstanceService;
import com.dayou.service.workflow.IWorkNodeService;
import com.dayou.service.workflow.IWorkTaskRecordService;
import com.dayou.workflow.config.WorkNodeProcessable;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import java.math.BigDecimal;
import java.time.LocalDate;
import java.util.*;
import java.util.stream.Collectors;

import static com.dayou.enums.MainBusinessEnum.MAJOR_BUSINESS;
import static com.dayou.enums.ProductionEnum.*;
import static com.dayou.enums.ProductionEnum.LETTER;
import static com.dayou.enums.TakeNumberEnum.LAND_NUMBER;
import static com.dayou.enums.workflow.NodeStateEnum.PENDING;
import static com.dayou.enums.workflow.NodeStateEnum.SKIP;
import static com.dayou.enums.workflow.WorkflowNodeEnum.*;

/**
 * 类说明：
 *
 * @author: wucl
 * @since: 2023/11/1
 * created with IntelliJ IDEA.
 */
@Component
public class MajorNodeHandler extends WorkNodeProcessable {

    @Autowired
    private IWorkFlowNodeInstanceService workFlowNodeInstanceService;
    @Autowired
    private WorkFlowNodeInstanceMapper workFlowNodeInstanceMapper;
    @Autowired
    private MajorProductionMapper majorProductionMapper;
    @Autowired
    private MajorTargetMapper majorTargetMapper;
    @Autowired
    private MajorMapper majorMapper;
    @Autowired
    private DepartmentMapper departmentMapper;
    @Autowired
    private IUserPostService userPostService;
    @Autowired
    private IWorkNodeService workNodeService;
    @Autowired
    private IWorkTaskRecordService workTaskRecordService;

    @Autowired
    private IProductionFundService productionFundService;

    @Autowired
    IMajorTargetService majorTargetService;

    @Autowired
    IMajorProductionService productionService;

    @Autowired
    private IUserService userService;


    @Override
    public boolean forward(WorkNodeCommit workNodeCommit) {
        WorkFlowNodeInstance currentInstanceNode = workFlowNodeInstanceMapper.getById(workNodeCommit.getInstanceNodeId());
        WorkNodeDTO nextWorkNode = beforeForward(workNodeCommit,currentInstanceNode);
        if (nextWorkNode==null && workNodeCommit.getNodeCode().equals(LEADER_ALLOCATION.name())){
            nextWorkNode = workNodeService.doCreatedDepartmentAllocationNode();
        }
        if (nextWorkNode!=null){
            String ifVerify = currentInstanceNode.getVerify();
            if (StrUtil.isNotEmpty(ifVerify)){
                CallbackEnum callback = CallbackEnum.valueOf(ifVerify);
                if (callback !=null){
                    //根据callback 确定具体的业务数据
                    //获取产品类型
                    List<ProductionEnum> production = workNodeCommit.getProduction();
                    switch (callback){
                        case CHECK_PRODUCTION_CHECK:
                            nextWorkNode = workNodeService.getNextWorkNodeByCheckState(currentInstanceNode.getFlowId(),currentInstanceNode.getNodeCode(),
                                    workNodeCommit.getDoSecondCheck(),workNodeCommit.getDoThirdCheck());
                            break;
                        case CHECK_PRODUCTION_TYPE:
                            //1. 获取业务上出具的产品类型。
                            //2.根据出具的产品类型 确定需要哪些节点
                            Map<String,List<WorkflowNodeEnum>> majorNecessaryNodes = CallbackEnum.NecessaryNode.getByProduction(MAJOR_BUSINESS.name(),
                                    production);
                            nextWorkNode = workNodeService.getNextWorkNodeByBusiness(currentInstanceNode.getFlowId(), MAJOR_BUSINESS
                                    ,currentInstanceNode.getNodeCode(), majorNecessaryNodes,workNodeCommit.getIfPay());
                            break;
                        case CHECK_PRODUCTION_FUND:
                            //出库申请：已收款不用部门审核，直接到财务审核
                            if (workNodeCommit.getIfProductionFund()){
                                nextWorkNode = workNodeService.getNextWorkNode(nextWorkNode.getFlowId(), nextWorkNode.getId());
                            }
                            break;
                    }
                }
            }
            if (CollectionUtil.isNotEmpty(workNodeCommit.getReportNos())){

                //主流程分支
                String code = workNodeService.getOne(new LambdaQueryWrapper<WorkNode>()
                        .select(WorkNode::getCode)
                        .eq(BaseEntity::getId, currentInstanceNode.getNodeId()).eq(BaseEntity::getDeleted, Boolean.FALSE)).getCode();
                WorkflowNodeEnum workflowNodeEnum = WorkflowNodeEnum.valueOf(code);

                if (workflowNodeEnum.equals(WorkflowNodeEnum.WRITE_STATEMENT)){
                    for (String businessSubId :workNodeCommit.getReportNos()){
                        addNextInstanceNode(currentInstanceNode,nextWorkNode, workNodeCommit.getNextHandlerId(),businessSubId,null);
                    }
                }
                else if(workflowNodeEnum.equals(WorkflowNodeEnum.WRITE_REPORT) || workflowNodeEnum.equals(WorkflowNodeEnum.WRITE_LETTER)){
                    for (String businessMinId :workNodeCommit.getReportNos()){
                        addNextInstanceNode(currentInstanceNode,nextWorkNode, workNodeCommit.getNextHandlerId(),workNodeCommit.getBusinessSubId(),businessMinId);
                    }
                }else {
                    addNextInstanceNode(currentInstanceNode,nextWorkNode, workNodeCommit.getNextHandlerId(),workNodeCommit.getBusinessSubId(),workNodeCommit.getBusinessMinId());
                }
            }
            else {
                addNextInstanceNode(currentInstanceNode,nextWorkNode, workNodeCommit.getNextHandlerId(),workNodeCommit.getBusinessSubId(),workNodeCommit.getBusinessMinId());
            }
            currentInstanceNode.setBusinessSubId(workNodeCommit.getBusinessSubId());
            currentInstanceNode.setBusinessMinId(workNodeCommit.getBusinessMinId());
            afterForward(currentInstanceNode);
            return Boolean.TRUE;
        }

        return Boolean.FALSE;
    }

    @Override
    public boolean skip(WorkNodeCommit workNodeCommit){
        WorkFlowNodeInstance instanceNode = workFlowNodeInstanceService.getById(workNodeCommit.getInstanceNodeId());
         workFlowNodeInstanceService.update(new LambdaUpdateWrapper<WorkFlowNodeInstance>().set(WorkFlowNodeInstance::getState,SKIP)
                .set(WorkFlowNodeInstance::getComment,workNodeCommit.getComments())
                .eq(WorkFlowNodeInstance::getId,workNodeCommit.getInstanceNodeId()));
        //添加日志
        return addWorkflowLog(workNodeCommit,instanceNode);
    }

    @Override
    public boolean goBack(WorkNodeCommit commit){
        Long instanceNodeId = commit.getInstanceNodeId();
        WorkFlowNodeInstance currentNode = workFlowNodeInstanceMapper.getInstanceNodeInfoById(instanceNodeId);
        //如果是撰写节点（意见书，报告，复评函）退回。需删除产品业务信息
        List<String> writeNodes = Arrays.asList(new String[]{WRITE_STATEMENT.name(), WRITE_REPORT.name(), WRITE_LETTER.name()});
        //如果是初审节点（意见书，报告，复评函）退回。需要撰写节点的状态修改回PENDING
        List<String> checkNodes = Arrays.asList(new String[]{CHECK_STATEMENT.name(), CHECK_REPORT.name(), CHECK_LETTER.name()});
        if (writeNodes.contains(currentNode.getNodeCode()) && commit.getCleanReportNo()!=null && commit.getCleanReportNo()){
            //是否取号？
            List<MajorTarget> productionNos = majorTargetMapper.getSubReportNo(currentNode.getBusinessId()).stream()
                    .filter(x->x!=null).collect(Collectors.toList());

            if (currentNode.getNodeCode().equals(WRITE_STATEMENT.name())){
                Set<String> statementNos = productionNos.stream().filter(x->StrUtil.isNotBlank(x.getStatementNo()))
                        .map(MajorTarget::getStatementNo).collect(Collectors.toSet());
                if (CollectionUtil.isNotEmpty(statementNos)){
                    checkRealAmount(statementNos);
                    majorTargetMapper.cleanSubStatementNo(statementNos);
                    majorProductionMapper.delete(new LambdaQueryWrapper<MajorProduction>()
                            .in(MajorProduction::getReportNo,statementNos));
                }
            }
            if (currentNode.getNodeCode().equals(WRITE_REPORT.name())){
                Set<String> reportNos = productionNos.stream().filter(x->StrUtil.isNotBlank(x.getReportNo()))
                        .map(MajorTarget::getReportNo).collect(Collectors.toSet());
                if (CollectionUtil.isNotEmpty(reportNos)){
                    checkRealAmount(reportNos);
                    majorTargetMapper.cleanSubReportNo(reportNos);
                    majorProductionMapper.delete(new LambdaQueryWrapper<MajorProduction>()
                            .in(MajorProduction::getReportNo,reportNos));
                }
            }
            if (currentNode.getNodeCode().equals(WRITE_LETTER.name())){
                Set<String> letterNos = productionNos.stream().filter(x->StrUtil.isNotBlank(x.getLetterNo()))
                        .map(MajorTarget::getLetterNo).collect(Collectors.toSet());
                if (CollectionUtil.isNotEmpty(letterNos)){
                    checkRealAmount(letterNos);
                    majorTargetMapper.cleanSubLetterNo(letterNos);
                    majorProductionMapper.delete(new LambdaQueryWrapper<MajorProduction>()
                            .in(MajorProduction::getReportNo,letterNos));
                }
            }

        }
        if (checkNodes.contains(currentNode.getNodeCode())){
            //在这些节点退回，需要特殊处理实例节点信息，不适用父类修改节点实例信息，因为上个节点还没有business_sub_id和business_min_id
            //将上一个节点状态改为PENDING
            if (currentNode.getNodeCode().equals(CHECK_STATEMENT.name())){
                workFlowNodeInstanceService.update(new LambdaUpdateWrapper<WorkFlowNodeInstance>().set(WorkFlowNodeInstance::getState,PENDING)
                        .eq(WorkFlowNodeInstance::getBusinessId,currentNode.getBusinessId()).eq(WorkFlowNodeInstance::getFlowId,currentNode.getFlowId())
                        .eq(WorkFlowNodeInstance::getSequence,(currentNode.getSequence()-1)).eq(BaseEntity::getDeleted,Boolean.FALSE));
                //将上一个节点的任务状态修改为未完成
                WorkFlowNodeInstance preNode = workFlowNodeInstanceService.getOne(new LambdaQueryWrapper<WorkFlowNodeInstance>().select(BaseEntity::getId)
                        .eq(WorkFlowNodeInstance::getFlowId, currentNode.getFlowId())
                        .eq(WorkFlowNodeInstance::getBusinessId, currentNode.getBusinessId()).eq(WorkFlowNodeInstance::getSequence, (currentNode.getSequence() - 1))
                        .eq(BaseEntity::getDeleted, Boolean.FALSE));

                if (preNode!=null){
                    workTaskRecordService.update(new LambdaUpdateWrapper<WorkTaskRecord>().set(WorkTaskRecord::getFinished,Boolean.FALSE).eq(WorkTaskRecord::getInstanceId,preNode.getId()));
                }
            }else{
                workFlowNodeInstanceService.update(new LambdaUpdateWrapper<WorkFlowNodeInstance>().set(WorkFlowNodeInstance::getState,PENDING)
                        .eq(WorkFlowNodeInstance::getBusinessId,currentNode.getBusinessId()).eq(WorkFlowNodeInstance::getFlowId,currentNode.getFlowId())
                                .eq(StrUtil.isNotEmpty(commit.getBusinessSubId()),WorkFlowNodeInstance::getBusinessSubId,currentNode.getBusinessSubId())
                        .eq(WorkFlowNodeInstance::getSequence,(currentNode.getSequence()-1)).eq(BaseEntity::getDeleted,Boolean.FALSE));
                //将上一个节点的任务状态修改为未完成
                WorkFlowNodeInstance preNode = workFlowNodeInstanceService.getOne(new LambdaQueryWrapper<WorkFlowNodeInstance>().select(BaseEntity::getId)
                        .eq(WorkFlowNodeInstance::getFlowId, currentNode.getFlowId())
                        .eq(StrUtil.isNotEmpty(commit.getBusinessSubId()),WorkFlowNodeInstance::getBusinessSubId,currentNode.getBusinessSubId())
                        .eq(WorkFlowNodeInstance::getBusinessId, currentNode.getBusinessId()).eq(WorkFlowNodeInstance::getSequence, (currentNode.getSequence() - 1))
                        .eq(BaseEntity::getDeleted, Boolean.FALSE));

                if (preNode!=null){
                    workTaskRecordService.update(new LambdaUpdateWrapper<WorkTaskRecord>().set(WorkTaskRecord::getFinished,Boolean.FALSE).eq(WorkTaskRecord::getInstanceId,preNode.getId()));
                }
            }


        }
        if (currentNode.getNodeCode().equals(STATEMENT_FEEDBACK.name())){
            majorProductionMapper.cancelDelivery(currentNode.getBusinessId(),currentNode.getBusinessSubId(),STATEMENT.name());
        }
        // 清除产品完成时间
        cleanProductionTime(currentNode);
        return super.goBack(commit);
    }

    @Override
    public Long searchHandlerId(WorkFlowNodeInstance instanceNode, HandlerPermissionDTO handlerPermissionDTO){
        HandlerPermissionEnum handlerPermissionEnum = handlerPermissionDTO.getName();
        Major major = majorMapper.selectOne(new LambdaQueryWrapper<Major>()
                        .select(Major::getDepartmentId,Major::getClientManagerId,Major::getPrincipalId).eq(Major::getId,instanceNode.getBusinessId()));
        switch (handlerPermissionEnum){
            case EMPLOYEE:
                return handlerPermissionDTO.getPowerId();
            case POST:
                Long handlerId = userPostService.getUniqueHandlerByPostForWorkNode(handlerPermissionDTO.getPowerId());
                return handlerId==null?
                        departmentMapper.selectOne(new LambdaQueryWrapper<Department>().select(Department::getLeaderId).eq(BaseEntity::getId, major.getDepartmentId())).getLeaderId()
                        :handlerId;
            case DEPARTMENT_LEADER:
                return departmentMapper.selectOne(new LambdaQueryWrapper<Department>().select(Department::getLeaderId).eq(BaseEntity::getId, major.getDepartmentId())).getLeaderId();
            case CLIENT_MANAGER:
            case INITIATOR:
                return major.getClientManagerId();
            case PRINCIPAL:
                return major.getPrincipalId();
            case PREVIOUS_HANDLER_LEADER:
                return userService.getLeaderByCurrentUser();
            case SYSTEM:
                //暂无程序处理逻辑
                return 0L;
            default:
                //实在找不到审批人 交由部门领导处理
                return departmentMapper.selectOne(new LambdaQueryWrapper<Department>().select(Department::getLeaderId).eq(BaseEntity::getId, major.getDepartmentId())).getLeaderId();
        }
    }

    private void checkRealAmount(Set<String> productionNos){
        productionNos.stream().forEach(x->{
            BigDecimal realAmount = productionFundService.getProductionRealAmountByProductionNo(x);
            if (BigDecimal.ZERO.compareTo(realAmount)!=0){
                ErrorCode.throwBusinessException(ErrorCode.CUSTOM_ERROR,"产品已认领实收款，无法退回流程。");
            }
        });
    }

    /**
     * 节点完成后操作
     * @param currentInstanceNode 实例信息
     */
    @Override
    public void afterForward(WorkFlowNodeInstance currentInstanceNode) {
        // 撰写节点完成后,更新产品完成时间
        // 通用的更新wrapper
        LambdaUpdateWrapper<MajorProduction> productionTimeUpdateWrapper = new LambdaUpdateWrapper<MajorProduction>()
                .set(MajorProduction::getProductionTime, new Date())
                .eq(BaseEntity::getDeleted, false);
        switch (WorkflowNodeEnum.valueOf(currentInstanceNode.getNodeCode())){
            // 撰写意见书
            case WRITE_STATEMENT:
                productionTimeUpdateWrapper.eq(MajorProduction::getProduction, STATEMENT.getCode()).eq(MajorProduction::getReportNo, currentInstanceNode.getBusinessSubId());
                productionService.update(productionTimeUpdateWrapper);
                break;
            // 撰写报告报告
            case WRITE_REPORT:
                productionTimeUpdateWrapper.eq(MajorProduction::getProduction, REPORT.getCode()).eq(MajorProduction::getReportNo, currentInstanceNode.getBusinessMinId());
                productionService.update(productionTimeUpdateWrapper);
                break;
            // 撰写复评函
            case WRITE_LETTER:
                productionTimeUpdateWrapper.eq(MajorProduction::getProduction, LETTER.getCode()).eq(MajorProduction::getReportNo, currentInstanceNode.getBusinessMinId());
                productionService.update(productionTimeUpdateWrapper);
                break;
        }
    }

    /**
     * 根据节点判断是否清除产品完成时间
     * @param currentInstanceNode 当前节点
     */
    public void cleanProductionTime(WorkFlowNodeInstance currentInstanceNode) {
        // 判断是否是从审核节点退回到撰写节点,是的话需要清空产品的productionTime
        // 通用的更新wrapper
        LambdaUpdateWrapper<MajorProduction> productionTimeUpdateWrapper = new LambdaUpdateWrapper<MajorProduction>()
                .set(MajorProduction::getProductionTime, null)
                .eq(BaseEntity::getDeleted, false);
        switch (WorkflowNodeEnum.valueOf(currentInstanceNode.getNodeCode())){
            // 撰写意见书
            case CHECK_STATEMENT:
                productionTimeUpdateWrapper.eq(MajorProduction::getProduction, STATEMENT.getCode()).eq(MajorProduction::getReportNo, currentInstanceNode.getBusinessSubId());
                productionService.update(productionTimeUpdateWrapper);
                break;
            // 撰写报告报告
            case CHECK_REPORT:
                productionTimeUpdateWrapper.eq(MajorProduction::getProduction, REPORT.getCode()).eq(MajorProduction::getReportNo, currentInstanceNode.getBusinessMinId());
                productionService.update(productionTimeUpdateWrapper);
                break;
            // 撰写复评函
            case CHECK_LETTER:
                productionTimeUpdateWrapper.eq(MajorProduction::getProduction, LETTER.getCode()).eq(MajorProduction::getReportNo, currentInstanceNode.getBusinessMinId());
                productionService.update(productionTimeUpdateWrapper);
                break;
        }
    }

    @Override
    public Boolean refuse(WorkNodeCommit commit) {
        Long instanceNodeId = commit.getInstanceNodeId();
        WorkFlowNodeInstance currentNode = workFlowNodeInstanceService.getById(instanceNodeId);
            String comments = commit.getComments();
            if (comments.equals("1") || comments.equals("2")){
                WorkFlowNodeInstance workFlowNodeInstance = workFlowNodeInstanceService.list(new LambdaQueryWrapper<WorkFlowNodeInstance>()
                        .eq(WorkFlowNodeInstance::getBusinessId, currentNode.getBusinessId()).eq(WorkFlowNodeInstance::getFlowId, currentNode.getFlowId())
                        .eq(WorkFlowNodeInstance::getSequence, (currentNode.getSequence() - 1)).eq(BaseEntity::getDeleted, Boolean.FALSE).orderByDesc(BaseEntity::getCreated)).get(0);
                WorkFlowNodeInstance instance = BeanUtil.copyProperties(workFlowNodeInstance, WorkFlowNodeInstance.class);
                instance.setNodeId(workNodeService.getUniqueNodeByFlowNameAndNodeName(MAJOR_BUSINESS,LEADER_ALLOCATION).getId());
                instance.setId(null);
                instance.setState(PENDING.name());
                workFlowNodeInstanceService.save(instance);
                List<User> users = userService.simplePostName("评估分管副总");
                commit.setComments(comments.equals("1")?"部门工作超负荷":"委托人要求高，无法满足其评估需求");
                if (CollectionUtil.isNotEmpty(users)){
                    WorkTaskRecord workTaskRecord = workTaskRecordService.list(new LambdaUpdateWrapper<WorkTaskRecord>()
                            .eq(WorkTaskRecord::getInstanceId, workFlowNodeInstance.getId()).orderByDesc(BaseEntity::getCreated)).get(0);
                    WorkTaskRecord workTask = BeanUtil.copyProperties(workTaskRecord, WorkTaskRecord.class);
                    workTask.setId(null);
                    workTask.setHandlerId(users.get(0).getId());
                    workTask.setFinished(Boolean.FALSE);
                    workTask.setFinishTime(null);
                    workTask.setInstanceId(instance.getId());
                    workTaskRecordService.save(workTask);
                }
            }
            else{
                commit.setComments(comments.equals("3")?"委托人撤单":"客户经理通知终止");
//                WorkFlowNodeInstance preNode = workFlowNodeInstanceService.list(new LambdaQueryWrapper<WorkFlowNodeInstance>().select(BaseEntity::getId)
//                        .eq(WorkFlowNodeInstance::getFlowId, currentNode.getFlowId())
//                        .eq(WorkFlowNodeInstance::getBusinessId, currentNode.getBusinessId()).eq(WorkFlowNodeInstance::getSequence, (currentNode.getSequence() - 1))
//                        .eq(BaseEntity::getDeleted, Boolean.FALSE).orderByDesc(BaseEntity::getCreated)).get(0);
                WorkNodeDTO orderNode = workNodeService.getUniqueNodeByFlowNameAndNodeName(MAJOR_BUSINESS, OPENING_ORDER);
                //将上一个节点状态改为PENDING
                WorkFlowNodeInstance orderInstance = new WorkFlowNodeInstance();
                orderInstance.setState(PENDING.getCode());
                orderInstance.setNodeId(orderNode.getId());
                orderInstance.setBusinessId(currentNode.getBusinessId());
                orderInstance.setFlowId(orderNode.getFlowId());
                orderInstance.setSequence(0);
                orderInstance.setBusinessType(MAJOR_BUSINESS.name());
                workFlowNodeInstanceService.save(orderInstance);

                WorkFlowNodeInstance oldOrderNode = workFlowNodeInstanceService.list(new LambdaQueryWrapper<WorkFlowNodeInstance>()
                        .eq(WorkFlowNodeInstance::getBusinessId, currentNode.getBusinessId()).orderByAsc(BaseEntity::getCreated)).get(0);

                WorkTaskRecord oldTask = workTaskRecordService.getOne(new LambdaQueryWrapper<WorkTaskRecord>().eq(WorkTaskRecord::getInstanceId, oldOrderNode.getId()));
                WorkTaskRecord workTaskRecord = new WorkTaskRecord();
                workTaskRecord.setInstanceId(orderInstance.getId());
                workTaskRecord.setTaskId(oldTask.getTaskId());
                workTaskRecord.setHandlerId(oldTask.getHandlerId());
                workTaskRecord.setFinished(true);
                workTaskRecord.setFinishTime(oldTask.getFinishTime());
                workTaskRecordService.save(workTaskRecord);
            }

        //删除当前节点
        workFlowNodeInstanceService.delete(instanceNodeId);

        //删除当前节点的待处理的任务记录
        workTaskRecordService.remove(new LambdaQueryWrapper<WorkTaskRecord>().eq(WorkTaskRecord::getInstanceId,instanceNodeId));

        //添加日志
        return addWorkflowLog(commit,currentNode);

    }
}
