package cn.stylefeng.workflow.design.modular.service.impl;

import cn.hutool.core.util.ObjectUtil;
import cn.stylefeng.roses.kernel.rule.exception.base.ServiceException;
import cn.stylefeng.roses.kernel.sys.api.SysUserServiceApi;
import cn.stylefeng.team.form.api.FormModelServiceApi;
import cn.stylefeng.team.form.api.enums.FormTypeEnum;
import cn.stylefeng.team.form.api.pojo.FormDesignVo;
import cn.stylefeng.workflow.api.entity.design.Definition;
import cn.stylefeng.workflow.api.entity.design.Model;
import cn.stylefeng.workflow.api.entity.design.Node;
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.ModelForm;
import cn.stylefeng.workflow.api.pojo.config.node.NodeData;
import cn.stylefeng.workflow.api.pojo.config.node.button.NodeButtonPermission;
import cn.stylefeng.workflow.api.pojo.config.node.form.FieldPermission;
import cn.stylefeng.workflow.api.pojo.config.node.form.FormPermission;
import cn.stylefeng.workflow.design.api.pojo.BusinessCategoryVo;
import cn.stylefeng.workflow.design.modular.enums.DefinitionExceptionEnum;
import cn.stylefeng.workflow.design.modular.factory.ModelFactory;
import cn.stylefeng.workflow.design.modular.factory.NodeFromDesignFactory;
import cn.stylefeng.workflow.design.modular.pojo.FlowDefinitionFormVo;
import cn.stylefeng.workflow.design.modular.pojo.request.DefinitionRequest;
import cn.stylefeng.workflow.design.modular.pojo.request.ModelRequest;
import cn.stylefeng.workflow.design.modular.pojo.request.StartPageRequest;
import cn.stylefeng.workflow.design.modular.service.*;
import cn.stylefeng.workflow.instance.api.FlowAuthServiceApi;
import cn.stylefeng.workflow.instance.api.TaskApi;
import jakarta.annotation.Resource;
import org.springframework.stereotype.Service;

import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import java.util.stream.Collectors;

@Service
public class StartPageServiceImpl implements StartPageService {

    @Resource
    private ModelService modelService;

    @Resource
    private DefinitionService definitionService;

    @Resource
    private FormModelServiceApi formModelServiceApi;

    @Resource
    private NodeService nodeService;

    @Resource
    private TaskApi taskApi;

    @Resource
    private SysUserServiceApi sysUserServiceApi;

    @Resource
    private FlowAuthServiceApi flowAuthServiceApi;

    @Resource
    private UserCommonWorkflowService userCommonWorkflowService;

    @Override
    public List<BusinessCategoryVo> getUserModelList(StartPageRequest startPageRequest) {

        Set<Long> userTotalFlowModelIdList = this.getUserHaveFlowModelIdList();
        if (ObjectUtil.isEmpty(userTotalFlowModelIdList)) {
            return new ArrayList<>();
        }

        ModelRequest modelRequest = new ModelRequest();
        modelRequest.setSearchText(startPageRequest.getSearchText());
        modelRequest.setOpenAuthValidate(true);
        modelRequest.setUserHaveAuthFlowModelIdList(userTotalFlowModelIdList);
        List<BusinessCategoryVo> businessCategoryVos = modelService.findList(modelRequest);

        List<Long> userCommonFlow = userCommonWorkflowService.findUserAuthedCommonFlow(userTotalFlowModelIdList);
        return ModelFactory.combineUserCommonFlow(businessCategoryVos, userCommonFlow);
    }

    @Override
    public FlowDefinitionFormVo getFlowDefinitionFormConfig(DefinitionRequest definitionRequest) {

        Definition definitionInfo = definitionService.getDefinitionInfo(definitionRequest.getDefinitionId());

        SixGraphDesign xSixGraphJson = definitionInfo.getXSixGraphJson();
        if (ObjectUtil.isEmpty(xSixGraphJson)) {
            throw new ServiceException(DefinitionExceptionEnum.CANT_FIND_FORM_CONFIG);
        }

        FlowGlobalConfig flowGlobalConfig = xSixGraphJson.getFlowGlobalConfig();
        if (ObjectUtil.isEmpty(flowGlobalConfig)) {
            throw new ServiceException(DefinitionExceptionEnum.CANT_FIND_FORM_CONFIG);
        }

        List<ModelForm> formDefinitionList = flowGlobalConfig.getFormDefinitionList();
        if (ObjectUtil.isEmpty(formDefinitionList)) {
            throw new ServiceException(DefinitionExceptionEnum.CANT_FIND_FORM_CONFIG);
        }

        Node thisNode = null;
        if (ObjectUtil.isEmpty(definitionRequest.getTaskId())) {
            thisNode = nodeService.getDefinitionApplicantNode(definitionRequest.getDefinitionId());
        }

        else {
            thisNode = taskApi.getTaskNode(definitionRequest.getTaskId());
        }


        ModelForm thisModelForm = formDefinitionList.get(0);
        if (FormTypeEnum.APP_DESIGN.getValueType().equals(thisModelForm.getFormType())) {
            return this.processAppDesignForm(thisNode, formDefinitionList, definitionRequest.getMobileFlag());
        } else {
            return this.processVueDesignForm(thisNode, thisModelForm);
        }
    }

    @Override
    public NodeButtonPermission getApplicantButtonPermission(DefinitionRequest definitionRequest) {

        Node definitionApplicantNode = nodeService.getDefinitionApplicantNode(definitionRequest.getDefinitionId());

        NodeData nodeData = definitionApplicantNode.getNodeData();
        if (nodeData == null) {
            return new NodeButtonPermission();
        }

        return nodeData.getNodeButtonPermission();
    }

    @Override
    public List<Model> getUserModelListFlat() {

        Set<Long> userHaveFlowModelIdList = this.getUserHaveFlowModelIdList();

        return modelService.getModelList(userHaveFlowModelIdList);
    }

    public FlowDefinitionFormVo processAppDesignForm(Node thisNode, List<ModelForm> formDefinitionList, Boolean mobileFlag) {
        formDefinitionList.removeIf(modelForm -> FormTypeEnum.CUSTOM_VUE_FORM.getValueType().equals(modelForm.getFormType()));
        if (ObjectUtil.isEmpty(formDefinitionList)) {
            throw new ServiceException(DefinitionExceptionEnum.CANT_FIND_FORM_CONFIG);
        }

        List<Long> formDefinitionIdList = formDefinitionList.stream().map(ModelForm::getFormDefinitionId).collect(Collectors.toList());
        List<FormDesignVo> fromDesignList = formModelServiceApi.getFromDesignListWithMobileCondition(formDefinitionIdList, mobileFlag);


        NodeFromDesignFactory.fillNodeFormDesign(thisNode, fromDesignList);

        List<FormDesignVo> finalResult = NodeFromDesignFactory.ensureHiddenItem(fromDesignList);

        FlowDefinitionFormVo flowDefinitionFormVo = new FlowDefinitionFormVo();
        flowDefinitionFormVo.setFormType(FormTypeEnum.APP_DESIGN.getValueType());
        flowDefinitionFormVo.setFormDesignConfigList(finalResult);
        return flowDefinitionFormVo;
    }

    private FlowDefinitionFormVo processVueDesignForm(Node thisNode, ModelForm vueFormConfig) {
        FlowDefinitionFormVo flowDefinitionFormVo = new FlowDefinitionFormVo();

        flowDefinitionFormVo.setFormType(FormTypeEnum.CUSTOM_VUE_FORM.getValueType());

        flowDefinitionFormVo.setComponentCode(vueFormConfig.getFormCode());

        NodeData nodeData = thisNode.getNodeData();
        if (nodeData != null) {
            List<FormPermission> formPermission = nodeData.getFormPermission();
            if (ObjectUtil.isNotEmpty(formPermission)) {
                List<FieldPermission> fieldPermissionList = formPermission.get(0).getFieldPermissionList();
                if (ObjectUtil.isNotEmpty(fieldPermissionList)) {
                    flowDefinitionFormVo.setFieldPermissionList(fieldPermissionList);
                }
            }
        }

        return flowDefinitionFormVo;
    }

    private Set<Long> getUserHaveFlowModelIdList() {

        Set<Long> userComprehensiveIdentitySummary = sysUserServiceApi.getUserComprehensiveIdentitySummary();
        if (ObjectUtil.isEmpty(userComprehensiveIdentitySummary)) {
            return new HashSet<>();
        }

        Set<Long> userTotalFlowModelIdList = flowAuthServiceApi.getUserTotalFlowModelIdList(userComprehensiveIdentitySummary);
        if (ObjectUtil.isEmpty(userTotalFlowModelIdList)) {
            return new HashSet<>();
        }

        return userTotalFlowModelIdList;
    }

}
