package com.qaup.collision.pathconflict.service;

import com.qaup.collision.pathconflict.model.entity.TransportRoute;
import com.qaup.collision.pathconflict.repository.TransportRouteRepository;
import com.qaup.collision.common.model.MovingObject;
import com.qaup.collision.common.model.MovingObject.MovingObjectType;
import com.qaup.collision.pathconflict.model.dto.ConflictAlertEvent;
import com.qaup.collision.pathconflict.model.entity.ObjectRouteAssignment;
import com.qaup.collision.pathconflict.repository.ObjectRouteAssignmentRepository;
import com.qaup.collision.pathconflict.model.entity.ConflictAlertLog;
import com.qaup.collision.pathconflict.repository.ConflictAlertLogRepository;
import com.qaup.collision.dataprocessing.service.CoordinateSystemService;

import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.locationtech.jts.geom.*;
import org.locationtech.jts.operation.distance.DistanceOp;
import org.springframework.stereotype.Service;
import org.springframework.context.ApplicationEventPublisher;

import java.util.*;
import java.util.Optional;

/**
 * 路径冲突检测服务
 * 基于路径、速度和距离的冲突检测算法
 * 
 * @author AI Assistant
 * @version 1.0
 * @since 2025-01-17
 */
@Slf4j
@Service
@RequiredArgsConstructor
public class PathConflictDetectionService {
    
    private final TransportRouteRepository routeRepository;
    private final ObjectRouteAssignmentRepository objectRouteAssignmentRepository;
    private final ConflictAlertLogRepository conflictAlertLogRepository;
    private final ApplicationEventPublisher eventPublisher;
    private final CoordinateSystemService coordinateSystemService; // 注入 CoordinateSystemService
    
    // 预警距离阈值（米）
    private static final double WARNING_DISTANCE_THRESHOLD = 200.0;
    // 告警距离阈值（米）
    private static final double ALERT_DISTANCE_THRESHOLD = 100.0;
    // 最大检测时间范围（秒）
    private static final int MAX_PREDICTION_TIME_SECONDS = 300; // 5分钟
    // 最小时间间隔阈值（秒）
    private static final double MIN_TIME_GAP_SECONDS = 30.0;
    
    /**
     * 执行路径冲突检测
     * 
     * @param activeObjects 当前活跃的移动对象（无人车和航空器）
     */
    public void detectPathConflicts(List<MovingObject> activeObjects) {
        log.debug("开始路径冲突检测，活跃对象数量: {}", activeObjects.size());
        
        List<ConflictAlertEvent> detectedAlertEvents = new ArrayList<>();
        
        // 生成所有对象组合
        for (int i = 0; i < activeObjects.size(); i++) {
            for (int j = i + 1; j < activeObjects.size(); j++) {
                MovingObject obj1 = activeObjects.get(i);
                MovingObject obj2 = activeObjects.get(j);
                
                // 检测两个对象之间的潜在冲突
                Optional<ConflictAlertEvent> alertEventOptional = detectConflictBetweenObjects(obj1, obj2);
                alertEventOptional.ifPresent(detectedAlertEvents::add);
            }
        }
        
        // 发布告警事件
        for (ConflictAlertEvent event : detectedAlertEvents) {
            eventPublisher.publishEvent(event);
            log.info("发布冲突告警事件: conflictId={}, alertType={}, alertLevel={}", 
                     event.getConflictId(), event.getAlertType(), event.getAlertLevel());
        }
        
        log.info("路径冲突检测完成，检测到并发布 {} 个潜在冲突告警事件", detectedAlertEvents.size());
    }
    
    /**
     * 检测两个对象之间的路径冲突
     */
    private Optional<ConflictAlertEvent> detectConflictBetweenObjects(MovingObject obj1, MovingObject obj2) {
        if (obj1.getObjectType() != MovingObjectType.UNMANNED_VEHICLE && obj2.getObjectType() != MovingObjectType.UNMANNED_VEHICLE) {
            log.debug("对象 {} 和 {} 都不是无人车，跳过冲突检测", obj1.getObjectName(), obj2.getObjectName());
            return Optional.empty();
        }

        try {
            // 获取对象的路径
            TransportRoute route1 = getObjectRoute(obj1);
            TransportRoute route2 = getObjectRoute(obj2);
            
            if (route1 == null || route2 == null) {
                log.debug("对象 {} 或 {} 没有分配路径，跳过冲突检测", obj1.getObjectName(), obj2.getObjectName());
                return Optional.empty();
            }
            
            // 计算路径交点
            List<Point> intersectionPoints = calculateRouteIntersections(route1, route2);
            
            for (Point intersectionPoint : intersectionPoints) {
                // 计算每个对象到交点的距离和时间
                ConflictCalculationResult result = calculateConflictDetails(obj1, obj2, route1, route2, intersectionPoint);
                
                if (result != null && isSignificantConflict(result)) {
                    String description = generateConflictDescription(obj1, obj2, route1, route2);
                    
                    ConflictAlertLog alertLog = ConflictAlertLog.builder()
                        .alertType(result.getAlertType().orElse(null))
                        .alertLevel(result.getAlertLevel().orElse(null))
                        .alertMessage(description)
                        .object1Distance(result.getDistance1())
                        .object2Distance(result.getDistance2())
                        .minimumDistance(Math.min(result.getDistance1(), result.getDistance2())) // 简化处理，可根据需要调整
                        .build();

                    conflictAlertLogRepository.save(alertLog);
                    log.info("保存冲突告警日志: {}", alertLog);
                    
                    return Optional.of(ConflictAlertEvent.builder()
                        .conflictId(Optional.of(alertLog.getId()))
                        .alertType(result.getAlertType())
                        .alertLevel(result.getAlertLevel())
                        .message(description)
                        .object1Name(obj1.getObjectName())
                        .object1Type(obj1.getObjectType())
                        .object2Name(obj2.getObjectName())
                        .object2Type(obj2.getObjectType())
                        .conflictPoint(intersectionPoint)
                        .object1Distance(result.getDistance1())
                        .object2Distance(result.getDistance2())
                        .estimatedTimeToConflictObj1(result.getTimeToConflict1())
                        .estimatedTimeToConflictObj2(result.getTimeToConflict2())
                        .timeGapSeconds(result.getTimeGap())
                        .build());
                }
            }
            
        } catch (Exception e) {
            log.error("检测对象 {} 和 {} 之间的冲突时发生异常", obj1.getObjectName(), obj2.getObjectName(), e);
        }
        
        return Optional.empty();
    }
    
    /**
     * 获取对象当前使用的路径
     */
    private TransportRoute getObjectRoute(MovingObject obj) {
        Optional<ObjectRouteAssignment> assignmentOptional = objectRouteAssignmentRepository.findFirstByObjectNameAndObjectTypeOrderByAssignedAtDesc(
            obj.getObjectName(), // Changed from getObjectId
            ObjectRouteAssignment.ObjectType.valueOf(obj.getObjectType().name())
        );

        return assignmentOptional.map(assignment -> routeRepository.findById(assignment.getAssignedRouteId()).orElse(null)) // Changed findByRouteId to findById
                                 .orElse(null);
    }
    
    /**
     * 计算两条路径的交点
     */
    private List<Point> calculateRouteIntersections(TransportRoute route1, TransportRoute route2) {
        List<Point> intersections = new ArrayList<>();
        
        try {
            LineString line1 = route1.getRouteGeometry();
            LineString line2 = route2.getRouteGeometry();
            
            Geometry intersection = line1.intersection(line2);
            
            if (intersection instanceof Point) {
                intersections.add((Point) intersection);
            } else if (intersection instanceof MultiPoint) {
                MultiPoint multiPoint = (MultiPoint) intersection;
                for (int i = 0; i < multiPoint.getNumGeometries(); i++) {
                    intersections.add((Point) multiPoint.getGeometryN(i));
                }
            } else if (intersection instanceof LineString) {
                // 如果是线段重叠，取线段的中点
                LineString overlapLine = (LineString) intersection;
                Point midPoint = overlapLine.getInteriorPoint();
                // 确保中间点不为空且不是POINT EMPTY
                if (midPoint != null && !midPoint.isEmpty()) {
                    intersections.add(midPoint);
                } else {
                    log.warn("LineString交点生成了空的中间点或无效点，跳过此交点。OverlapLine: {}", overlapLine);
                }
            }
            
        } catch (Exception e) {
            log.error("计算路径交点时出错", e);
        }
        
        return intersections;
    }
    
    /**
     * 计算冲突详细信息
     */
    private ConflictCalculationResult calculateConflictDetails(
            MovingObject obj1, MovingObject obj2, 
            TransportRoute route1, TransportRoute route2,
            Point intersectionPoint) {
        
        try {
            // 计算对象到交点的距离
            double distance1 = calculateDistanceAlongRoute(obj1.getCurrentPosition(), intersectionPoint, route1);
            double distance2 = calculateDistanceAlongRoute(obj2.getCurrentPosition(), intersectionPoint, route2);
            
            // 计算到达交点的时间（基于当前速度）
            // 处理速度为null的情况，使用默认最小速度1 km/h
            double speed1 = Math.max(obj1.getCurrentSpeed() != null ? obj1.getCurrentSpeed() : 1.0, 1.0); // 避免除零，最小速度1 km/h
            double speed2 = Math.max(obj2.getCurrentSpeed() != null ? obj2.getCurrentSpeed() : 1.0, 1.0);
            
            // 转换为m/s
            double speed1_ms = speed1 * 1000.0 / 3600.0;
            double speed2_ms = speed2 * 1000.0 / 3600.0;
            
            int timeToConflict1 = (int) (distance1 / speed1_ms);
            int timeToConflict2 = (int) (distance2 / speed2_ms);
            
            // 计算时间差
            double timeGap = Math.abs(timeToConflict1 - timeToConflict2);
            
            // 评估冲突告警级别和类型
            Optional<ConflictAlertLog.AlertLevel> alertLevelOptional = evaluateAlertLevel(distance1, obj1.getObjectType(), distance2, obj2.getObjectType(), timeGap);
            Optional<ConflictAlertLog.AlertType> alertTypeOptional = alertLevelOptional.isPresent()
                ? evaluateAlertType(alertLevelOptional.get())
                : Optional.empty();
            
            return new ConflictCalculationResult(
                distance1, distance2, timeToConflict1, timeToConflict2, timeGap,
                alertTypeOptional, alertLevelOptional,
                obj1.getObjectType(), obj2.getObjectType()); // Pass object types
                
        } catch (Exception e) {
            log.error("计算冲突详细信息时出错", e);
            return null;
        }
    }
    
    /**
     * 评估冲突的告警级别
     */
    private Optional<ConflictAlertLog.AlertLevel> evaluateAlertLevel(
            double distance1, MovingObjectType obj1Type,
            double distance2, MovingObjectType obj2Type,
            double timeGap) {

        boolean obj1IsUnmannedVehicle = MovingObjectType.UNMANNED_VEHICLE.equals(obj1Type);
        boolean obj2IsUnmannedVehicle = MovingObjectType.UNMANNED_VEHICLE.equals(obj2Type);

        if (!obj1IsUnmannedVehicle && !obj2IsUnmannedVehicle) {
            // 双方都不是无人车，根据业务规则，不生成告警。
            return Optional.empty();
        }

        double distanceToEvaluate;

        if (obj1IsUnmannedVehicle && obj2IsUnmannedVehicle) {
            // 双方都是无人车，关注两者中离交点最近的距离
            distanceToEvaluate = Math.min(distance1, distance2);
        } else if (obj1IsUnmannedVehicle) {
            // 只有 obj1 是无人车，关注 obj1 的距离。obj2 是无人车需要避让的对象。
            distanceToEvaluate = distance1;
        } else { // obj2IsUnmannedVehicle
            // 只有 obj2 是无人车，关注 obj2 的距离。obj1 是无人车需要避让的对象。
            distanceToEvaluate = distance2;
        }

        // 现在根据确定的 relevantDistance 评估告警级别
        if (distanceToEvaluate <= ALERT_DISTANCE_THRESHOLD && timeGap <= MIN_TIME_GAP_SECONDS) {
            return Optional.of(ConflictAlertLog.AlertLevel.CRITICAL);
        } else if (distanceToEvaluate <= WARNING_DISTANCE_THRESHOLD && timeGap <= MIN_TIME_GAP_SECONDS * 2) {
            return Optional.of(ConflictAlertLog.AlertLevel.WARNING);
        } else {
            // 不满足 CRITICAL/WARNING 阈值，不生成告警。
            return Optional.empty();
        }
    }

    /**
     * 根据告警级别评估告警类型
     */
    private Optional<ConflictAlertLog.AlertType> evaluateAlertType(ConflictAlertLog.AlertLevel alertLevel) {
        // 处理null输入
        if (alertLevel == null) {
            return Optional.empty();
        }

        switch (alertLevel) {
            case WARNING:
                return Optional.of(ConflictAlertLog.AlertType.CONFLICT_WARNING);
            case CRITICAL:
            case EMERGENCY:
                return Optional.of(ConflictAlertLog.AlertType.CONFLICT_ALERT);
            default:
                // 应该不会到达这里，因为所有的 AlertLevel 都已经被明确处理
                return Optional.empty();
        }
    }
    
    /**
     * 判断是否为显著冲突
     */
    private boolean isSignificantConflict(ConflictCalculationResult result) {
        return result.getAlertLevel().isPresent() && 
               (result.getAlertLevel().get() == ConflictAlertLog.AlertLevel.WARNING ||
                result.getAlertLevel().get() == ConflictAlertLog.AlertLevel.CRITICAL ||
                result.getAlertLevel().get() == ConflictAlertLog.AlertLevel.EMERGENCY);
    }
    
    /**
     * 计算沿路径的距离
     */
    private double calculateDistanceAlongRoute(Point currentPos, Point targetPos, TransportRoute route) {
        try {
            // 1. 获取原始路径几何和点
            LineString originalRouteLine = route.getRouteGeometry();
            
            // 2. 将所有相关几何对象转换为局部米制坐标系
            // 2.1 转换 currentPos 和 targetPos
            double[] localCurrentCoords = coordinateSystemService.convertToLocalCoordinate(currentPos.getX(), currentPos.getY());
            double[] localTargetCoords = coordinateSystemService.convertToLocalCoordinate(targetPos.getX(), targetPos.getY());

            GeometryFactory geometryFactory = new GeometryFactory(new PrecisionModel(), 0); // SRID 0 for Cartesian system (meters)
            Point localCurrentPos = geometryFactory.createPoint(new Coordinate(localCurrentCoords[0], localCurrentCoords[1]));
            Point localTargetPos = geometryFactory.createPoint(new Coordinate(localTargetCoords[0], localTargetCoords[1]));

            // 2.2 转换 routeLine
            Coordinate[] originalCoords = originalRouteLine.getCoordinates();
            Coordinate[] localRouteCoords = new Coordinate[originalCoords.length];
            for (int i = 0; i < originalCoords.length; i++) {
                double[] localCoord = coordinateSystemService.convertToLocalCoordinate(originalCoords[i].x, originalCoords[i].y);
                localRouteCoords[i] = new Coordinate(localCoord[0], localCoord[1]);
            }
            LineString localRouteLine = geometryFactory.createLineString(localRouteCoords);
            
            // 3. 在局部米制坐标系中执行距离计算
            // 3.1 找到当前位置在路径上的最近点
            DistanceOp distOp1 = new DistanceOp(localCurrentPos, localRouteLine);
            Coordinate[] nearestPoints1 = distOp1.nearestPoints();
            Point nearestOnRoute1 = geometryFactory.createPoint(nearestPoints1[1]);
            
            // 3.2 找到目标位置在路径上的最近点
            DistanceOp distOp2 = new DistanceOp(localTargetPos, localRouteLine);
            Coordinate[] nearestPoints2 = distOp2.nearestPoints();
            Point nearestOnRoute2 = geometryFactory.createPoint(nearestPoints2[1]);
            
            // 3.3 计算沿路径的距离 (现在这些距离将是米)
            double distanceToCurrentOnRoute = getLinearLengthToPoint(localRouteLine, nearestOnRoute1);
            double distanceToTargetOnRoute = getLinearLengthToPoint(localRouteLine, nearestOnRoute2);
            
            return Math.abs(distanceToTargetOnRoute - distanceToCurrentOnRoute);
            
        } catch (Exception e) {
            log.error("计算沿路径距离时出错: currentPos={}, targetPos={}", 
                      currentPos, targetPos, e);
            return -1.0; // 表示错误
        }
    }
    
    /**
     * 生成冲突ID
     */
    private String generateConflictId(String obj1Name, String obj2Name) {
        // 确保ID的生成是确定性的，与对象的顺序无关
        String[] names = {obj1Name, obj2Name};
        Arrays.sort(names);
        return "CONFLICT-" + names[0] + "-" + names[1] + "-" + UUID.randomUUID().toString().substring(0, 8);
    }
    
    /**
     * 生成冲突描述
     */
    private String generateConflictDescription(
            MovingObject obj1, MovingObject obj2,
            TransportRoute route1, TransportRoute route2) {
        return String.format("对象 %s (%s) 在路径上与对象 %s (%s) 可能发生冲突。",
            obj1.getObjectName(), obj1.getObjectType(),
            obj2.getObjectName(), obj2.getObjectType());
    }
    
    /**
     * 计算沿LineString从起点到给定点的距离。
     * 假定point已经投影到line上。
     * 如果点不在line上，结果可能不准确。
     */
    private double getLinearLengthToPoint(LineString line, Point point) {
        double length = 0.0;
        Coordinate[] coords = line.getCoordinates();
        
        for (int i = 0; i < coords.length - 1; i++) {
            Point p1 = line.getFactory().createPoint(coords[i]);
            Point p2 = line.getFactory().createPoint(coords[i+1]);
            
            // 如果点在线段 (p1, p2) 上，则计算到p1的距离，然后加上点到p1的距离
            if (point.equals(p1)) {
                return length;
            }
            
            double segmentLength = p1.distance(p2);
            // 检查点是否在当前线段上 (使用一个小的容差)
            if (point.distance(p1) + point.distance(p2) - segmentLength < 1e-6) { // 容差检查
                 return length + p1.distance(point);
            }
            length += segmentLength;
        }
        // 如果点是最后一个点
        if (point.equals(line.getEndPoint())) {
            return line.getLength();
        }
        // 如果没有找到匹配，返回-1或者抛异常，这里返回线长表示无法准确计算
        return -1.0; // 表示未找到精确位置或计算错误
    }

    /**
     * 冲突计算结果内部类
     */
    private static class ConflictCalculationResult {
        private final double distance1;
        private final double distance2;
        private final int timeToConflict1;
        private final int timeToConflict2;
        private final double timeGap;
        private final Optional<ConflictAlertLog.AlertType> alertType; // Changed to Optional
        private final Optional<ConflictAlertLog.AlertLevel> alertLevel; // Changed to Optional
        private final MovingObjectType object1Type; // New
        private final MovingObjectType object2Type; // New

        public ConflictCalculationResult(double distance1, double distance2,
                                       int timeToConflict1, int timeToConflict2,
                                       double timeGap,
                                       Optional<ConflictAlertLog.AlertType> alertType, // Changed to Optional
                                       Optional<ConflictAlertLog.AlertLevel> alertLevel, // Changed to Optional
                                       MovingObjectType object1Type, // New
                                       MovingObjectType object2Type) { // New
            this.distance1 = distance1;
            this.distance2 = distance2;
            this.timeToConflict1 = timeToConflict1;
            this.timeToConflict2 = timeToConflict2;
            this.timeGap = timeGap;
            this.alertType = alertType; // Changed
            this.alertLevel = alertLevel; // Changed
            this.object1Type = object1Type; // New
            this.object2Type = object2Type; // New
        }

        public double getDistance1() { return distance1; }
        public double getDistance2() { return distance2; }
        public int getTimeToConflict1() { return timeToConflict1; }
        public int getTimeToConflict2() { return timeToConflict2; }
        public double getTimeGap() { return timeGap; }
        public Optional<ConflictAlertLog.AlertType> getAlertType() { return alertType; } // Changed
        public Optional<ConflictAlertLog.AlertLevel> getAlertLevel() { return alertLevel; } // Changed
        public MovingObjectType getObject1Type() { return object1Type; } // New
        public MovingObjectType getObject2Type() { return object2Type; } // New
    }
} 