package com.dayou.workflow.handler;

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.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.mapper.AssetsMapper;
import com.dayou.mapper.DepartmentMapper;
import com.dayou.mapper.WorkFlowNodeInstanceMapper;
import com.dayou.service.IAssetsProductionService;
import com.dayou.service.IUserPostService;
import com.dayou.service.IUserService;
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.time.LocalDate;
import java.util.Arrays;
import java.util.Date;
import java.util.List;
import java.util.Map;

import static com.dayou.enums.workflow.NodeStateEnum.PENDING;
import static com.dayou.enums.workflow.NodeStateEnum.SKIP;
import static com.dayou.enums.workflow.WorkflowNodeEnum.*;

@Component
public class AssetsNodeHandler extends WorkNodeProcessable {

    @Autowired
    private AssetsMapper assetsMapper;

    @Autowired
    private IAssetsProductionService assetsProductionService;

    @Autowired
    private DepartmentMapper departmentMapper;

    @Autowired
    private IUserPostService userPostService;

    @Autowired
    private IWorkNodeService workNodeService;

    @Autowired
    private WorkFlowNodeInstanceMapper workFlowNodeInstanceMapper;

    @Autowired
    private IWorkFlowNodeInstanceService workFlowNodeInstanceService;

    @Autowired
    private IWorkTaskRecordService workTaskRecordService;

    @Autowired
    private IUserService userService;


    @Override
    public boolean forward(WorkNodeCommit workNodeCommit) {
        WorkFlowNodeInstance currentInstanceNode = workFlowNodeInstanceMapper.getById(workNodeCommit.getInstanceNodeId());
        WorkNodeDTO nextWorkNode = beforeForward(workNodeCommit, currentInstanceNode);
        if (ObjectUtil.isNotNull(nextWorkNode)) {
            String ifVerify = currentInstanceNode.getVerify();
            if (StrUtil.isNotEmpty(ifVerify)) {
                CallbackEnum callback = CallbackEnum.valueOf(ifVerify);
                //根据callback 确定具体的业务数据
                //获取产品类型
                List<ProductionEnum> production = workNodeCommit.getProduction();
                switch (callback) {
                    // 校验资产产品类型
                    case CHECK_ASSET_PRODUCTION_TYPE:
                        //1. 获取业务上出具的产品类型。
                        //2.根据出具的产品类型 确定需要哪些节点
                        Map<String, List<WorkflowNodeEnum>> assetsNecessaryNodes = CallbackEnum.NecessaryNode.getByProduction(MainBusinessEnum.ASSET_BUSINESS.name(),
                                production);
                        nextWorkNode = workNodeService.getNextWorkNodeByBusiness(currentInstanceNode.getFlowId(), MainBusinessEnum.ASSET_BUSINESS, currentInstanceNode.getNodeCode(), assetsNecessaryNodes, null);
                        break;
                    // 校验资产四审
                    case CHECK_ASSET_FOURTH_CHECK_REPORT:
                        // doFourthCheck为真则执行四审节点,为假则跳过四审节点
                        if (!workNodeCommit.getDoFourthCheck()) {
                            nextWorkNode = workNodeService.getNextWorkNodeByFourthCheckState(currentInstanceNode.getFlowId(), currentInstanceNode.getNodeCode());
                        }
                        break;
                    // 校验订单实收款
                    case CHECK_ASSET_ORDER_FUND:
                        // 产品已有实收款则跳过出库申请
                        if (workNodeCommit.getIfProductionFund()) {
                            nextWorkNode = workNodeService.getNextWorkNodeByFourthCheckState(currentInstanceNode.getFlowId(), currentInstanceNode.getNodeCode());
                        }
                        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.GENERATE_STATEMENT)) {
                    for (String businessSubId : workNodeCommit.getReportNos()) {
                        addNextInstanceNode(currentInstanceNode, nextWorkNode, workNodeCommit.getNextHandlerId(), businessSubId, null);
                    }
                } else if (workflowNodeEnum.equals(WorkflowNodeEnum.WRITE_REPORT)) {
                    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());
            }
            return Boolean.TRUE;
        }
        // 判断下一个节点为null,且当前节点为 归档 时, 返回TRUE
        if (ObjectUtil.isNull(nextWorkNode)) {
            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.BUSINESS_ARCHIVING)) {
                // 将产品归档状态与归档时间更新
                assetsProductionService.prodSaveFile(new Date(), workNodeCommit.getBusinessSubId());
                assetsProductionService.prodSaveFile(new Date(), workNodeCommit.getBusinessMinId());
                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> checkNodes = Arrays.asList(REVIEW_STATEMENT.name(), CHECK_REPORT.name());

        // 用于判断是否是复审节点进行退回操作
        List<String> reCheckNodes = Arrays.asList(REEXAMINE_STATEMENT.name(), RECHECK_REPORT.name());

        if (checkNodes.contains(currentNode.getNodeCode())) { // 审核节点退回到撰写节点
            //将上一个节点状态改为PENDING
            workFlowNodeInstanceService.update(new LambdaUpdateWrapper<WorkFlowNodeInstance>()
                    .set(WorkFlowNodeInstance::getState, PENDING)
                    .eq(WorkFlowNodeInstance::getBusinessId, currentNode.getBusinessId())
                    // 如果subId和minId都不为空,有可能意见书开始就已经流程分叉,所以需要判断一下subId
                    .eq(ObjectUtil.isNotNull(currentNode.getBusinessSubId()) && ObjectUtil.isNotNull(currentNode.getBusinessMinId()), WorkFlowNodeInstance::getBusinessSubId, currentNode.getBusinessSubId())
                    .eq(WorkFlowNodeInstance::getFlowId, currentNode.getFlowId())
                    .eq(WorkFlowNodeInstance::getSequence, (currentNode.getSequence() - 1))
                    .eq(BaseEntity::getDeleted, Boolean.FALSE));
            //删除当前节点
            workFlowNodeInstanceService.delete(instanceNodeId);

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

            //添加日志
            return addWorkflowLog(commit, currentNode);
        } else if (reCheckNodes.contains(currentNode.getNodeCode())) { // 复审节点退回跳过审核节点直接到撰写节点

            // 获取上一个审核节点的信息(审核节点可能会流程分叉,所以还要判断subId和minId)
            WorkFlowNodeInstance skipNode = workFlowNodeInstanceService.getOne(new LambdaQueryWrapper<WorkFlowNodeInstance>()
                    .eq(WorkFlowNodeInstance::getBusinessId, currentNode.getBusinessId())
                    .eq(ObjectUtil.isNotNull(currentNode.getBusinessSubId()), WorkFlowNodeInstance::getBusinessSubId, currentNode.getBusinessSubId())
                    .eq(ObjectUtil.isNotNull(currentNode.getBusinessMinId()), WorkFlowNodeInstance::getBusinessMinId, currentNode.getBusinessMinId())
                    .eq(WorkFlowNodeInstance::getFlowId, currentNode.getFlowId())
                    .eq(WorkFlowNodeInstance::getSequence, (currentNode.getSequence() - 1))
                    .eq(BaseEntity::getDeleted, Boolean.FALSE));

            // 将上一个审核节点删除
            workFlowNodeInstanceService.delete(skipNode.getId());
            // 将上一个审核节点的任务删除
            workTaskRecordService.remove(new LambdaQueryWrapper<WorkTaskRecord>().eq(WorkTaskRecord::getInstanceId, skipNode.getId()));

            //将上上个撰写节点状态改为PENDING
            workFlowNodeInstanceService.update(new LambdaUpdateWrapper<WorkFlowNodeInstance>()
                    .set(WorkFlowNodeInstance::getState, PENDING)
                    .eq(WorkFlowNodeInstance::getBusinessId, currentNode.getBusinessId())
                    // 如果subId和minId都不为空,有可能意见书开始就已经流程分叉,所以需要判断一下subId
                    .eq(ObjectUtil.isNotNull(currentNode.getBusinessSubId()) && ObjectUtil.isNotNull(currentNode.getBusinessMinId()), WorkFlowNodeInstance::getBusinessSubId, currentNode.getBusinessSubId())
                    .eq(WorkFlowNodeInstance::getFlowId, currentNode.getFlowId())
                    .eq(WorkFlowNodeInstance::getSequence, (currentNode.getSequence() - 2))
                    .eq(BaseEntity::getDeleted, Boolean.FALSE));

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

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

            //添加日志
            return addWorkflowLog(commit, currentNode);
        } else {
            return super.goBack(commit);
        }
    }

    /**
     * 选择节点处理人
     *
     * @param instanceNode         节点实列
     * @param handlerPermissionDTO
     * @return Long
     */
    @Override
    public Long searchHandlerId(WorkFlowNodeInstance instanceNode, HandlerPermissionDTO handlerPermissionDTO) {
        HandlerPermissionEnum handlerPermissionEnum = handlerPermissionDTO.getName();
        Assets assets = assetsMapper.selectOne(new LambdaQueryWrapper<Assets>().select(Assets::getClientManagerId, Assets::getPrincipalId, Assets::getDepartmentId)
                .eq(BaseEntity::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, assets.getDepartmentId())).getLeaderId()
                        : handlerId;
            case DEPARTMENT_LEADER:
                return departmentMapper.selectOne(new LambdaQueryWrapper<Department>().select(Department::getLeaderId).eq(BaseEntity::getId, assets.getDepartmentId())).getLeaderId();
            case CLIENT_MANAGER:
            case INITIATOR:
                return assets.getClientManagerId();
            case PRINCIPAL:
                return assets.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, assets.getDepartmentId())).getLeaderId();
        }
    }
}
