package com.qaup.collision.common.service;

import com.qaup.collision.common.model.spatial.AirportArea;
import com.qaup.collision.common.model.spatial.VehicleLocation;
import com.qaup.common.constant.GeoConstants;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.locationtech.jts.geom.*;
import org.springframework.stereotype.Service;

import java.time.LocalDateTime;
import java.util.*;
import java.util.stream.Collectors;

/**
 * 空间查询服务类 - 基于PostGIS的综合空间分析
 * 提供车辆位置与机场区域的空间关系分析、碰撞检测、路径规划等功能
 */
@Service
@RequiredArgsConstructor
@Slf4j
public class SpatialQueryService {

    private final VehicleLocationService vehicleLocationService;
    private final AirportAreaService airportAreaService;
    /**
     * 综合空间查询结果
     */
    public static class SpatialQueryResult {
        private List<VehicleLocation> vehiclesInArea;
        private List<AirportArea> areasContainingVehicles;
        private Map<String, Object> spatialStatistics;
        private List<ConflictDetection> potentialConflicts;

        // 构造函数和getter/setter
        public SpatialQueryResult() {
            this.vehiclesInArea = new ArrayList<>();
            this.areasContainingVehicles = new ArrayList<>();
            this.spatialStatistics = new HashMap<>();
            this.potentialConflicts = new ArrayList<>();
        }

        // Getters and Setters
        public List<VehicleLocation> getVehiclesInArea() { return vehiclesInArea; }
        public void setVehiclesInArea(List<VehicleLocation> vehiclesInArea) { this.vehiclesInArea = vehiclesInArea; }
        
        public List<AirportArea> getAreasContainingVehicles() { return areasContainingVehicles; }
        public void setAreasContainingVehicles(List<AirportArea> areasContainingVehicles) { this.areasContainingVehicles = areasContainingVehicles; }
        
        public Map<String, Object> getSpatialStatistics() { return spatialStatistics; }
        public void setSpatialStatistics(Map<String, Object> spatialStatistics) { this.spatialStatistics = spatialStatistics; }
        
        public List<ConflictDetection> getPotentialConflicts() { return potentialConflicts; }
        public void setPotentialConflicts(List<ConflictDetection> potentialConflicts) { this.potentialConflicts = potentialConflicts; }
    }

    /**
     * 冲突检测结果
     */
    public static class ConflictDetection {
        private String conflictType;
        private VehicleLocation vehicle1;
        private VehicleLocation vehicle2;
        private AirportArea affectedArea;
        private double distance;
        private String severity;
        private String description;

        public ConflictDetection(String conflictType, String severity, String description) {
            this.conflictType = conflictType;
            this.severity = severity;
            this.description = description;
        }

        // Getters and Setters
        public String getConflictType() { return conflictType; }
        public void setConflictType(String conflictType) { this.conflictType = conflictType; }
        
        public VehicleLocation getVehicle1() { return vehicle1; }
        public void setVehicle1(VehicleLocation vehicle1) { this.vehicle1 = vehicle1; }
        
        public VehicleLocation getVehicle2() { return vehicle2; }
        public void setVehicle2(VehicleLocation vehicle2) { this.vehicle2 = vehicle2; }
        
        public AirportArea getAffectedArea() { return affectedArea; }
        public void setAffectedArea(AirportArea affectedArea) { this.affectedArea = affectedArea; }
        
        public double getDistance() { return distance; }
        public void setDistance(double distance) { this.distance = distance; }
        
        public String getSeverity() { return severity; }
        public void setSeverity(String severity) { this.severity = severity; }
        
        public String getDescription() { return description; }
        public void setDescription(String description) { this.description = description; }
    }

    /**
     * 执行综合空间分析
     */
    public SpatialQueryResult performSpatialAnalysis(double longitude, double latitude, double radiusMeters, int minutesBack) {
        SpatialQueryResult result = new SpatialQueryResult();

        try {
            // 1. 查找半径范围内的车辆
            List<VehicleLocation> nearbyVehicles = vehicleLocationService.getVehiclesWithinRadius(
                longitude, latitude, radiusMeters, minutesBack);
            result.setVehiclesInArea(nearbyVehicles);

            // 2. 查找包含指定点的区域
            List<AirportArea> containingAreas = airportAreaService.getAreasContainingPoint(longitude, latitude);
            result.setAreasContainingVehicles(containingAreas);

            // 3. 执行冲突检测
            List<ConflictDetection> conflicts = detectVehicleConflicts(nearbyVehicles, radiusMeters);
            result.setPotentialConflicts(conflicts);

            // 4. 计算空间统计信息
            Map<String, Object> statistics = calculateSpatialStatistics(nearbyVehicles, containingAreas);
            result.setSpatialStatistics(statistics);

            log.info("空间分析完成: 中心点=({}, {}), 半径={}m, 发现车辆={}, 发现区域={}, 冲突数={}",
                longitude, latitude, radiusMeters, nearbyVehicles.size(), containingAreas.size(), conflicts.size());

        } catch (Exception e) {
            log.error("空间分析失败: 中心点=({}, {}), 半径={}m", longitude, latitude, radiusMeters, e);
        }

        return result;
    }

    /**
     * 检测车辆间的潜在冲突
     */
    public List<ConflictDetection> detectVehicleConflicts(List<VehicleLocation> vehicles, double alertRadius) {
        List<ConflictDetection> conflicts = new ArrayList<>();

        try {
            for (int i = 0; i < vehicles.size(); i++) {
                for (int j = i + 1; j < vehicles.size(); j++) {
                    VehicleLocation vehicle1 = vehicles.get(i);
                    VehicleLocation vehicle2 = vehicles.get(j);

                    double distance = calculateDistance(vehicle1.getLocation(), vehicle2.getLocation());

                    // 距离冲突检测
                    if (distance < alertRadius) {
                        ConflictDetection conflict = new ConflictDetection(
                            "PROXIMITY_CONFLICT",
                            distance < alertRadius * 0.5 ? "HIGH" : "MEDIUM",
                            String.format("车辆 %s 和 %s 距离过近: %.2fm", 
                                vehicle1.getVehicleId(), vehicle2.getVehicleId(), distance)
                        );
                        conflict.setVehicle1(vehicle1);
                        conflict.setVehicle2(vehicle2);
                        conflict.setDistance(distance);
                        conflicts.add(conflict);
                    }

                    // 相向移动冲突检测
                    if (isHeadOnConflict(vehicle1, vehicle2, distance)) {
                        ConflictDetection conflict = new ConflictDetection(
                            "HEAD_ON_CONFLICT",
                            "HIGH",
                            String.format("车辆 %s 和 %s 可能发生正面冲突", 
                                vehicle1.getVehicleId(), vehicle2.getVehicleId())
                        );
                        conflict.setVehicle1(vehicle1);
                        conflict.setVehicle2(vehicle2);
                        conflict.setDistance(distance);
                        conflicts.add(conflict);
                    }
                }
            }
        } catch (Exception e) {
            log.error("冲突检测失败", e);
        }

        return conflicts;
    }

    /**
     * 检测车辆违反区域限制
     */
    public List<ConflictDetection> detectAreaViolations(Long vehicleId, int minutesBack) {
        List<ConflictDetection> violations = new ArrayList<>();

        try {
            Optional<VehicleLocation> vehicleOpt = vehicleLocationService.getLatestVehicleLocation(vehicleId);
            if (vehicleOpt.isEmpty()) {
                return violations;
            }

            VehicleLocation vehicle = vehicleOpt.get();
            Point vehiclePoint = vehicle.getLocation();

            // 检查车辆所在的所有区域
            List<AirportArea> containingAreas = airportAreaService.getAreasContainingPoint(
                vehiclePoint.getX(), vehiclePoint.getY());

            for (AirportArea area : containingAreas) {
                // 检查速度限制
                if (isSpeedViolation(vehicle, area)) {
                    ConflictDetection violation = new ConflictDetection(
                        "SPEED",
                        "MEDIUM",
                        String.format("车辆 %s 在区域 %s 超速", vehicleId, area.getName())
                    );
                    violation.setVehicle1(vehicle);
                    violation.setAffectedArea(area);
                    violations.add(violation);
                }

                // 检查车辆类型限制
                if (isVehicleTypeViolation(vehicle, area)) {
                    ConflictDetection violation = new ConflictDetection(
                        "ACCESS",
                        "HIGH",
                        String.format("车辆 %s 不允许进入区域 %s", vehicleId, area.getName())
                    );
                    violation.setVehicle1(vehicle);
                    violation.setAffectedArea(area);
                    violations.add(violation);
                }
            }

        } catch (Exception e) {
            log.error("区域违规检测失败: vehicleId={}", vehicleId, e);
        }

        return violations;
    }

    /**
     * 查找车辆轨迹与区域的交互历史
     */
    public Map<String, Object> analyzeVehicleTrajectoryIntersections(Long vehicleId, LocalDateTime startTime, LocalDateTime endTime) {
        Map<String, Object> analysis = new HashMap<>();

        try {
            // 获取车辆轨迹
            List<VehicleLocation> trajectory = vehicleLocationService.getVehicleTrajectory(vehicleId, startTime, endTime);
            
            if (trajectory.isEmpty()) {
                analysis.put("error", "未找到轨迹数据");
                return analysis;
            }

            // 创建轨迹线
            String trajectoryWkt = createTrajectoryLineString(trajectory);
            
            // 查找与轨迹相交的区域
            List<AirportArea> intersectingAreas = airportAreaService.getAreasIntersectingTrajectory(trajectoryWkt);

            // 分析结果
            analysis.put("vehicleId", vehicleId);
            analysis.put("trajectoryPointCount", trajectory.size());
            analysis.put("intersectingAreaCount", intersectingAreas.size());
            analysis.put("intersectingAreas", intersectingAreas.stream()
                .map(area -> Map.of(
                    "areaName", area.getName(),
                    "areaType", area.getType(),
                    "priority", area.getPriority()
                )).collect(Collectors.toList()));

            // 计算轨迹统计
            analysis.put("totalDistance", calculateTrajectoryDistance(trajectory));
            analysis.put("maxSpeed", trajectory.stream()
                .filter(loc -> loc.getSpeed() != null)
                .mapToDouble(VehicleLocation::getSpeed)
                .max().orElse(0.0));
            analysis.put("averageSpeed", trajectory.stream()
                .filter(loc -> loc.getSpeed() != null)
                .mapToDouble(VehicleLocation::getSpeed)
                .average().orElse(0.0));

        } catch (Exception e) {
            log.error("轨迹交互分析失败: vehicleId={}", vehicleId, e);
            analysis.put("error", "分析失败: " + e.getMessage());
        }

        return analysis;
    }

    /**
     * 执行区域密度分析
     */
    public Map<String, Object> analyzeAreaDensity(String areaName, int minutesBack) {
        Map<String, Object> density = new HashMap<>();

        try {
            Optional<AirportArea> areaOpt = airportAreaService.getAreaByName(areaName);
            if (areaOpt.isEmpty()) {
                density.put("error", "区域不存在");
                return density;
            }

            AirportArea area = areaOpt.get();
            
            // 查找区域内的所有车辆
            String areaWkt = area.getBoundary().toString();
            List<VehicleLocation> vehiclesInArea = vehicleLocationService.getVehiclesInArea(areaWkt, minutesBack);

            // 计算密度指标
            double areaSize = area.getArea() != null ? area.getArea() : 0.0; // 平方米
            double vehicleDensity = areaSize > 0 ? vehiclesInArea.size() / (areaSize / 1000000) : 0; // 车辆/平方公里

            density.put("areaName", areaName);
            density.put("areaType", area.getType());
            density.put("areaSize", areaSize);
            density.put("vehicleCount", vehiclesInArea.size());
            density.put("vehicleDensity", vehicleDensity);
            
            // 按车辆类型分组
            Map<String, Long> vehicleTypeCount = vehiclesInArea.stream()
                .collect(Collectors.groupingBy(v -> v.getVehicleType().toString(), Collectors.counting()));
            density.put("vehicleTypeDistribution", vehicleTypeCount);

            // 速度统计
            density.put("averageSpeed", vehiclesInArea.stream()
                .filter(v -> v.getSpeed() != null)
                .mapToDouble(VehicleLocation::getSpeed)
                .average().orElse(0.0));

        } catch (Exception e) {
            log.error("区域密度分析失败: areaName={}", areaName, e);
            density.put("error", "分析失败: " + e.getMessage());
        }

        return density;
    }

    // ===== 私有辅助方法 =====

    private double calculateDistance(Point point1, Point point2) {
        return point1.distance(point2) * GeoConstants.DEGREE_TO_METER; // 近似转换为米（在赤道附近）
    }

    private boolean isHeadOnConflict(VehicleLocation vehicle1, VehicleLocation vehicle2, double distance) {
        if (vehicle1.getHeading() == null || vehicle2.getHeading() == null || distance > 1000) {
            return false;
        }

        // 检查航向是否相反（差异在150-210度之间表示相向）
        double headingDiff = Math.abs(vehicle1.getHeading() - vehicle2.getHeading());
        headingDiff = Math.min(headingDiff, 360 - headingDiff); // 处理跨0度的情况
        
        return headingDiff > 150 && headingDiff < 210 && distance < 500; // 500米内相向移动
    }

    private boolean isSpeedViolation(VehicleLocation vehicle, AirportArea area) {
        if (vehicle.getSpeed() == null) {
            return false;
        }

        try {
            // 注意：速度限制现在应该在geofences表中配置，而不是在area中
            // 这里提供一个简化的默认检查，实际应该查询相关的geofence规则
            return vehicle.getSpeed() > 25.0; // 假设默认限速25m/s
        } catch (Exception e) {
            return false;
        }
    }

    private boolean isVehicleTypeViolation(VehicleLocation vehicle, AirportArea area) {
        // 注意：车辆类型限制现在应该在geofences表中配置，而不是在area中
        // 这里返回false，实际应该查询相关的geofence规则来判断车辆类型是否允许
        return false;
    }

    private String createTrajectoryLineString(List<VehicleLocation> trajectory) {
        if (trajectory.size() < 2) {
            return "LINESTRING EMPTY";
        }

        StringBuilder wkt = new StringBuilder("LINESTRING(");
        for (int i = 0; i < trajectory.size(); i++) {
            Point location = trajectory.get(i).getLocation();
            wkt.append(location.getX()).append(" ").append(location.getY());
            if (i < trajectory.size() - 1) {
                wkt.append(", ");
            }
        }
        wkt.append(")");
        return wkt.toString();
    }

    private double calculateTrajectoryDistance(List<VehicleLocation> trajectory) {
        double totalDistance = 0.0;
        for (int i = 1; i < trajectory.size(); i++) {
            totalDistance += calculateDistance(
                trajectory.get(i-1).getLocation(),
                trajectory.get(i).getLocation()
            );
        }
        return totalDistance;
    }

    private Map<String, Object> calculateSpatialStatistics(List<VehicleLocation> vehicles, List<AirportArea> areas) {
        Map<String, Object> stats = new HashMap<>();
        
        stats.put("vehicleCount", vehicles.size());
        stats.put("areaCount", areas.size());
        
        if (!vehicles.isEmpty()) {
            stats.put("averageSpeed", vehicles.stream()
                .filter(v -> v.getSpeed() != null)
                .mapToDouble(VehicleLocation::getSpeed)
                .average().orElse(0.0));
                
            Map<String, Long> typeDistribution = vehicles.stream()
                .collect(Collectors.groupingBy(v -> v.getVehicleType().toString(), Collectors.counting()));
            stats.put("vehicleTypeDistribution", typeDistribution);
        }
        
        if (!areas.isEmpty()) {
            Map<String, Long> areaTypeDistribution = areas.stream()
                .collect(Collectors.groupingBy(AirportArea::getType, Collectors.counting()));
            stats.put("areaTypeDistribution", areaTypeDistribution);
        }
        
        return stats;
    }
} 