package com.dayou.workflow.config;


import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.util.ObjectUtil;
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.bo.SimpleParentModel;
import com.dayou.common.BaseEntity;
import com.dayou.common.SimpleListModel;
import com.dayou.dto.HandlerPermissionDTO;
import com.dayou.dto.WorkNodeCommit;
import com.dayou.dto.WorkNodeDTO;
import com.dayou.entity.*;
import com.dayou.enums.GlobalConfigEnum;
import com.dayou.enums.MainBusinessEnum;
import com.dayou.enums.workflow.*;
import com.dayou.exception.ErrorCode;
import com.dayou.mapper.*;
import com.dayou.service.*;
import com.dayou.service.workflow.IWorkFlowLogService;
import com.dayou.service.workflow.IWorkFlowNodeInstanceService;
import com.dayou.service.workflow.IWorkNodeService;
import com.dayou.service.workflow.IWorkTaskRecordService;
import com.dayou.utils.LoginContext;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.transaction.annotation.Transactional;

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

import static com.dayou.enums.FinanceInvoiceState.审核拒绝;
import static com.dayou.enums.FinanceInvoiceState.审核通过;
import static com.dayou.enums.GlobalConfigEnum.*;
import static com.dayou.enums.MainBusinessEnum.ASSET_BUSINESS;
import static com.dayou.enums.MainBusinessEnum.MAJOR_BUSINESS;
import static com.dayou.enums.workflow.NodeLogEnum.PASS;
import static com.dayou.enums.workflow.NodeStateEnum.*;
import static com.dayou.enums.workflow.WorkflowNodeEnum.LEADER_ALLOCATION;
import static com.dayou.enums.workflow.WorkflowNodeEnum.OPENING_ORDER;

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

    @Autowired
    private IWorkFlowNodeInstanceService workFlowNodeInstanceService;
    @Autowired
    private IWorkTaskRecordService workTaskRecordService;
    @Autowired
    private IWorkFlowLogService workFlowLogService;
    @Autowired
    private WorkTaskRecordMapper workTaskRecordMapper;

    @Autowired
    private IWorkNodeService workNodeService;

    @Autowired
    private IUserPostService userPostService;

    @Autowired
    private IGlobalConfigService globalConfigService;

    @Autowired
    private IDepartmentService departmentService;

    @Autowired
    private WorkFlowNodeInstanceMapper workFlowNodeInstanceMapper;

    @Autowired
    private ICommissionDeclareService commissionDeclareService;

    @Autowired
    private IBusinessPerformanceDistributionService businessPerformanceDistributionService;

    @Autowired
    private IMajorProductionAllotService majorProductionAllotService;

    @Autowired
    private IProductionFundService productionFundService;

    @Autowired
    private IOrderFundService orderFundService;


    /**
     * 提交流程前置处理
     * @param commit
     * @return
     */
    @Transactional
    public WorkNodeDTO beforeForward(WorkNodeCommit commit, WorkFlowNodeInstance currentInstanceNode){
        //节点控制前置处理。
        //当任务不需要当前节点处理人产生业务数据的时候，则把任务状态改为已完成。
        if (!currentInstanceNode.getState().equals(PENDING.name())){
            ErrorCode.throwBusinessException(ErrorCode.COMMIT_STATE_ERROR);
        }
        List<Long> notBusinessHandleTaskId = workTaskRecordMapper.getNotBusinessHandleTaskId(currentInstanceNode.getId());
        if (CollectionUtil.isNotEmpty(notBusinessHandleTaskId)){
            workTaskRecordService.update(new LambdaUpdateWrapper<WorkTaskRecord>().set(WorkTaskRecord::getFinished,Boolean.TRUE)
                    .set(WorkTaskRecord::getFinishTime, LocalDateTime.now()).in(BaseEntity::getId,notBusinessHandleTaskId));
        }
        //需要检查任务完成状态
        if (commit.getState().equals(PASS) && commit.getIfCheckTask()){
            if (checkCurrentNodeTaskState(currentInstanceNode)){
                //将当前节点状态变更成已完成
                workFlowNodeInstanceService.update(new LambdaUpdateWrapper<WorkFlowNodeInstance>().set(WorkFlowNodeInstance::getState,NodeStateEnum.FINISHED)
                        .set(WorkFlowNodeInstance::getComment,commit.getComments()).eq(BaseEntity::getId,currentInstanceNode.getId()));
                addWorkflowLog(commit,currentInstanceNode);
            }else {
                ErrorCode.throwBusinessException(ErrorCode.TASK_NOT_FINISHED);
            }
        }
        //不需要检查任务完成状态(不能解除封印)
//        if (commit.getState().equals(PASS) && !commit.getIfCheckTask()){
//            //将当前节点状态变更成已完成
//            workFlowNodeInstanceService.update(new LambdaUpdateWrapper<WorkFlowNodeInstance>().set(WorkFlowNodeInstance::getState,NodeStateEnum.FINISHED)
//                    .set(WorkFlowNodeInstance::getComment,commit.getComments()).eq(BaseEntity::getId,currentInstanceNode.getId()));
//            addWorkflowLog(commit,currentInstanceNode);
//        }

        //寻找下一个节点，有可能下一个节点并非流程配置的节点，需根据业务数据变动
        WorkNodeDTO nextWorkNode = workNodeService.getNextWorkNode(currentInstanceNode.getFlowId(), currentInstanceNode.getNodeId());

        if (commit.getIfSkip()!=null && commit.getIfSkip()){
            nextWorkNode = workNodeService.getNextWorkNode(currentInstanceNode.getFlowId(), nextWorkNode.getId());
        }

//        if (nextWorkNode==null){
//            ErrorCode.throwBusinessException(ErrorCode.NEXT_NODE_NOT_EXISTS);
//        }

        return nextWorkNode;
    }


    public boolean forward(WorkNodeCommit workNodeCommit) {
        WorkFlowNodeInstance currentInstanceNode = workFlowNodeInstanceMapper.getById(workNodeCommit.getInstanceNodeId());
        WorkNodeDTO nextWorkNode = beforeForward(workNodeCommit,currentInstanceNode);
        if (nextWorkNode!=null){
            addNextInstanceNode(currentInstanceNode,nextWorkNode, workNodeCommit.getNextHandlerId(),workNodeCommit.getBusinessSubId(),workNodeCommit.getBusinessMinId());
        }else {
            //下一个节点为空，代表整体流程结束。如果需要对业务数据的修改请在这个方法里处理
            afterForward(currentInstanceNode);
        }
        return Boolean.TRUE;
    }

    public void afterForward(WorkFlowNodeInstance currentInstanceNode) {
        //终止前节点控制前置处理。
        MainBusinessEnum mainBusinessEnum = MainBusinessEnum.valueOf(currentInstanceNode.getBusinessType());
        switch (mainBusinessEnum){
            case COMMISSION_DECLARE_MAJOR_EVALUATE:
            case COMMISSION_DECLARE_MAJOR_MARKET:
            case COMMISSION_DECLARE_ASSET_EVALUATE:
            case COMMISSION_DECLARE_ASSET_MARKET:
                commissionDeclareService.update(new LambdaUpdateWrapper<CommissionDeclare>().set(CommissionDeclare::getDeclareResult,审核通过.name())
                        .eq(BaseEntity::getId,currentInstanceNode.getBusinessId()));
                break;
        }
    }


    /**
     * 跳过
     * @param commit
     * @return
     */
    @Transactional
    public boolean skip(WorkNodeCommit commit){
        return Boolean.FALSE;
    }

    /**
     * 退回
     * @param commit
     * @return
     */
    @Transactional
    public boolean goBack(WorkNodeCommit commit){
        Long instanceNodeId = commit.getInstanceNodeId();
        WorkFlowNodeInstance currentNode = workFlowNodeInstanceService.getById(instanceNodeId);

        //将上一个节点状态改为PENDING
        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,commit.getBusinessSubId())
                .eq(StrUtil.isNotEmpty(commit.getBusinessMinId()),WorkFlowNodeInstance::getBusinessMinId,commit.getBusinessMinId())
                .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(StrUtil.isNotEmpty(commit.getBusinessSubId()),WorkFlowNodeInstance::getBusinessSubId,commit.getBusinessSubId())
                .eq(StrUtil.isNotEmpty(commit.getBusinessMinId()),WorkFlowNodeInstance::getBusinessMinId,commit.getBusinessMinId())
                .eq(BaseEntity::getDeleted, Boolean.FALSE));

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

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

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

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

    }

    /**
     * 重置
     * @param commit
     * @return
     */
    public boolean reset(WorkNodeCommit commit){
        //todo
        return Boolean.FALSE;
    }

    /**
     * 终止
     * @param commit
     * @return
     */
    @Transactional
    public boolean ending(WorkNodeCommit commit){
        WorkFlowNodeInstance currentNode = workFlowNodeInstanceService.getById(commit.getInstanceNodeId());
        beforeEnding(currentNode);
        //只需将当前节点设置为终止状态。
        workFlowNodeInstanceService.update(new LambdaUpdateWrapper<WorkFlowNodeInstance>().set(WorkFlowNodeInstance::getState,CLOSED)
                        .set(WorkFlowNodeInstance::getComment,commit.getComments())
                .eq(WorkFlowNodeInstance::getId,commit.getInstanceNodeId()));

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


    public Long searchHandlerId(WorkFlowNodeInstance instanceNode, HandlerPermissionDTO handlerPermissionDTO){
        HandlerPermissionEnum handlerPermissionEnum = handlerPermissionDTO.getName();

        switch (handlerPermissionEnum){
            case EMPLOYEE:
                return handlerPermissionDTO.getPowerId();
            case POST:
                return userPostService.getUniqueHandlerByPostForWorkNode(handlerPermissionDTO.getPowerId());
            case DEPARTMENT_LEADER:
                return getDepartmentLeaderByBusinessType(instanceNode.getBusinessType());
            case SYSTEM:
                //暂无程序处理逻辑
                return 0L;
            default:
                //实在找不到审批人 交由部门领导处理
                return 0L;
        }
    }

    /**
     * 检查节点任务状态
     * @param currentInstanceNode
     * @return
     */
    private Boolean checkCurrentNodeTaskState(WorkFlowNodeInstance currentInstanceNode){
        List<WorkTaskRecord> notFinish = workTaskRecordService.list(new LambdaQueryWrapper<WorkTaskRecord>().eq(WorkTaskRecord::getInstanceId, currentInstanceNode.getId())
                .eq(WorkTaskRecord::getFinished,Boolean.FALSE)
                .eq(BaseEntity::getDeleted, Boolean.FALSE));
        return CollectionUtil.isEmpty(notFinish);

    }

    /**
     * 添加流程日志
     * @param workNodeCommit
     */
    protected boolean addWorkflowLog(WorkNodeCommit workNodeCommit,WorkFlowNodeInstance currentInstanceNode){
        WorkFlowLog log = new WorkFlowLog();
        log.setBusinessId(currentInstanceNode.getBusinessId());
        log.setBusinessType(currentInstanceNode.getBusinessType());
        log.setHandingTime(new Date().getTime() - currentInstanceNode.getCreated().getTime());
        log.setHandlerId(LoginContext.getCurrentUserId());
        log.setComments(workNodeCommit.getComments());
        log.setState(workNodeCommit.getState().name());
        log.setInstanceId(workNodeCommit.getInstanceNodeId());
        log.setBusinessSubId(workNodeCommit.getBusinessSubId());
        log.setBusinessMinId(workNodeCommit.getBusinessMinId());
        return workFlowLogService.add(log);
    }

    /**
     * 构建节点实例
     * @param nextWorkNode
     * @param currentInstanceNode
     * @param businessSubId
     * @param businessMinId
     * @return
     */
    private WorkFlowNodeInstance buildNodeInstance(WorkNodeDTO nextWorkNode, WorkFlowNodeInstance currentInstanceNode, String businessSubId, String businessMinId){
        WorkFlowNodeInstance nodeInstance = new WorkFlowNodeInstance();
        nodeInstance.setNodeId(nextWorkNode.getId());
        nodeInstance.setFlowId(nextWorkNode.getFlowId());
        nodeInstance.setBusinessId(currentInstanceNode.getBusinessId());
        nodeInstance.setBusinessSubId(businessSubId);
        nodeInstance.setBusinessMinId(businessMinId);
        nodeInstance.setBusinessType(currentInstanceNode.getBusinessType());
        nodeInstance.setSequence((currentInstanceNode.getSequence()==null?0:currentInstanceNode.getSequence())+1);
        nodeInstance.setState(NodeStateEnum.PENDING.name());
        return nodeInstance;
    }

    /**
     * 创建运行时的下一个节点实例
     * @param currentInstanceNode
     */
    protected void addNextInstanceNode(WorkFlowNodeInstance currentInstanceNode,WorkNodeDTO nextWorkNode,Long handlerId,String businessSubId,String businessMinId){
        if (nextWorkNode!=null){
            List<WorkNodeTask> tasks = nextWorkNode.getTasks();
            //如果该节点下面只有一个任务，且由系统控制。则需要相关条件判断需不需要创建该节点实例
            WorkFlowNodeInstance nodeInstance = buildNodeInstance(nextWorkNode, currentInstanceNode,businessSubId,businessMinId);
            workFlowNodeInstanceService.add(nodeInstance);
            if (CollectionUtil.isNotEmpty(tasks)){
                workTaskRecordService.doCreateNodeTaskRecord(this,tasks,nodeInstance,handlerId);
            }
            // 节点下面没有任务，说明是状态节点。状态节点业务上未定义逻辑
        }
    }

    /**
     * 根据业务类型确定需要找到的部门领导，A既可以是市场部也可以是评估部，确定部门时就需要看是什么样的业务类型
     * @param businessType
     * @return
     */
    protected Long getDepartmentLeaderByBusinessType(String businessType){
        List<SimpleParentModel> departmentList = LoginContext.getLoginCacheUserBO().getDepartmentList();
        List<Long> ownDepIds = departmentList.stream().map(SimpleListModel::getId).collect(Collectors.toList());
        if (CollectionUtil.isEmpty(ownDepIds)){
            ErrorCode.throwBusinessException(ErrorCode.CUSTOM_ERROR,"用户部门岗位未设置。");
        }
        switch (MainBusinessEnum.valueOf(businessType)){
            case COMMISSION_DECLARE_MAJOR_MARKET:
                return findDepartmentLeader(ownDepIds,COMMISSION_MAJOR_MARKET_DEPARTMENT);
            case COMMISSION_DECLARE_MAJOR_EVALUATE:
                return findDepartmentLeader(ownDepIds,COMMISSION_MAJOR_EVALUATE_DEPARTMENT);
            case COMMISSION_DECLARE_ASSET_MARKET:
                return findDepartmentLeader(ownDepIds,COMMISSION_ASSET_MARKET_DEPARTMENT);
            case COMMISSION_DECLARE_ASSET_EVALUATE:
                return findDepartmentLeader(ownDepIds,COMMISSION_ASSET_EVALUATE_DEPARTMENT);
        }
        return 0L;
    }

    private Long findDepartmentLeader(List<Long> ownDepIds,GlobalConfigEnum configEnum){
        List<GlobalConfig> list = globalConfigService.getConfigByKey( configEnum.name());
        if (CollectionUtil.isEmpty(list)){
            ErrorCode.throwBusinessException(ErrorCode.CUSTOM_ERROR, configEnum.getDesc()+"未配置。");
        }
        List<String> dIds = list.stream().filter(x->StrUtil.isNotBlank(x.getValue())).map(GlobalConfig::getValue).collect(Collectors.toList());
        if (CollectionUtil.isEmpty(dIds)){
            ErrorCode.throwBusinessException(ErrorCode.CUSTOM_ERROR,configEnum.getDesc()+"未配置。");
        }
        List<Long> xIds = dIds.stream().map(x -> { return  Long.valueOf(x);}).collect(Collectors.toList());
        List<Long> targetIds = ownDepIds.stream().filter(xIds::contains).collect(Collectors.toList());
        if (targetIds.size()==0){
            ErrorCode.throwBusinessException(ErrorCode.CUSTOM_ERROR,"抱歉，您不属于"+configEnum.getDesc()+"人员。");
        }
        //多个默认第一个，保证流程顺畅
        Department department = departmentService.getById(targetIds.get(0));
        if (department.getLeaderId()==null){
            ErrorCode.throwBusinessException(ErrorCode.CUSTOM_ERROR,department.getName() +" 部门领导未设置。");
        }
        return department.getLeaderId();
    }

    @Transactional(rollbackFor = Exception.class)
    public void beforeEnding(WorkFlowNodeInstance currentInstanceNode){
        //终止前节点控制前置处理。
        MainBusinessEnum mainBusinessEnum = MainBusinessEnum.valueOf(currentInstanceNode.getBusinessType());
        switch (mainBusinessEnum){
            case COMMISSION_DECLARE_MAJOR_EVALUATE:
            case COMMISSION_DECLARE_MAJOR_MARKET:
                commissionDeclareService.update(new LambdaUpdateWrapper<CommissionDeclare>().set(CommissionDeclare::getDeclareResult,审核拒绝.name())
                        .eq(BaseEntity::getId,currentInstanceNode.getBusinessId()));
                majorProductionAllotService.update(new LambdaUpdateWrapper<MajorProductionAllot>()
                        .set(MajorProductionAllot::getDeleted, 1)
                        .eq(MajorProductionAllot::getDeclareId, currentInstanceNode.getBusinessId()));
                break;
            case COMMISSION_DECLARE_ASSET_MARKET:
            case COMMISSION_DECLARE_ASSET_EVALUATE:
                // 更新审核状态
                commissionDeclareService.update(new LambdaUpdateWrapper<CommissionDeclare>().set(CommissionDeclare::getDeclareResult,审核拒绝.name())
                        .eq(BaseEntity::getId,currentInstanceNode.getBusinessId()));
                // 更新绩效分配信息deleted
                businessPerformanceDistributionService.update(new LambdaUpdateWrapper<BusinessPerformanceDistribution>()
                        .set(BusinessPerformanceDistribution :: getDeleted, 1)
                        .eq(BusinessPerformanceDistribution::getDeclareId ,currentInstanceNode.getBusinessId()));
            case ASSET_BUSINESS: // 资产流程终止节点前的处理
                // 删除节点任务
                workTaskRecordService.update(new LambdaUpdateWrapper<WorkTaskRecord>().set(BaseEntity::getDeleted, true).eq(WorkTaskRecord::getInstanceId, currentInstanceNode.getId()));

                // 判断是否出具了产品,出具了产品的话需要将产品应收款改为0
                if (ObjectUtil.isNotNull(currentInstanceNode.getBusinessSubId()) && !currentInstanceNode.getBusinessSubId().isEmpty()) {
                    // 预评
                    productionFundService.update(new LambdaUpdateWrapper<ProductionFund>()
                            .set(ProductionFund::getProductionShouldAmount, 0)
                            .eq(ProductionFund::getBusinessType, ASSET_BUSINESS.getCode())
                            .eq(ProductionFund::getBusinessId, currentInstanceNode.getBusinessId())
                            .eq(ProductionFund::getProductionNo, currentInstanceNode.getBusinessSubId())
                            .eq(BaseEntity::getDeleted, false));
                }
                if (ObjectUtil.isNotNull(currentInstanceNode.getBusinessMinId()) && !currentInstanceNode.getBusinessMinId().isEmpty()) {
                    // 报告
                    productionFundService.update(new LambdaUpdateWrapper<ProductionFund>()
                            .set(ProductionFund::getProductionShouldAmount, 0)
                            .eq(ProductionFund::getBusinessType, ASSET_BUSINESS.getCode())
                            .eq(ProductionFund::getBusinessId, currentInstanceNode.getBusinessId())
                            .eq(ProductionFund::getProductionNo, currentInstanceNode.getBusinessMinId())
                            .eq(BaseEntity::getDeleted, false));
                }
                break;
            case MAJOR_BUSINESS: // 大中型流程终止节点前的处理
                // 删除节点任务
                workTaskRecordService.update(new LambdaUpdateWrapper<WorkTaskRecord>().set(BaseEntity::getDeleted, true).eq(WorkTaskRecord::getInstanceId, currentInstanceNode.getId()));

                // 判断是否出具了产品,出具了产品的话需要将产品应收款改为0
                if (ObjectUtil.isNotNull(currentInstanceNode.getBusinessSubId()) && !currentInstanceNode.getBusinessSubId().isEmpty()) {
                    // 预评
                    productionFundService.update(new LambdaUpdateWrapper<ProductionFund>()
                            .set(ProductionFund::getProductionShouldAmount, 0)
                            .eq(ProductionFund::getBusinessType, MAJOR_BUSINESS.getCode())
                            .eq(ProductionFund::getBusinessId, currentInstanceNode.getBusinessId())
                            .eq(ProductionFund::getProductionNo, currentInstanceNode.getBusinessSubId())
                            .eq(BaseEntity::getDeleted, false));
                }
                if (ObjectUtil.isNotNull(currentInstanceNode.getBusinessMinId()) && !currentInstanceNode.getBusinessMinId().isEmpty()) {
                    // 报告
                    productionFundService.update(new LambdaUpdateWrapper<ProductionFund>()
                            .set(ProductionFund::getProductionShouldAmount, 0)
                            .eq(ProductionFund::getBusinessType, MAJOR_BUSINESS.getCode())
                            .eq(ProductionFund::getBusinessId, currentInstanceNode.getBusinessId())
                            .eq(ProductionFund::getProductionNo, currentInstanceNode.getBusinessMinId())
                            .eq(BaseEntity::getDeleted, false));
                }
                break;
            case PERSONAL_BUSINESS: // 个贷业务流程终止节点前的处理
                // 删除节点任务
                workTaskRecordService.update(new LambdaUpdateWrapper<WorkTaskRecord>().set(BaseEntity::getDeleted, true).eq(WorkTaskRecord::getInstanceId, currentInstanceNode.getId()));
                break;
        }
    }

    public Boolean refuse(WorkNodeCommit workNodeCommit) {
        //todo
        return Boolean.FALSE;
    }
}
