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

import cn.axzo.workflow.common.model.response.bpmn.task.BpmnHistoricTaskInstanceVO;
import org.apache.maven.artifact.versioning.DefaultArtifactVersion;
import org.flowable.task.api.history.HistoricTaskInstance;
import org.mapstruct.Mapper;
import org.mapstruct.Mapping;
import org.springframework.util.CollectionUtils;
import org.springframework.util.StringUtils;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
import java.util.Objects;
import java.util.stream.Stream;

import static cn.axzo.workflow.common.constant.BpmnConstants.FLOW_SERVER_VERSION_130;
import static cn.axzo.workflow.common.constant.BpmnConstants.HIDDEN_ASSIGNEE_ID;
import static cn.axzo.workflow.common.constant.BpmnConstants.OLD_TASK_ASSIGNEE_SKIP_FLAT;
import static cn.axzo.workflow.core.common.enums.BpmnProcessTaskResultEnum.MI_END;
import static cn.axzo.workflow.core.common.enums.BpmnProcessTaskResultEnum.REJECTION_AUTO_COMPLETED;
import static org.mapstruct.NullValueCheckStrategy.ALWAYS;

/**
 * 历史任务实例的 MapStruts 转换器
 *
 * @author wangli
 * @since 2023/7/29 17:50
 */
@Mapper(
        componentModel = "spring",
        nullValueCheckStrategy = ALWAYS,
        imports = Arrays.class
)
public interface BpmnHistoricTaskInstanceConverter extends EntityConverter<BpmnHistoricTaskInstanceVO,
        HistoricTaskInstance> {
    @Override
    @Mapping(target = "taskId", source = "id")
    @Mapping(target = "taskDefinitionKey", source = "taskDefinitionKey")
    @Mapping(target = "name", source = "name")
    @Mapping(target = "processInstanceId", source = "processInstanceId")
    @Mapping(target = "processDefinitionId", source = "processDefinitionId")
    @Mapping(target = "assignee", source = "assignee")
    @Mapping(target = "createTime", source = "createTime")
    @Mapping(target = "endTime", source = "endTime")
    @Mapping(target = "durationInMillis", source = "durationInMillis")
    @Mapping(target = "tenantId", source = "tenantId")
    @Mapping(target = "deleteReason", source = "deleteReason")
    BpmnHistoricTaskInstanceVO toVo(HistoricTaskInstance entity);


    default List<BpmnHistoricTaskInstanceVO> toVosSkipSystemOperation(List<HistoricTaskInstance> entities,
            //                                                                      HistoricVariableInstance instanceVersion,
                                                                      String instanceVersion) {
        if (CollectionUtils.isEmpty(entities)) {
            return Collections.emptyList();
        }
        List<BpmnHistoricTaskInstanceVO> vos = new ArrayList<>();
        Stream<HistoricTaskInstance> taskInstanceStream = entities.stream()
                .filter(i -> !Objects.equals(i.getAssignee(), HIDDEN_ASSIGNEE_ID))
                .filter(i -> !Objects.equals(i.getDeleteReason(), HIDDEN_ASSIGNEE_ID))
                .filter(i -> !Objects.equals(i.getDeleteReason(), MI_END.getStatus()));
        if (Objects.isNull(instanceVersion)) {
            compatibleVersion(taskInstanceStream).forEach(i -> vos.add(toVo(i)));
        } else {
            if (StringUtils.hasText(instanceVersion)) {
                DefaultArtifactVersion version = new DefaultArtifactVersion(instanceVersion);
                DefaultArtifactVersion supportVersion = new DefaultArtifactVersion(FLOW_SERVER_VERSION_130);
                if (version.compareTo(supportVersion) < 0) {
                    compatibleVersion(taskInstanceStream).forEach(i -> vos.add(toVo(i)));
                } else {
                    taskInstanceStream.forEach(i -> vos.add(toVo(i)));
                }
            } else {
                taskInstanceStream.forEach(i -> vos.add(toVo(i)));
            }
        }
        return vos;
    }

    /**
     * 兼容 1.2.1 版本的审批日志
     *
     * @param stream
     * @return
     */
    default Stream<HistoricTaskInstance> compatibleVersion(Stream<HistoricTaskInstance> stream) {
        return stream.filter(i -> (!Objects.equals(REJECTION_AUTO_COMPLETED.getDesc(), i.getDeleteReason()))
                || (Objects.equals(i.getAssignee(), OLD_TASK_ASSIGNEE_SKIP_FLAT) && Objects.equals(REJECTION_AUTO_COMPLETED.getDesc(), i.getDeleteReason()))
        ).filter(i -> !(!Objects.equals(i.getAssignee(), OLD_TASK_ASSIGNEE_SKIP_FLAT) && Objects.equals(MI_END.getStatus(), i.getDeleteReason())));
    }

}
