package com.dayou.workflow.handler;

import cn.hutool.core.util.StrUtil;
import com.alibaba.fastjson.JSON;
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.DepartmentMapper;
import com.dayou.mapper.PersonalMapper;
import com.dayou.mapper.WorkFlowNodeInstanceMapper;
import com.dayou.service.ICustomerCompanyService;
import com.dayou.service.IPersonalProductionService;
import com.dayou.service.IPersonalTargetService;
import com.dayou.service.IUserPostService;
import com.dayou.service.workflow.IWorkFlowNodeInstanceService;
import com.dayou.service.workflow.IWorkNodeService;
import com.dayou.workflow.config.WorkNodeProcessable;
import com.google.common.collect.Lists;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import java.util.Arrays;
import java.util.Date;
import java.util.List;
import java.util.Map;

import static com.dayou.common.Constants.PERSONAL_DEPARTMENT;
import static com.dayou.enums.FinanceInvoiceState.审核通过;
import static com.dayou.enums.MainBusinessEnum.PERSONAL_BUSINESS;
import static com.dayou.enums.ProductionEnum.*;
import static com.dayou.enums.workflow.WorkflowNodeEnum.*;

/**
 * 类说明：
 *
 * @author: wucl
 * @since: 2024/3/4
 * created with IntelliJ IDEA.
 */
@Component
public class PersonalNodeHandler extends WorkNodeProcessable {

    @Autowired
    private PersonalMapper personalMapper;

    @Autowired
    private DepartmentMapper departmentMapper;

    @Autowired
    private IUserPostService userPostService;

    @Autowired
    private IWorkNodeService workNodeService;

    @Autowired
    private ICustomerCompanyService customerCompanyService;

    @Autowired
    private WorkFlowNodeInstanceMapper workFlowNodeInstanceMapper;

    @Autowired
    private IPersonalTargetService personalTargetService;

    @Autowired
    private IPersonalProductionService personalProductionService;

    @Autowired
    private IWorkFlowNodeInstanceService workFlowNodeInstanceService;


    @Override
    public boolean forward(WorkNodeCommit workNodeCommit) {
        WorkFlowNodeInstance currentInstanceNode = workFlowNodeInstanceMapper.getById(workNodeCommit.getInstanceNodeId());
        WorkNodeDTO nextWorkNode = beforeForward(workNodeCommit,currentInstanceNode);
        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_PERSONAL_PRODUCTION_TYPE:
                            //检查是否需要修改产品
                            WorkNodeDTO workNodeDTO = workNodeService.changeProductionRetNextNode(currentInstanceNode.getNodeCode(), production, currentInstanceNode.getBusinessId());
                            if (workNodeDTO==null){
                                //1. 获取业务上出具的产品类型。
                                //2.根据出具的产品类型 确定需要哪些节点
                                Map<String, List<WorkflowNodeEnum>> personalNecessaryNodes = CallbackEnum.NecessaryNode.getByProduction(PERSONAL_BUSINESS.name(),
                                        production);
                                WorkNodeDTO next = workNodeService.getNextWorkNodeByBusiness(currentInstanceNode.getFlowId(), PERSONAL_BUSINESS, currentInstanceNode.getNodeCode(), personalNecessaryNodes, null);
                                if (next != null) {
                                    nextWorkNode = next;
                                }
                            }else{
                                nextWorkNode = workNodeDTO;
                            }
                            break;
                        case CHECK_FEEDBACK:
                            if (workNodeCommit.getIfFeedback()!=null && !workNodeCommit.getIfFeedback()) {
                                Map<String, List<WorkflowNodeEnum>> xPersonalNecessaryNodes = CallbackEnum.NecessaryNode.getByProduction(PERSONAL_BUSINESS.name(),
                                        production);
                                nextWorkNode = workNodeService.getNextWorkNodeByBusiness(currentInstanceNode.getFlowId(), PERSONAL_BUSINESS, QUOTATION_FEEDBACK.name(), xPersonalNecessaryNodes,null);
                            }
                            break;
                        case CHECK_PERSONAL_CLIENT_TYPE:
                            Long ccId = workNodeCommit.getCcId();
                            if (ccId !=null){
                                if (customerCompanyService.avoidWareHouseApply(ccId)){
                                    if (currentInstanceNode.getNodeCode().equals(REPORT_IN.name())){
                                        nextWorkNode = workNodeService.getUniqueNodeByFlowNameAndNodeName(PERSONAL_BUSINESS,REPORT_OUT);
                                    }else {
                                        nextWorkNode = workNodeService.getUniqueNodeByFlowNameAndNodeName(PERSONAL_BUSINESS,LETTER_OUT);
                                    }
                                }
                            }
                    }
                }
            }
            addNextInstanceNode(currentInstanceNode,nextWorkNode, workNodeCommit.getNextHandlerId(),workNodeCommit.getBusinessSubId(),workNodeCommit.getBusinessMinId());
            afterForward(currentInstanceNode);
            return Boolean.TRUE;
        }
        return Boolean.FALSE;
    }

    @Override
    public Long searchHandlerId(WorkFlowNodeInstance instanceNode, HandlerPermissionDTO handlerPermissionDTO){
        HandlerPermissionEnum handlerPermissionEnum = handlerPermissionDTO.getName();
        Personal personal = personalMapper.selectOne(new LambdaQueryWrapper<Personal>().select(Personal::getClientManagerId, Personal::getInwardStaff, Personal::getOutwardStaff, Personal::getPricingStaff)
                .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(Department::getName,PERSONAL_DEPARTMENT)).getLeaderId()
                        :handlerId;
            case DEPARTMENT_LEADER:
                return departmentMapper.selectOne(new LambdaQueryWrapper<Department>().select(Department::getLeaderId).eq(Department::getName,PERSONAL_DEPARTMENT)).getLeaderId();
            case CLIENT_MANAGER:
                return personal.getClientManagerId();
            case OUTWARD_STAFF:
                return personal.getOutwardStaff();
            case INWARD_STAFF:
                return personal.getInwardStaff();
            case PRICING_STAFF:
                return personal.getPricingStaff();
            case SYSTEM:
                //暂无程序处理逻辑
                return 0L;
            default:
                //实在找不到审批人 交由部门领导处理
                return departmentMapper.selectOne(new LambdaQueryWrapper<Department>().select(Department::getLeaderId).eq(Department::getName,PERSONAL_DEPARTMENT)).getLeaderId();
        }
    }

    @Override
    public boolean goBack(WorkNodeCommit commit){
        Long instanceNodeId = commit.getInstanceNodeId();
        WorkFlowNodeInstance currentNode = workFlowNodeInstanceMapper.getInstanceNodeInfoById(instanceNodeId);
        //如果是撰写节点（意见书，报告，复评函）退回。需删除产品业务信息
        List<String> needToCleanFeedbackNodes = Arrays.asList(new String[]{QUOTATION_FEEDBACK.name(), GENERATE_STATEMENT.name(),WRITE_REPORT.name(), WRITE_LETTER.name(),COMMIT_FILE.name()});
        if (needToCleanFeedbackNodes.contains(currentNode.getNodeCode())){
            //如果是在撰写意见书退回，清空反馈
            PersonalTarget target = personalTargetService.getOne(new LambdaQueryWrapper<PersonalTarget>().select(PersonalTarget::getFeedback, BaseEntity::getId)
                    .eq(PersonalTarget::getPersonalId, currentNode.getBusinessId()).eq(BaseEntity::getDeleted, Boolean.FALSE));
            if (currentNode.getNodeCode().equals(GENERATE_STATEMENT.name())){
                personalTargetService.update(new LambdaUpdateWrapper<PersonalTarget>().set(
                        PersonalTarget::getFeedback,null
                ).eq(BaseEntity::getId,target.getId()));
            }
            else{

                if (StrUtil.isNotEmpty(target.getFeedback())){
                    List<String> productionTypes = JSON.parseArray(target.getFeedback(), String.class);
                    if (productionTypes.size()>1){
                        List<String> xProductionType = Lists.newArrayList(productionTypes.get(0));
                        personalTargetService.update(new LambdaUpdateWrapper<PersonalTarget>()
                                .set(PersonalTarget::getFeedback,JSON.toJSONString(xProductionType)).eq(BaseEntity::getId,target.getId()));

                    }
                    else {
                        personalTargetService.update(new LambdaUpdateWrapper<PersonalTarget>().set(
                                PersonalTarget::getFeedback,null
                        ).eq(BaseEntity::getId,target.getId()));
                    }
                }
            }

        }

        // 清除产品完成时间
        cleanProductionTime(currentNode);

        return super.goBack(commit);
    }

    /**
     * 节点完成后操作
     * @param currentInstanceNode 实例信息
     */
    @Override
    public void afterForward(WorkFlowNodeInstance currentInstanceNode) {
        // 审核节点完成后,更新产品完成时间
        PersonalTarget target = personalTargetService.getOne(new LambdaQueryWrapper<PersonalTarget>()
                .select(BaseEntity::getId)
                .eq(PersonalTarget::getPersonalId, currentInstanceNode.getBusinessId())
                .eq(PersonalTarget::getDeleted, false));
        // 通用的更新wrapper
        LambdaUpdateWrapper<PersonalProduction> productionTimeUpdateWrapper = new LambdaUpdateWrapper<PersonalProduction>()
                .eq(BaseEntity::getDeleted, false)
                .eq(PersonalProduction::getTargetId, target.getId());
        Date nodeFinishedTime;
        switch (WorkflowNodeEnum.valueOf(currentInstanceNode.getNodeCode())){
            // 审核意见书
            case REVIEW_STATEMENT:
                nodeFinishedTime = workFlowNodeInstanceService.getNodeFinishedTime(PERSONAL_BUSINESS, GENERATE_STATEMENT, currentInstanceNode.getBusinessId(), currentInstanceNode.getBusinessSubId(), null);
                productionTimeUpdateWrapper.eq(PersonalProduction::getProduction, STATEMENT.getCode())
                        .set(PersonalProduction::getProductionTime, nodeFinishedTime);
                personalProductionService.update(productionTimeUpdateWrapper);
                break;
            // 审核报告报告(包含技术报告和结果报告)
            case CHECK_REPORT:
                nodeFinishedTime = workFlowNodeInstanceService.getNodeFinishedTime(PERSONAL_BUSINESS, WRITE_REPORT, currentInstanceNode.getBusinessId(), currentInstanceNode.getBusinessSubId(), null);
                productionTimeUpdateWrapper.and(temp->temp.eq(PersonalProduction::getProduction,TECHNIC.getCode()).or().eq(PersonalProduction::getProduction,FINAL.getCode()))
                        .set(PersonalProduction::getProductionTime, nodeFinishedTime);
                personalProductionService.update(productionTimeUpdateWrapper);
                break;
            // 审核复评函
            case CHECK_LETTER:
                nodeFinishedTime = workFlowNodeInstanceService.getNodeFinishedTime(PERSONAL_BUSINESS, WRITE_LETTER, currentInstanceNode.getBusinessId(), currentInstanceNode.getBusinessSubId(), null);
                productionTimeUpdateWrapper.eq(PersonalProduction::getProduction, LETTER.getCode())
                        .set(PersonalProduction::getProductionTime, nodeFinishedTime);
                personalProductionService.update(productionTimeUpdateWrapper);
                break;
        }
    }

    /**
     * 根据节点判断是否清除产品完成时间
     * @param currentInstanceNode 当前节点
     */
    public void cleanProductionTime(WorkFlowNodeInstance currentInstanceNode) {
        // 判断是否是从审核节点退回到撰写节点,是的话需要清空产品的productionTime
        PersonalTarget target = personalTargetService.getOne(new LambdaQueryWrapper<PersonalTarget>()
                .select(BaseEntity::getId)
                .eq(PersonalTarget::getPersonalId, currentInstanceNode.getBusinessId())
                .eq(PersonalTarget::getDeleted, false));
        // 通用的更新wrapper
        LambdaUpdateWrapper<PersonalProduction> productionTimeUpdateWrapper = new LambdaUpdateWrapper<PersonalProduction>()
                .set(PersonalProduction::getProductionTime, null)
                .eq(BaseEntity::getDeleted, false)
                .eq(PersonalProduction::getTargetId, target.getId());
        switch (WorkflowNodeEnum.valueOf(currentInstanceNode.getNodeCode())){
            // 审核意见书退回
            case REVIEW_STATEMENT:
                productionTimeUpdateWrapper.eq(PersonalProduction::getProduction, STATEMENT.getCode());
                personalProductionService.update(productionTimeUpdateWrapper);
                break;
            // 审核报告退回
            case CHECK_REPORT:
                productionTimeUpdateWrapper.and(temp->temp.eq(PersonalProduction::getProduction,TECHNIC.getCode()).or().eq(PersonalProduction::getProduction,FINAL.getCode()));
                personalProductionService.update(productionTimeUpdateWrapper);
                break;
            // 审核复评函退回
            case CHECK_LETTER:
                productionTimeUpdateWrapper.eq(PersonalProduction::getProduction, LETTER.getCode());
                personalProductionService.update(productionTimeUpdateWrapper);
                break;
        }
    }
}
