package com.qaup.collision.datacollector.util;

import lombok.extern.slf4j.Slf4j;
import org.locationtech.jts.geom.*;
import org.locationtech.jts.operation.linemerge.LineMerger;
import org.springframework.stereotype.Component;

import java.util.ArrayList;
import java.util.Collection;
import java.util.List;

/**
 * 路由几何处理工具类
 * 使用JTS Topology Suite将多个LineString段合并为单一连续路径
 * 支持CGCS2000坐标系（中国大地坐标系2000）的投影坐标数据
 */
@Slf4j
@Component
public class RouteGeometryProcessor {

    private final GeometryFactory geometryFactory = new GeometryFactory(new PrecisionModel(), 4326);
    
    /**
     * 将多个LineString段合并为单一连续的LineString
     * 使用JTS LineMerger自动处理无序线段的连接
     * 
     * @param lineStrings 多个LineString段的列表（可以是无序的）
     * @return 合并后的单一LineString，如果合并失败则返回null
     */
    public LineString mergeLineStrings(List<LineString> lineStrings) {
        if (lineStrings == null || lineStrings.isEmpty()) {
            log.warn("🛣️ 输入的LineString列表为空");
            return null;
        }
        
        if (lineStrings.size() == 1) {
            log.info("🛣️ 只有一个LineString段，直接返回");
            return lineStrings.get(0);
        }
        
        try {
            // 记录输入线段的详细信息
            logInputLineStrings(lineStrings);
            
            // 使用JTS LineMerger自动合并无序线段
            LineMerger lineMerger = new LineMerger();
            
            // 添加所有LineString到LineMerger
            for (LineString lineString : lineStrings) {
                if (lineString != null && !lineString.isEmpty()) {
                    lineMerger.add(lineString);
                }
            }
            
            // 获取合并结果
            @SuppressWarnings("unchecked")
            Collection<LineString> mergedLines = lineMerger.getMergedLineStrings();
            
            if (mergedLines.isEmpty()) {
                log.warn("🛣️ LineMerger未能合并任何线段");
                return null;
            }
            
            if (mergedLines.size() == 1) {
                // 成功合并为单一路径
                LineString result = mergedLines.iterator().next();
                log.info("🛣️ ✅ 使用LineMerger成功合并 {} 个LineString段为单一路径，包含 {} 个坐标点", 
                        lineStrings.size(), result.getNumPoints());
                return result;
            } else {
                // 合并后仍有多个不连续的线段，说明存在缺失
                logMissingSegments(lineStrings, mergedLines);
                
                // 返回最长的线段
                LineString longestLine = null;
                int maxPoints = 0;
                
                for (LineString line : mergedLines) {
                    if (line.getNumPoints() > maxPoints) {
                        maxPoints = line.getNumPoints();
                        longestLine = line;
                    }
                }
                
                log.warn("🛣️ ⚠️ LineMerger产生了 {} 个不连续的线段，返回最长的线段（{} 个坐标点）", 
                        mergedLines.size(), maxPoints);
                return longestLine;
            }
            
        } catch (Exception e) {
            log.error("🛣️ ❌ 使用LineMerger合并LineString段失败", e);
            return null;
        }
    }
    
    /**
     * 记录输入线段的详细信息
     */
    private void logInputLineStrings(List<LineString> lineStrings) {
        log.info("🛣️ 📋 输入线段详细信息（共 {} 段）：", lineStrings.size());
        for (int i = 0; i < lineStrings.size(); i++) {
            LineString line = lineStrings.get(i);
            if (line != null && !line.isEmpty()) {
                Coordinate[] coords = line.getCoordinates();
                log.info("🛣️   线段 {}: 起点[{}, {}] -> 终点[{}, {}], 包含 {} 个坐标点",
                        i + 1,
                        coords[0].x, coords[0].y,
                        coords[coords.length - 1].x, coords[coords.length - 1].y,
                        coords.length);
            } else {
                log.warn("🛣️   线段 {}: 空线段或无效线段", i + 1);
            }
        }
    }
    
    /**
     * 记录缺失线段的详细信息，供机场排查问题
     */
    private void logMissingSegments(List<LineString> originalLines, Collection<LineString> mergedLines) {
        log.error("🛣️ =============== 路由数据缺失检测报告 ===============");
        log.error("🛣️ 🚨 检测到路由数据存在缺失，无法形成完整连续路径！");
        log.error("🛣️ 📊 原始输入: {} 个线段", originalLines.size());
        log.error("🛣️ 📊 合并结果: {} 个不连续的路径段", mergedLines.size());
        
        // 分析每个不连续的路径段
        int segmentIndex = 1;
        for (LineString mergedLine : mergedLines) {
            Coordinate[] coords = mergedLine.getCoordinates();
            log.error("🛣️ 📍 路径段 {}: 起点[{}, {}] -> 终点[{}, {}], 长度: {} 个坐标点",
                    segmentIndex,
                    coords[0].x, coords[0].y,
                    coords[coords.length - 1].x, coords[coords.length - 1].y,
                    coords.length);
            segmentIndex++;
        }
        
        // 分析缺失的连接点
        if (mergedLines.size() > 1) {
            log.error("🛣️ 🔍 缺失连接分析：");
            LineString[] segments = mergedLines.toArray(new LineString[0]);
            
            for (int i = 0; i < segments.length - 1; i++) {
                LineString current = segments[i];
                LineString next = segments[i + 1];
                
                Coordinate currentEnd = current.getCoordinates()[current.getNumPoints() - 1];
                Coordinate nextStart = next.getCoordinates()[0];
                
                double distance = calculateDistance(currentEnd, nextStart);
                
                log.error("🛣️ ❌ 缺失连接 {}-{}: 从[{}, {}]到[{}, {}], 距离: {:.2f}米",
                        i + 1, i + 2,
                        currentEnd.x, currentEnd.y,
                        nextStart.x, nextStart.y,
                        distance);
            }
        }
        
        // 输出建议信息
        log.error("🛣️ 💡 建议机场方面检查：");
        log.error("🛣️   1. 是否有线段数据缺失");
        log.error("🛣️   2. 线段端点坐标是否准确");
        log.error("🛣️   3. 路由规划算法是否完整");
        log.error("🛣️ ================================================");
    }
    
    /**
     * 计算两个坐标点之间的距离（米）
     * CGCS2000投影坐标系使用欧几里得距离计算
     */
    private double calculateDistance(Coordinate coord1, Coordinate coord2) {
        double dx = coord2.x - coord1.x;
        double dy = coord2.y - coord1.y;
        return Math.sqrt(dx * dx + dy * dy);
    }
    
    /**
     * 从GeoJSON Feature列表中提取并合并LineString
     * 
     * @param coordinates 坐标数据列表，每个元素是一个LineString的坐标数组
     * @return 合并后的单一LineString
     */
    public LineString createMergedLineStringFromCoordinates(List<List<List<Double>>> coordinates) {
        if (coordinates == null || coordinates.isEmpty()) {
            return null;
        }
        
        List<LineString> lineStrings = new ArrayList<>();
        
        // 将坐标数据转换为LineString对象
        for (List<List<Double>> coordArray : coordinates) {
            if (coordArray != null && coordArray.size() >= 2) {
                Coordinate[] coords = coordArray.stream()
                    .map(coord -> new Coordinate(coord.get(0), coord.get(1)))
                    .toArray(Coordinate[]::new);
                
                LineString lineString = geometryFactory.createLineString(coords);
                lineStrings.add(lineString);
            }
        }
        
        return mergeLineStrings(lineStrings);
    }
    
    /**
     * 验证LineString的有效性
     */
    public boolean isValidLineString(LineString lineString) {
        if (lineString == null) {
            return false;
        }
        
        return lineString.isValid() && lineString.getNumPoints() >= 2;
    }
    
    /**
     * 简化LineString以减少冗余点
     * 
     * @param lineString 输入的LineString
     * @param tolerance 简化容差（米）
     * @return 简化后的LineString
     */
    public LineString simplifyLineString(LineString lineString, double tolerance) {
        if (lineString == null) {
            return null;
        }
        
        try {
            Geometry simplified = org.locationtech.jts.simplify.DouglasPeuckerSimplifier.simplify(lineString, tolerance);
            if (simplified instanceof LineString) {
                return (LineString) simplified;
            } else {
                log.warn("简化后的几何对象不是LineString类型: {}", simplified.getGeometryType());
                return lineString;
            }
        } catch (Exception e) {
            log.error("简化LineString失败", e);
            return lineString;
        }
    }
}