package com.njcn.bpm.utils;

import cn.hutool.core.date.LocalDateTimeUtil;
import cn.hutool.core.map.MapUtil;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.njcn.bpm.pojo.po.BpmCategory;
import com.njcn.bpm.pojo.po.BpmForm;
import com.njcn.bpm.pojo.po.BpmProcessDefinitionInfo;
import com.njcn.bpm.pojo.vo.BpmProcessDefinitionInfoVO;
import org.flowable.bpmn.model.BpmnModel;
import org.flowable.bpmn.model.UserTask;
import org.flowable.common.engine.impl.db.SuspensionState;
import org.flowable.engine.repository.Deployment;
import org.flowable.engine.repository.ProcessDefinition;
import org.mapstruct.Mapper;
import org.mapstruct.Mapping;
import org.mapstruct.MappingTarget;
import org.mapstruct.factory.Mappers;

import java.util.List;
import java.util.Map;

/**
 * Bpm 流程定义的 Convert
 *
 * @author yunlong.li
 */
@Mapper
public interface BpmProcessDefinitionConvert {

    BpmProcessDefinitionConvert INSTANCE = Mappers.getMapper(BpmProcessDefinitionConvert.class);

    default Page<BpmProcessDefinitionInfoVO> buildProcessDefinitionPage(Page<ProcessDefinition> page,
                                                                              Map<String, Deployment> deploymentMap,
                                                                              Map<String, BpmProcessDefinitionInfo> processDefinitionInfoMap,
                                                                              Map<String, BpmForm> formMap,
                                                                              Map<String, BpmCategory> categoryMap) {
        List<BpmProcessDefinitionInfoVO> list = buildProcessDefinitionList(page.getRecords(), deploymentMap, processDefinitionInfoMap, formMap, categoryMap);
        Page<BpmProcessDefinitionInfoVO> voPage = new Page<>();
        voPage.setRecords(list);
        voPage.setTotal(page.getTotal());
        voPage.setSize(page.getSize());
        voPage.setCurrent(page.getCurrent());
        return voPage;
    }

    default List<BpmProcessDefinitionInfoVO> buildProcessDefinitionList(List<ProcessDefinition> list,
                                                                        Map<String, Deployment> deploymentMap,
                                                                        Map<String, BpmProcessDefinitionInfo> processDefinitionInfoMap,
                                                                        Map<String, BpmForm> formMap,
                                                                        Map<String, BpmCategory> categoryMap) {
        return CollectionUtils.convertList(list, definition -> {
            Deployment deployment = MapUtil.get(deploymentMap, definition.getDeploymentId(), Deployment.class);
            BpmProcessDefinitionInfo processDefinitionInfo = MapUtil.get(processDefinitionInfoMap, definition.getId(), BpmProcessDefinitionInfo.class);
            BpmForm form = null;
            if (processDefinitionInfo != null) {
                form = MapUtil.get(formMap, processDefinitionInfo.getFormId(), BpmForm.class);
            }
            BpmCategory category = MapUtil.get(categoryMap, definition.getCategory(), BpmCategory.class);
            return buildProcessDefinition(definition, deployment, processDefinitionInfo, form, category, null, null);
        });
    }

    default BpmProcessDefinitionInfoVO buildProcessDefinition(ProcessDefinition definition,
                                                              Deployment deployment,
                                                              BpmProcessDefinitionInfo processDefinitionInfo,
                                                              BpmForm form,
                                                              BpmCategory category,
                                                              BpmnModel bpmnModel,
                                                              List<UserTask> startUserSelectUserTaskList) {
        BpmProcessDefinitionInfoVO respVO = BeanUtils.toBean(definition, BpmProcessDefinitionInfoVO.class);
        respVO.setSuspensionState(definition.isSuspended() ? SuspensionState.SUSPENDED.getStateCode() : SuspensionState.ACTIVE.getStateCode());
        // Deployment
        if (deployment != null) {
            respVO.setDeploymentTime(LocalDateTimeUtil.of(deployment.getDeploymentTime()));
        }
        // BpmProcessDefinitionInfoDO
        if (processDefinitionInfo != null) {
            copyTo(processDefinitionInfo, respVO);
            // Form
            if (form != null) {
                respVO.setFormName(form.getName());
            }
        }
        // Category
        if (category != null) {
            respVO.setCategoryName(category.getName());
        }
        // BpmnModel
        if (bpmnModel != null) {
            respVO.setBpmnXml(BpmnModelUtils.getBpmnXml(bpmnModel));
            respVO.setStartUserSelectTasks(BeanUtils.toBean(startUserSelectUserTaskList, BpmProcessDefinitionInfoVO.UserTask.class));
        }
        return respVO;
    }

    @Mapping(source = "from.id", target = "to.id", ignore = true)
    void copyTo(BpmProcessDefinitionInfo from, @MappingTarget BpmProcessDefinitionInfoVO to);

}
