package com.qaup.collision.pathconflict.event;

import com.qaup.collision.pathconflict.model.dto.ConflictAlertEvent;
import com.qaup.collision.pathconflict.service.VehicleCommandService;
import com.qaup.collision.websocket.broadcaster.RuleEventWebSocketPublisher;
import com.qaup.collision.websocket.message.PathConflictAlertMessage;
import com.qaup.collision.pathconflict.model.entity.ObjectRouteAssignment;
import com.qaup.collision.pathconflict.repository.ObjectRouteAssignmentRepository;
import com.qaup.collision.pathconflict.model.entity.ConflictAlertLog;

import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.context.event.EventListener;
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Component;

import java.math.BigDecimal;
import java.math.RoundingMode;

/**
 * 冲突告警事件监听器
 * 负责处理路径冲突告警事件，发送WebSocket消息和车辆控制指令
 * 
 * @author AI Assistant
 * @version 1.0
 * @since 2025-01-17
 */
@Slf4j
@Component
@RequiredArgsConstructor
public class ConflictAlertEventListener {
    
    private final RuleEventWebSocketPublisher webSocketPublisher;
    private final VehicleCommandService vehicleCommandService;
    private final ObjectRouteAssignmentRepository objectRouteAssignmentRepository;
    
    /**
     * 处理冲突告警事件
     */
    @Async
    @EventListener
    public void handleConflictAlert(ConflictAlertEvent event) {
        log.info("处理路径冲突告警事件: conflictId={}, alertType={}, alertLevel={}", 
            event.getConflictId().map(String::valueOf).orElse("N/A"), 
            event.getAlertType().map(Enum::name).orElse("N/A"), 
            event.getAlertLevel().map(Enum::name).orElse("N/A"));
        
        // 只有当告警级别为 WARNING, CRITICAL, EMERGENCY 时才发送给前端和车辆指令
        if (event.getAlertLevel().isPresent() &&
            (event.getAlertLevel().get() == ConflictAlertLog.AlertLevel.WARNING ||
             event.getAlertLevel().get() == ConflictAlertLog.AlertLevel.CRITICAL ||
             event.getAlertLevel().get() == ConflictAlertLog.AlertLevel.EMERGENCY)) {
            try {
                // 发送WebSocket消息到控制台
                sendWebSocketAlert(event);
                
                // 向涉及的无人车发送控制指令
                sendVehicleCommands(event);
                
            } catch (Exception e) {
                log.error("处理冲突告警事件失败: conflictId={}", event.getConflictId().orElse(null), e);
            }
        } else {
            log.debug("告警级别不符合发送条件，不发送WebSocket告警和车辆指令: conflictId={}, alertLevel={}", event.getConflictId().orElse(null), event.getAlertLevel().orElse(null));
        }
    }
    
    /**
     * 发送WebSocket告警消息到控制台
     */
    private void sendWebSocketAlert(ConflictAlertEvent event) {
        try {
            PathConflictAlertMessage message = PathConflictAlertMessage.builder()
                .conflictId(event.getConflictId().orElse(null))
                .alertType(event.getAlertType().orElse(null)) // 直接传递 Optional 里的枚举对象
                .alertLevel(event.getAlertLevel().orElse(null)) // 直接传递 Optional 里的枚举对象
                .message(event.getMessage())
                .object1(PathConflictAlertMessage.ConflictObject.builder()
                    .objectName(event.getObject1Name())
                    .objectType(event.getObject1Type().name())
                    .build())
                .object2(PathConflictAlertMessage.ConflictObject.builder()
                    .objectName(event.getObject2Name())
                    .objectType(event.getObject2Type().name())
                    .build())
                .position(event.getConflictPointLatitude() != null && event.getConflictPointLongitude() != null ?
                    PathConflictAlertMessage.Position.builder()
                        .latitude(event.getConflictPointLatitude())
                        .longitude(event.getConflictPointLongitude())
                        .build() : null)
                .object1Distance(new BigDecimal(event.getObject1Distance()).setScale(2, RoundingMode.HALF_UP).doubleValue()) // 内联四舍五入
                .object2Distance(new BigDecimal(event.getObject2Distance()).setScale(2, RoundingMode.HALF_UP).doubleValue()) // 内联四舍五入
                .timeToConflict1(event.getEstimatedTimeToConflictObj1()) // 新增
                .timeToConflict2(event.getEstimatedTimeToConflictObj2()) // 新增
                .timeGap(event.getTimeGapSeconds()) // 新增
                .eventTime(event.getEventTime())
                .build();
            
            // 发送WebSocket消息
            webSocketPublisher.publishPathConflictAlert(message);
            
            log.info("WebSocket告警消息已发送: conflictId={}", event.getConflictId().map(String::valueOf).orElse(null));
            
        } catch (Exception e) {
            log.error("发送WebSocket告警消息失败: conflictId={}", event.getConflictId().map(String::valueOf).orElse(null), e);
        }
    }
    
    /**
     * 向涉及的无人车发送控制指令
     */
    private void sendVehicleCommands(ConflictAlertEvent event) {
        try {
            // 向对象1发送指令（如果是无人车）
            objectRouteAssignmentRepository.findFirstByObjectNameAndObjectTypeOrderByAssignedAtDesc(
                event.getObject1Name(), ObjectRouteAssignment.ObjectType.UNMANNED_VEHICLE)
                .ifPresent(assignment -> sendVehicleCommand(event.getObject1Name(), event));
            
            // 向对象2发送指令（如果是无人车）
            objectRouteAssignmentRepository.findFirstByObjectNameAndObjectTypeOrderByAssignedAtDesc(
                event.getObject2Name(), ObjectRouteAssignment.ObjectType.UNMANNED_VEHICLE)
                .ifPresent(assignment -> sendVehicleCommand(event.getObject2Name(), event));
            
        } catch (Exception e) {
            log.error("发送车辆控制指令失败: conflictId={}", event.getConflictId().orElse(null), e);
        }
    }
    
    /**
     * 向指定无人车发送控制指令
     */
    private void sendVehicleCommand(String vehicleId, ConflictAlertEvent event) {
        try {
            String commandType;
            String commandMessage;
            
            // 根据告警级别确定指令类型
            if (event.isEmergencyAlert()) {
                commandType = "EMERGENCY_STOP";
                commandMessage = String.format("紧急告警：检测到路径冲突，立即停车！对象1距离冲突点：%.1f米，对象2距离冲突点：%.1f米，时间差：%.1f秒", 
                    event.getObject1Distance(), event.getObject2Distance(), event.getTimeGapSeconds());
            } else if (event.isAlert()) {
                commandType = "SLOW_DOWN";
                commandMessage = String.format("路径冲突告警：前方对象1预计%d秒，对象2预计%d秒到达冲突点，请减速行驶，时间差：%.1f秒", 
                    event.getEstimatedTimeToConflictObj1(), event.getEstimatedTimeToConflictObj2(), event.getTimeGapSeconds());
            } else if (event.isWarning()) {
                commandType = "CAUTION";
                commandMessage = String.format("路径冲突预警：前方检测到潜在冲突，请注意观察。对象1距离冲突点：%.1f米，对象2距离冲突点：%.1f米", 
                    event.getObject1Distance(), event.getObject2Distance());
            } else {
                // 如果是非警告、非关键、非紧急的告警（即旧的INFO级别），则不发送指令。
                // 在PathConflictDetectionService中已经过滤了INFO级别的事件生成，
                // 所以理论上此处不会进入此分支，但作为防御性编程，避免意外情况。
                log.warn("收到非WARNING/CRITICAL/EMERGENCY级别的告警事件，不发送车辆指令: conflictId={}, alertLevel={}", 
                    event.getConflictId().orElse(null), event.getAlertLevel().orElse(null));
                return; // 不发送指令
            }
            
            // 发送指令到无人车
            boolean success = vehicleCommandService.sendCommand(
                vehicleId, commandType, commandMessage, event.getConflictId().map(String::valueOf).orElse(null));
            
            if (success) {
                log.info("车辆控制指令已发送: vehicleId={}, commandType={}, conflictId={}", 
                    vehicleId, commandType, event.getConflictId().map(String::valueOf).orElse(null));
            } else {
                log.warn("车辆控制指令发送失败: vehicleId={}, conflictId={}", 
                    vehicleId, event.getConflictId().map(String::valueOf).orElse(null));
            }
            
        } catch (Exception e) {
            log.error("发送车辆控制指令时出错: vehicleId={}, conflictId={}", 
                vehicleId, event.getConflictId().map(String::valueOf).orElse(null), e);
        }
    }
} 