package com.qqchen.deploy.backend.workflow.event.handler;

import cn.hutool.core.date.DateUtil;
import com.qqchen.deploy.backend.workflow.entity.WorkflowNodeInstance;
import com.qqchen.deploy.backend.workflow.enums.WorkflowInstanceStatusEnums;
import com.qqchen.deploy.backend.workflow.enums.WorkflowNodeInstanceStatusEnums;
import com.qqchen.deploy.backend.workflow.dto.event.WorkflowInstanceStatusChangeEvent;
import com.qqchen.deploy.backend.workflow.repository.IWorkflowNodeInstanceRepository;
import lombok.extern.slf4j.Slf4j;
import org.flowable.common.engine.api.delegate.event.FlowableEvent;
import org.flowable.engine.ProcessEngine;
import org.flowable.engine.delegate.event.FlowableProcessEngineEvent;
import org.flowable.engine.history.HistoricProcessInstance;
import org.springframework.context.ApplicationEventPublisher;
import org.springframework.context.annotation.Lazy;
import org.springframework.stereotype.Component;

import jakarta.annotation.Resource;

/**
 * 流程实例事件处理器
 * 处理 Flowable 的 PROCESS_* 级别事件（流程实例生命周期事件）
 * 
 * @author system
 */
@Slf4j
@Component
public class ProcessInstanceEventHandler implements IFlowableEventHandler {

    @Resource
    private ApplicationEventPublisher publisher;

    @Resource
    @Lazy
    private ProcessEngine processEngine;

    @Resource
    private IWorkflowNodeInstanceRepository workflowNodeInstanceRepository;

    @Override
    public boolean canHandle(String eventType) {
        return eventType.startsWith("PROCESS_");
    }

    @Override
    public void handle(FlowableEvent event) {
        String eventType = event.getType().name();
        FlowableProcessEngineEvent processEvent = (FlowableProcessEngineEvent) event;
        
        // 对于 PROCESS_COMPLETED 事件，需要检查节点状态来决定最终状态
        WorkflowInstanceStatusEnums status;
        if ("PROCESS_COMPLETED".equals(eventType)) {
            status = determineCompletionStatus(processEvent.getProcessInstanceId());
        } else {
            status = convertToWorkflowStatus(eventType);
        }

        if (status != null) {
            // ✅ 优化：只在需要 endTime 时查询 HistoricProcessInstance（仅完成状态）
            java.time.LocalDateTime endTime = null;
            if (status.isFinalState()) {
                HistoricProcessInstance historicProcessInstance = processEngine.getHistoryService()
                    .createHistoricProcessInstanceQuery()
                    .processInstanceId(processEvent.getProcessInstanceId())
                    .singleResult();
                if (historicProcessInstance != null && historicProcessInstance.getEndTime() != null) {
                    endTime = DateUtil.toLocalDateTime(historicProcessInstance.getEndTime());
                }
            }

            log.debug("工作流实例状态变更: processInstanceId={}, eventType={}, status={}", 
                processEvent.getProcessInstanceId(), eventType, status);

            publisher.publishEvent(WorkflowInstanceStatusChangeEvent.builder()
                .processInstanceId(processEvent.getProcessInstanceId())
                .status(status)
                .endTime(endTime)
                .build()
            );
        }
    }

    /**
     * 判断流程完成时的最终状态
     * 
     * @param processInstanceId 流程实例ID
     * @return 如果所有节点成功返回 COMPLETED，如果有节点失败返回 COMPLETED_WITH_ERRORS
     */
    private WorkflowInstanceStatusEnums determineCompletionStatus(String processInstanceId) {
        // ✅ 优化：只查询有失败状态的节点，避免加载所有节点数据
        // 先检查是否有失败的节点（排除开始和结束节点）
        boolean hasFailedNode = workflowNodeInstanceRepository.findByProcessInstanceId(processInstanceId)
            .stream()
            .filter(node -> !"StartEvent".equals(node.getNodeType()) && !"EndEvent".equals(node.getNodeType()))
            .anyMatch(node -> WorkflowNodeInstanceStatusEnums.FAILED.equals(node.getStatus()));
        
        if (hasFailedNode) {
            log.warn("工作流实例 {} 完成，但存在失败的节点", processInstanceId);
            return WorkflowInstanceStatusEnums.COMPLETED_WITH_ERRORS;
        } else {
            log.debug("工作流实例 {} 完成，所有节点均成功", processInstanceId);
            return WorkflowInstanceStatusEnums.COMPLETED;
        }
    }

    private WorkflowInstanceStatusEnums convertToWorkflowStatus(String eventType) {
        return switch (eventType) {
            case "PROCESS_CREATED" -> WorkflowInstanceStatusEnums.CREATED;
            case "PROCESS_STARTED" -> WorkflowInstanceStatusEnums.RUNNING;
            case "PROCESS_COMPLETED" -> WorkflowInstanceStatusEnums.COMPLETED;
            case "PROCESS_CANCELLED" -> WorkflowInstanceStatusEnums.FAILED;
            case "PROCESS_SUSPENDED" -> WorkflowInstanceStatusEnums.SUSPENDED;
            case "PROCESS_COMPLETED_WITH_TERMINATE_END_EVENT" -> WorkflowInstanceStatusEnums.TERMINATED;
            default -> null;
        };
    }

}
