package cn.axzo.workflow.core.service.converter;

import cn.axzo.workflow.common.enums.BpmnProcessInstanceResultEnum;
import cn.axzo.workflow.common.enums.WorkspaceType;
import cn.axzo.workflow.common.model.response.bpmn.process.BpmnProcessInstanceAdminPageItemVO;
import cn.axzo.workflow.common.model.response.category.CategoryItemVO;
import org.flowable.bpmn.model.FlowElement;
import org.flowable.bpmn.model.ReceiveTask;
import org.flowable.bpmn.model.ServiceTask;
import org.flowable.bpmn.model.UserTask;
import org.flowable.engine.history.HistoricProcessInstance;
import org.flowable.engine.runtime.ActivityInstance;
import org.mapstruct.Mapper;
import org.mapstruct.Mapping;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.stream.Collectors;

import static cn.axzo.workflow.common.enums.BpmnProcessInstanceResultEnum.PROCESSING;
import static org.mapstruct.NullValueCheckStrategy.ALWAYS;

/**
 * 流程实例分页模型的 MapStruts 转换器
 *
 * @author wangli
 * @since 2024/1/25 16:31
 */
@Mapper(
        componentModel = "spring",
        nullValueCheckStrategy = ALWAYS,
        imports = Arrays.class
)
public interface BpmnProcessInstanceAdminPageItemConverter extends EntityConverter<BpmnProcessInstanceAdminPageItemVO,
        HistoricProcessInstance> {

    @Mapping(target = "processInstanceId", source = "id")
    @Mapping(target = "processInstanceName", source = "name")
    @Mapping(target = "businessStatus", source = "businessStatus")
    @Mapping(target = "category", source = "processDefinitionKey")
    @Mapping(target = "startTime", source = "startTime")
    @Mapping(target = "endTime", source = "endTime")
    @Mapping(target = "tenantId", source = "tenantId")
    @Override
    BpmnProcessInstanceAdminPageItemVO toVo(HistoricProcessInstance entity);

    default List<BpmnProcessInstanceAdminPageItemVO> toVos(List<HistoricProcessInstance> instances,
                                                           Map<String, List<FlowElement>> instanceFlowElementMap,
                                                           Map<String, ActivityInstance> liveActivityMap,
                                                           Map<String, ActivityInstance> leastEndActivityMap,
                                                           Map<String, CategoryItemVO> categoryMap) {
        List<BpmnProcessInstanceAdminPageItemVO> result = new ArrayList<>();
        instances.forEach(i -> {
            BpmnProcessInstanceAdminPageItemVO vo = toVo(i);

            if (Objects.equals(PROCESSING.getStatus(), i.getBusinessStatus())) {
                List<FlowElement> flowElements = instanceFlowElementMap.get(i.getId()).stream()
                        .filter(j -> j instanceof UserTask || j instanceof ReceiveTask || j instanceof ServiceTask)
                        .collect(Collectors.toList());
                vo.setTotalNodeCount(flowElements.size());

                // 进行中的节点
                ActivityInstance activityInstance = liveActivityMap.get(i.getId());
                if (Objects.nonNull(activityInstance)) {
                    for (int j = 0; j < flowElements.size(); j++) {
                        if (Objects.equals(flowElements.get(j).getId(), activityInstance.getActivityId())) {
                            vo.setCurrentNodeCount(j);
                            vo.setCurrentActivityId(activityInstance.getActivityId());
                            vo.setCurrentActivityName(activityInstance.getActivityName());
                        }
                    }
                }

                // 最后已结束的节点
                ActivityInstance leastEndActivity = leastEndActivityMap.get(i.getId());
                if (Objects.nonNull(leastEndActivity)) {
                    vo.setLeastCompleteActivityEndTime(leastEndActivity.getEndTime());
                }

            }
            CategoryItemVO category = categoryMap.getOrDefault(i.getProcessDefinitionKey(), new CategoryItemVO());
            vo.setCategoryDesc(category.getLabel());
            vo.setWorkspaceTypeCode(category.getWorkspaceTypeCode());
            vo.setBusinessStatusDesc(BpmnProcessInstanceResultEnum.valueOfStatus(vo.getBusinessStatus()).getDesc());
            vo.setWorkspaceType(WorkspaceType.getType(Integer.valueOf(vo.getWorkspaceTypeCode())));
            result.add(vo);
        });
        return result;
    }
}
