package cn.stylefeng.workflow.instance.core.actions.subflow.factory;

import cn.hutool.core.util.ObjectUtil;
import cn.stylefeng.roses.kernel.rule.pojo.dict.SimpleDict;
import cn.stylefeng.workflow.api.entity.instance.RuntimeNode;
import cn.stylefeng.workflow.api.enums.InstanceStatusEnum;
import cn.stylefeng.workflow.api.enums.subflow.DeptCounterSignTypeEnum;
import cn.stylefeng.workflow.api.enums.subflow.SubmitterTypeEnum;
import cn.stylefeng.workflow.api.pojo.InstanceContext;
import cn.stylefeng.workflow.api.pojo.InstanceVariable;
import cn.stylefeng.workflow.api.pojo.SubFlowStatusContext;
import cn.stylefeng.workflow.api.pojo.config.node.subflow.NodeSubFlow;
import com.alibaba.fastjson.JSON;
import com.baomidou.mybatisplus.core.toolkit.IdWorker;

import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

public class SubFlowStatusContextFactory {

    public static Map<Long, SubFlowStatusContext> firstCreateSubFlowStatusContexts(RuntimeNode runtimeNode, NodeSubFlow nodeSubFlow, InstanceContext instanceContext) {

        Map<Long, SubFlowStatusContext> subFlowStatusContextHashMap = new HashMap<>();

        if (!nodeSubFlow.getDeptCounterSignFlag()) {
            SubFlowStatusContext singleSubFlowContext = createSingleSubFlowContext();
            subFlowStatusContextHashMap.put(singleSubFlowContext.getSubFlowInstanceId(), singleSubFlowContext);
            return subFlowStatusContextHashMap;
        }

        Integer deptCounterSignType = nodeSubFlow.getDeptCounterSignType();

        List<Long> huiqianOrgIdList = null;
        if (DeptCounterSignTypeEnum.FORM_ELEMENT.getCode().equals(deptCounterSignType)) {
            huiqianOrgIdList = getDeptCounterSignOrgIdList(nodeSubFlow, instanceContext.getInstanceVariable());
        }

        else if (DeptCounterSignTypeEnum.FLOW_VARIABLE.getCode().equals(deptCounterSignType)) {
            huiqianOrgIdList = getDeptCounterSignOrgIdByModelVariableCode(nodeSubFlow, instanceContext.getInstanceVariable());
        }
        if (ObjectUtil.isEmpty(huiqianOrgIdList)) {
            return subFlowStatusContextHashMap;
        }

        Integer submitterType = nodeSubFlow.getSubmitterType();
        Long submitterUserId = null;
        if (SubmitterTypeEnum.MAIN_FLOW_APPLICANT.getCode().equals(submitterType)) {

            submitterUserId = instanceContext.getRuntimeInstance().getApplicant();
        }

        else if (SubmitterTypeEnum.POINT_USER.getCode().equals(submitterType)) {
            submitterUserId = nodeSubFlow.getSubmitterUserId();
        }

        else if (SubmitterTypeEnum.FORM_VARIABLE.getCode().equals(submitterType)) {
            submitterUserId = getSubmitterUserIdByFormVariableCode(nodeSubFlow, instanceContext.getInstanceVariable());
        }

        else if (SubmitterTypeEnum.MODEL_VARIABLE.getCode().equals(submitterType)) {
            submitterUserId = getSubmitterUserIdByModelVariableCode(nodeSubFlow, instanceContext.getInstanceVariable());
        }

        for (Long subFlowOrgId : huiqianOrgIdList) {
            SubFlowStatusContext deptSubFlowContext = createDeptSubFlowContext(subFlowOrgId, submitterUserId);
            subFlowStatusContextHashMap.put(deptSubFlowContext.getSubFlowInstanceId(), deptSubFlowContext);
        }

        return subFlowStatusContextHashMap;
    }

    private static SubFlowStatusContext createSingleSubFlowContext() {

        SubFlowStatusContext subFlowStatusContext = new SubFlowStatusContext();

        subFlowStatusContext.setSubFlowInstanceId(IdWorker.getId());

        subFlowStatusContext.setSubFlowInstanceStatus(InstanceStatusEnum.PROCESSING.getStatus());

        subFlowStatusContext.setCycleNumberIndex(0);

        return subFlowStatusContext;
    }

    private static SubFlowStatusContext createDeptSubFlowContext(Long deptCounterSignOrgId, Long subFlowApplicantId) {
        SubFlowStatusContext singleSubFlowContext = createSingleSubFlowContext();
        singleSubFlowContext.setDeptCounterSignOrgId(deptCounterSignOrgId);
        singleSubFlowContext.setSubFlowApplicantId(subFlowApplicantId);
        return singleSubFlowContext;
    }

    private static List<Long> getDeptCounterSignOrgIdList(NodeSubFlow nodeSubFlow, InstanceVariable instanceVariable) {

        Long formDefinitionId = nodeSubFlow.getDeptCounterSignFormDefinitionId();
        String formVariableCode = nodeSubFlow.getDeptCounterSignFormVariableCode();

        List<SimpleDict> deptList = getCommonFormVariable(instanceVariable, formDefinitionId, formVariableCode);
        if (deptList == null) {
            return null;
        }

        return deptList.stream().map(SimpleDict::getId).collect(Collectors.toList());
    }

    private static List<Long> getDeptCounterSignOrgIdByModelVariableCode(NodeSubFlow nodeSubFlow, InstanceVariable instanceVariable) {

        String modelVariableCode = nodeSubFlow.getDeptCounterSignModelVariableCode();
        List<SimpleDict> deptList = getCommonModelValue(instanceVariable, modelVariableCode);
        if (deptList == null) {
            return null;
        }

        return deptList.stream().map(SimpleDict::getId).collect(Collectors.toList());
    }

    private static Long getSubmitterUserIdByModelVariableCode(NodeSubFlow nodeSubFlow, InstanceVariable instanceVariable) {

        String modelVariableCode = nodeSubFlow.getSubmitterModelVariableCode();
        List<SimpleDict> userIdList = getCommonModelValue(instanceVariable, modelVariableCode);
        if (userIdList == null) {
            return null;
        }

        return userIdList.get(0).getId();
    }

    private static Long getSubmitterUserIdByFormVariableCode(NodeSubFlow nodeSubFlow, InstanceVariable instanceVariable) {

        Long formDefinitionId = nodeSubFlow.getSubmitterFormDefinitionId();
        String formVariableCode = nodeSubFlow.getSubmitterFormVariableCode();

        List<SimpleDict> userIdList = getCommonFormVariable(instanceVariable, formDefinitionId, formVariableCode);
        if (userIdList == null) {
            return null;
        }

        return userIdList.get(0).getId();
    }

    private static List<SimpleDict> getCommonFormVariable(InstanceVariable instanceVariable, Long formDefinitionId, String formVariableCode) {
        if (ObjectUtil.isEmpty(formDefinitionId)) {
            return null;
        }

        if (ObjectUtil.isEmpty(formVariableCode)) {
            return null;
        }

        Map<String, Map<String, Object>> formData = instanceVariable.getFormData();
        if (ObjectUtil.isEmpty(formData)) {
            return null;
        }

        Map<String, Object> formVariable = formData.get(String.valueOf(formDefinitionId));
        if (formVariable == null) {
            return null;
        }

        Object submitterFromVarValue = formVariable.get(formVariableCode);
        if (submitterFromVarValue == null) {
            return null;
        }

        List<SimpleDict> userIdList = JSON.parseArray(submitterFromVarValue.toString(), SimpleDict.class);
        if (ObjectUtil.isEmpty(userIdList)) {
            return null;
        }

        return userIdList;
    }

    private static List<SimpleDict> getCommonModelValue(InstanceVariable instanceVariable, String modelVariableCode) {
        if (ObjectUtil.isEmpty(modelVariableCode)) {
            return null;
        }

        Map<String, Object> customVueFormData = instanceVariable.getCustomVueFormData();
        if (ObjectUtil.isEmpty(customVueFormData)) {
            return null;
        }

        Object commonListObj = customVueFormData.get(modelVariableCode);
        List<SimpleDict> commonList = JSON.parseArray(commonListObj.toString(), SimpleDict.class);
        if (ObjectUtil.isEmpty(commonList)) {
            return null;
        }

        return commonList;
    }
}
