package cn.stylefeng.workflow.instance.api.factory;

import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.extra.spring.SpringUtil;
import cn.stylefeng.roses.kernel.auth.api.context.LoginContext;
import cn.stylefeng.roses.kernel.auth.api.pojo.login.LoginUser;
import cn.stylefeng.roses.kernel.rule.exception.base.ServiceException;
import cn.stylefeng.roses.kernel.sys.api.SysUserServiceApi;
import cn.stylefeng.roses.kernel.sys.api.pojo.user.SimpleUserDTO;
import cn.stylefeng.workflow.api.entity.design.Definition;
import cn.stylefeng.workflow.api.entity.instance.RuntimeInstance;
import cn.stylefeng.workflow.api.enums.FlowTitleTypeEnum;
import cn.stylefeng.workflow.api.enums.InstanceStatusEnum;
import cn.stylefeng.workflow.api.exception.enums.WorkflowExceptionEnum;
import cn.stylefeng.workflow.api.pojo.InstanceVariable;
import cn.stylefeng.workflow.api.pojo.config.SixGraphDesign;
import cn.stylefeng.workflow.api.pojo.config.model.FlowGlobalConfig;
import cn.stylefeng.workflow.api.pojo.config.model.ModelTitleConfig;
import cn.stylefeng.workflow.design.api.ModelApi;
import cn.stylefeng.workflow.instance.api.constants.InstanceConstants;
import cn.stylefeng.workflow.instance.api.pojo.request.WorkflowStartRequest;
import com.baomidou.mybatisplus.core.toolkit.IdWorker;

import java.util.HashMap;
import java.util.Map;

public class RuntimeInstanceFactory {

    public static RuntimeInstance createRuInstance(WorkflowStartRequest workflowStartRequest, Definition definition) {

        RuntimeInstance runtimeInstance = new RuntimeInstance();

        if (ObjectUtil.isEmpty(workflowStartRequest.getFlowInstanceId())) {
            runtimeInstance.setInstanceId(IdWorker.getId());
        } else {
            runtimeInstance.setInstanceId(workflowStartRequest.getFlowInstanceId());
        }

        runtimeInstance.setModelId(definition.getModelId());
        runtimeInstance.setDefinitionId(definition.getDefinitionId());

        runtimeInstance.setParentInstanceId(workflowStartRequest.getParentInstanceId());
        runtimeInstance.setParentNodeId(workflowStartRequest.getParentNodeId());
        runtimeInstance.setParamSendParentFlag(workflowStartRequest.getParamSendParentFlag());

        runtimeInstance.setStartType(workflowStartRequest.getWorkflowStartType());

        runtimeInstance.setInstanceTitle(createInstanceTitle(definition, workflowStartRequest.getInstanceVariable()));

        Long applicant = workflowStartRequest.getApplicant();
        if (ObjectUtil.isNotEmpty(applicant)) {
            runtimeInstance.setApplicant(applicant);
            runtimeInstance.setApplicantOrgId(workflowStartRequest.getApplicantOrgId());
            runtimeInstance.setApplicantPositionId(workflowStartRequest.getApplicantPositionId());
        } else {
            LoginUser loginUser = LoginContext.me().getLoginUserNullable();
            if (loginUser == null) {
                throw new ServiceException(WorkflowExceptionEnum.CANT_FIND_APPLICANT);
            }

            runtimeInstance.setApplicant(loginUser.getUserId());
            runtimeInstance.setApplicantOrgId(loginUser.getCurrentOrgId());
            runtimeInstance.setApplicantPositionId(loginUser.getCurrentPositionId());
        }

        runtimeInstance.setInstanceStatus(InstanceStatusEnum.PROCESSING.getStatus());



        runtimeInstance.setInstanceVariable(workflowStartRequest.getInstanceVariable());

        return runtimeInstance;
    }

    public static String createInstanceTitle(Definition definition, InstanceVariable instanceVariable) {

        ModelApi modelApi = SpringUtil.getBean(ModelApi.class);
        String modelName = modelApi.getModelName(definition.getModelId());

        SixGraphDesign xSixGraphJson = definition.getXSixGraphJson();
        if (ObjectUtil.isEmpty(xSixGraphJson)) {
            return modelName;
        }

        FlowGlobalConfig flowGlobalConfig = xSixGraphJson.getFlowGlobalConfig();
        if (ObjectUtil.isEmpty(flowGlobalConfig)) {
            return modelName;
        }

        ModelTitleConfig modelTitleConfig = flowGlobalConfig.getModelTitleConfig();
        if (ObjectUtil.isEmpty(modelTitleConfig)) {
            return modelName;
        }

        Integer flowTitleType = modelTitleConfig.getFlowTitleType();
        if (flowTitleType == null) {
            return modelName;
        }

        if (FlowTitleTypeEnum.FIXED.getCode().equals(flowTitleType)) {
            String titleConfigValue = modelTitleConfig.getTitleConfigValue();
            if (StrUtil.isBlank(titleConfigValue)) {
                return modelName;
            } else {
                return titleConfigValue;
            }
        }

        else if (FlowTitleTypeEnum.FORM_VARIABLE.getCode().equals(flowTitleType)) {
            Long formDefinitionId = modelTitleConfig.getFormDefinitionId();
            String formVariableCode = modelTitleConfig.getFormVariableCode();

            if (ObjectUtil.isEmpty(formDefinitionId) || ObjectUtil.isEmpty(formVariableCode)) {
                return modelName;
            }

            Map<String, Map<String, Object>> formData = instanceVariable.getFormData();
            Map<String, Object> formDefinitionData = formData.get(String.valueOf(formDefinitionId));
            if (ObjectUtil.isEmpty(formDefinitionData)) {
                return modelName;
            }

            Object formVariableValue = formDefinitionData.get(formVariableCode);
            if (ObjectUtil.isEmpty(formVariableValue)) {
                return modelName;
            }

            return formVariableValue.toString();
        }

        else if (FlowTitleTypeEnum.MODEL_VARIABLE.getCode().equals(flowTitleType)) {
            String modelVariableCode = modelTitleConfig.getModelVariableCode();
            if (StrUtil.isBlank(modelVariableCode)) {
                return modelName;
            }

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

            Object variableValue = modelVariableData.get(modelVariableCode);
            if (ObjectUtil.isNull(variableValue)) {
                return modelName;
            }

            return variableValue.toString();
        }

        else if (FlowTitleTypeEnum.CUSTOM.getCode().equals(flowTitleType)) {

            String titleConfigValue = modelTitleConfig.getTitleConfigValue();
            if (StrUtil.isBlank(titleConfigValue)) {
                return modelName;
            }

            if (StrUtil.contains(titleConfigValue, InstanceConstants.SUBMIT_USER_TAG)) {

                Long userId = LoginContext.me().getLoginUser().getUserId();
                SysUserServiceApi sysUserServiceApi = SpringUtil.getBean(SysUserServiceApi.class);
                SimpleUserDTO simpleUserDTO = sysUserServiceApi.getUserInfoByUserId(userId);
                if (simpleUserDTO != null) {
                    titleConfigValue = titleConfigValue.replace(InstanceConstants.SUBMIT_USER_TAG, simpleUserDTO.getRealName());
                }
            }

            if (StrUtil.contains(titleConfigValue, InstanceConstants.MODEL_NAME_TAG)) {
                titleConfigValue = titleConfigValue.replace(InstanceConstants.MODEL_NAME_TAG, modelName);
            }

            return StrUtil.format(titleConfigValue, createInstanceVariable(instanceVariable));
        }

        return modelName;
    }

    public static Map<String, Object> createInstanceVariable(InstanceVariable instanceVariable) {
        Map<String, Object> variableMap = new HashMap<>();
        if (instanceVariable == null) {
            return variableMap;
        }

        Map<String, Map<String, Object>> formData = instanceVariable.getFormData();
        for (Map<String, Object> value : formData.values()) {
            variableMap.putAll(value);
        }

        Map<String, Object> customVueFormData = instanceVariable.getCustomVueFormData();
        if (ObjectUtil.isNotEmpty(customVueFormData)) {
            variableMap.putAll(customVueFormData);
        }

        return variableMap;
    }

}
