package com.qaup.collision.rule.event;

import com.qaup.collision.rule.model.entity.SpatialRule;
import com.qaup.collision.rule.model.enums.RuleExecutionResult;
import com.qaup.collision.rule.model.enums.RuleExecutionStatus;

import lombok.Getter;
import org.springframework.context.ApplicationEvent;

import java.time.LocalDateTime;
import java.util.Map;

/**
 * 规则执行事件
 * 记录规则执行过程中的关键状态变化
 */
@Getter
public class RuleExecutionEvent extends ApplicationEvent {

    private final SpatialRule rule;
    private final String vehicleId;
    private final RuleExecutionStatus executionStatus;
    private final RuleExecutionResult executionResult;
    private final LocalDateTime executionStartTime;
    private final LocalDateTime executionEndTime;
    private final long executionDurationMs;
    private final LocalDateTime eventTimestamp;
    private final String eventSource;
    private final Map<String, Object> executionContext;
    private final String errorMessage;
    private final String executionDetails;
    private final ExecutionEventType eventType;

    public enum ExecutionEventType {
        EXECUTION_STARTED("规则执行开始"),
        EXECUTION_COMPLETED("规则执行完成"),
        EXECUTION_FAILED("规则执行失败"),
        EXECUTION_TIMEOUT("规则执行超时"),
        EXECUTION_SKIPPED("规则执行跳过"),
        EXECUTION_RETRIED("规则执行重试");

        private final String description;

        ExecutionEventType(String description) {
            this.description = description;
        }

        public String getDescription() {
            return description;
        }
    }

    public RuleExecutionEvent(Object source, SpatialRule rule, String vehicleId,
                            RuleExecutionStatus executionStatus, RuleExecutionResult executionResult,
                            LocalDateTime executionStartTime, LocalDateTime executionEndTime,
                            String eventSource, Map<String, Object> executionContext,
                            String errorMessage, String executionDetails, ExecutionEventType eventType) {
        super(source);
        this.rule = rule;
        this.vehicleId = vehicleId;
        this.executionStatus = executionStatus;
        this.executionResult = executionResult;
        this.executionStartTime = executionStartTime;
        this.executionEndTime = executionEndTime;
        this.executionDurationMs = calculateDuration(executionStartTime, executionEndTime);
        this.eventTimestamp = LocalDateTime.now();
        this.eventSource = eventSource;
        this.executionContext = executionContext;
        this.errorMessage = errorMessage;
        this.executionDetails = executionDetails;
        this.eventType = eventType;
    }

    public static RuleExecutionEvent executionStarted(Object source, SpatialRule rule, String vehicleId,
                                                    String eventSource, Map<String, Object> executionContext) {
        return new RuleExecutionEvent(source, rule, vehicleId,
                RuleExecutionStatus.EXECUTING, null,
                LocalDateTime.now(), null,
                eventSource, executionContext,
                null, "规则执行开始", ExecutionEventType.EXECUTION_STARTED);
    }

    public static RuleExecutionEvent executionCompleted(Object source, SpatialRule rule, String vehicleId,
                                                      RuleExecutionResult result, LocalDateTime startTime,
                                                      String eventSource, Map<String, Object> executionContext,
                                                      String details) {
        return new RuleExecutionEvent(source, rule, vehicleId,
                RuleExecutionStatus.SUCCESS, result,
                startTime, LocalDateTime.now(),
                eventSource, executionContext,
                null, details, ExecutionEventType.EXECUTION_COMPLETED);
    }

    public static RuleExecutionEvent executionFailed(Object source, SpatialRule rule, String vehicleId,
                                                    LocalDateTime startTime, String eventSource,
                                                    Map<String, Object> executionContext, String errorMessage) {
        return new RuleExecutionEvent(source, rule, vehicleId,
                RuleExecutionStatus.FAILED, RuleExecutionResult.EXECUTION_ERROR,
                startTime, LocalDateTime.now(),
                eventSource, executionContext,
                errorMessage, "规则执行失败: " + errorMessage, ExecutionEventType.EXECUTION_FAILED);
    }

    private long calculateDuration(LocalDateTime startTime, LocalDateTime endTime) {
        if (startTime == null || endTime == null) {
            return 0;
        }
        return java.time.Duration.between(startTime, endTime).toMillis();
    }

    public boolean isExecutionSuccessful() {
        return executionStatus == RuleExecutionStatus.SUCCESS && 
               executionResult != null && 
               executionResult != RuleExecutionResult.EXECUTION_ERROR;
    }

    public String getEventDescription() {
        return String.format("%s - 规则ID: %s, 车辆ID: %s, 状态: %s, 结果: %s, 耗时: %dms",
                eventType.getDescription(),
                rule.getRuleId(),
                vehicleId,
                executionStatus.name(),
                executionResult != null ? executionResult.name() : "N/A",
                executionDurationMs);
    }

    @Override
    public String toString() {
        return String.format("RuleExecutionEvent{ruleId='%s', vehicleId='%s', eventType=%s, status=%s, result=%s, duration=%dms}",
                rule.getRuleId(), vehicleId, eventType.name(), executionStatus.name(),
                executionResult != null ? executionResult.name() : "N/A", executionDurationMs);
    }
} 