package com.qaup.collision.common.service;

import com.qaup.collision.common.model.spatial.AirportArea;
import com.qaup.collision.common.model.repository.AirportAreaRepository;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.locationtech.jts.geom.Coordinate;
import org.locationtech.jts.geom.GeometryFactory;
import org.locationtech.jts.geom.Point;
import org.locationtech.jts.geom.Polygon;
import org.locationtech.jts.geom.Geometry;
import org.locationtech.jts.io.WKTReader;
import org.locationtech.jts.io.ParseException;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.List;
import java.util.Map;
import java.util.Optional;

/**
 * 机场区域服务类 - 基于PostGIS的空间数据管理
 * 提供机场区域的配置管理、空间查询、冲突检测等功能
 */
@Service
@RequiredArgsConstructor
@Slf4j
public class AirportAreaService {

    private final AirportAreaRepository airportAreaRepository;
    private final GeometryFactory geometryFactory = new GeometryFactory();
    private final WKTReader wktReader = new WKTReader(geometryFactory);
    /**
     * 保存机场区域配置
     */
    @Transactional
    public AirportArea saveAirportArea(AirportArea airportArea) {
        try {
            AirportArea saved = airportAreaRepository.save(airportArea);
            log.info("保存机场区域: areaName={}, areaType={}, priority={}", 
                     saved.getName(), saved.getType(), saved.getPriority());
            return saved;
        } catch (Exception e) {
            log.error("保存机场区域失败: areaName={}", airportArea.getName(), e);
            throw new RuntimeException("保存机场区域失败", e);
        }
    }

    /**
     * 批量保存机场区域配置
     */
    @Transactional
    public List<AirportArea> saveAirportAreas(List<AirportArea> airportAreas) {
        try {
            List<AirportArea> saved = airportAreaRepository.saveAll(airportAreas);
            log.info("批量保存机场区域: 数量={}", saved.size());
            return saved;
        } catch (Exception e) {
            log.error("批量保存机场区域失败: 数量={}", airportAreas.size(), e);
            throw new RuntimeException("批量保存机场区域失败", e);
        }
    }

    /**
     * 创建机场区域
     */
    public AirportArea createAirportArea(String areaName, String areaType, String description,
                                        String geometryWkt, Integer priority, 
                                        Map<String, Object> restrictions) {
        try {
            Geometry geometry = wktReader.read(geometryWkt);
            geometry.setSRID(4326); // 设置WGS84坐标系

            AirportArea airportArea = new AirportArea();
            airportArea.setName(areaName);
            airportArea.setType(areaType);
            airportArea.setDescription(description);
            airportArea.setBoundary((Polygon) geometry);
            airportArea.setPriority(priority != null ? priority : 1);
            airportArea.setEnabled(true);

            return airportArea;
        } catch (ParseException e) {
            log.error("解析几何形状失败: geometryWkt={}", geometryWkt, e);
            throw new RuntimeException("无效的几何形状格式", e);
        } catch (Exception e) {
            log.error("创建机场区域失败: areaName={}", areaName, e);
            throw new RuntimeException("创建机场区域失败", e);
        }
    }

    /**
     * 创建矩形区域
     */
    public AirportArea createRectangularArea(String areaName, String areaType, String description,
                                            double minLon, double minLat, double maxLon, double maxLat,
                                            Integer priority, Map<String, Object> restrictions) {
        try {
            // 创建矩形多边形
            Coordinate[] coordinates = new Coordinate[]{
                new Coordinate(minLon, minLat),
                new Coordinate(maxLon, minLat),
                new Coordinate(maxLon, maxLat),
                new Coordinate(minLon, maxLat),
                new Coordinate(minLon, minLat) // 闭合多边形
            };
            
            Polygon polygon = geometryFactory.createPolygon(coordinates);
            polygon.setSRID(4326);

            AirportArea airportArea = new AirportArea();
            airportArea.setName(areaName);
            airportArea.setType(areaType);
            airportArea.setDescription(description);
            airportArea.setBoundary((Polygon) polygon);
            airportArea.setPriority(priority != null ? priority : 1);
            airportArea.setEnabled(true);

            return airportArea;
        } catch (Exception e) {
            log.error("创建矩形区域失败: areaName={}", areaName, e);
            throw new RuntimeException("创建矩形区域失败", e);
        }
    }

    /**
     * 根据区域名称获取区域配置
     */
    public Optional<AirportArea> getAreaByName(String areaName) {
        try {
            return airportAreaRepository.findByName(areaName);
        } catch (Exception e) {
            log.error("获取区域失败: areaName={}", areaName, e);
            return Optional.empty();
        }
    }

    /**
     * 根据区域ID获取区域配置
     */
    public Optional<AirportArea> getAreaByAreaId(String areaId) {
        try {
            return airportAreaRepository.findByAreaId(areaId);
        } catch (Exception e) {
            log.error("获取区域失败: areaId={}", areaId, e);
            return Optional.empty();
        }
    }

    /**
     * 根据区域类型获取所有活跃区域
     */
    public List<AirportArea> getActiveAreasByType(String areaType) {
        try {
            return airportAreaRepository.findActiveAreasByType(areaType);
        } catch (Exception e) {
            log.error("获取活跃区域失败: areaType={}", areaType, e);
            return List.of();
        }
    }

    /**
     * 空间查询：查找包含指定点的所有区域
     */
    public List<AirportArea> getAreasContainingPoint(double longitude, double latitude) {
        Point point = geometryFactory.createPoint(new Coordinate(longitude, latitude));
        point.setSRID(4326);

        try {
            return airportAreaRepository.findAreasContainingPoint(point);
        } catch (Exception e) {
            log.error("点包含查询失败: point=({}, {})", longitude, latitude, e);
            return List.of();
        }
    }

    /**
     * 空间查询：查找与指定几何形状相交的区域
     */
    public List<AirportArea> getAreasIntersectingGeometry(String geometryWkt) {
        try {
            Geometry geometry = wktReader.read(geometryWkt);
            geometry.setSRID(4326);
            return airportAreaRepository.findAreasIntersectingGeometry(geometry);
        } catch (ParseException e) {
            log.error("解析几何形状失败: geometryWkt={}", geometryWkt, e);
            return List.of();
        } catch (Exception e) {
            log.error("相交查询失败: geometryWkt={}", geometryWkt, e);
            return List.of();
        }
    }

    /**
     * 空间查询：查找指定距离范围内的区域
     */
    public List<AirportArea> getAreasWithinRadius(double longitude, double latitude, double radiusMeters) {
        Point centerPoint = geometryFactory.createPoint(new Coordinate(longitude, latitude));
        centerPoint.setSRID(4326);

        try {
            return airportAreaRepository.findAreasWithinRadius(centerPoint, radiusMeters);
        } catch (Exception e) {
            log.error("半径查询失败: center=({}, {}), radius={}m", longitude, latitude, radiusMeters, e);
            return List.of();
        }
    }

    /**
     * 查找最高优先级的包含指定点的区域
     */
    public Optional<AirportArea> getHighestPriorityAreaContainingPoint(double longitude, double latitude) {
        Point point = geometryFactory.createPoint(new Coordinate(longitude, latitude));
        point.setSRID(4326);

        try {
            return airportAreaRepository.findHighestPriorityAreaContainingPoint(point);
        } catch (Exception e) {
            log.error("最高优先级区域查询失败: point=({}, {})", longitude, latitude, e);
            return Optional.empty();
        }
    }

    /**
     * 检测区域重叠冲突
     */
    public List<AirportArea> detectAreaOverlaps(Long areaId, String geometryWkt) {
        try {
            Geometry geometry = wktReader.read(geometryWkt);
            geometry.setSRID(4326);
            return airportAreaRepository.findOverlappingAreas(geometry, areaId);
        } catch (ParseException e) {
            log.error("解析几何形状失败: geometryWkt={}", geometryWkt, e);
            return List.of();
        } catch (Exception e) {
            log.error("重叠检测失败: areaId={}, geometryWkt={}", areaId, geometryWkt, e);
            return List.of();
        }
    }

    /**
     * 根据优先级范围获取区域
     */
    public List<AirportArea> getAreasByPriorityRange(int minPriority, int maxPriority) {
        try {
            return airportAreaRepository.findAreasByPriorityRange(minPriority, maxPriority);
        } catch (Exception e) {
            log.error("优先级范围查询失败: 优先级范围=[{}, {}]", minPriority, maxPriority, e);
            return List.of();
        }
    }

    /**
     * 根据限制类型查找区域
     */
    public List<AirportArea> getAreasByRestrictionType(String restrictionType) {
        try {
            return airportAreaRepository.findAreasByRestrictionType(restrictionType);
        } catch (Exception e) {
            log.error("限制类型查询失败: restrictionType={}", restrictionType, e);
            return List.of();
        }
    }

    /**
     * 查找与车辆轨迹相交的所有区域
     */
    public List<AirportArea> getAreasIntersectingTrajectory(String trajectoryWkt) {
        try {
            return airportAreaRepository.findAreasIntersectingTrajectory(trajectoryWkt);
        } catch (Exception e) {
            log.error("轨迹相交查询失败: trajectoryWkt={}", trajectoryWkt, e);
            return List.of();
        }
    }

    /**
     * 查找距离指定点最近的N个区域
     */
    public List<AirportArea> getNearestAreas(double longitude, double latitude, int limit) {
        Point referencePoint = geometryFactory.createPoint(new Coordinate(longitude, latitude));
        referencePoint.setSRID(4326);

        try {
            return airportAreaRepository.findNearestAreas(referencePoint, limit);
        } catch (Exception e) {
            log.error("最近区域查询失败: reference=({}, {}), limit={}", longitude, latitude, limit, e);
            return List.of();
        }
    }

    /**
     * 根据区域编码查找区域
     */
    public Optional<AirportArea> findByAreaCode(String areaCode) {
        try {
            return airportAreaRepository.findByAreaId(areaCode);
        } catch (Exception e) {
            log.error("根据区域编码查找区域失败: areaCode={}", areaCode, e);
            return Optional.empty();
        }
    }

    /**
     * 查找包含指定点的所有区域
     */
    public List<AirportArea> findAreasContainingPoint(Point point) {
        try {
            return airportAreaRepository.findAreasContainingPoint(point);
        } catch (Exception e) {
            log.error("查找包含点的区域失败: point={}", point, e);
            return List.of();
        }
    }

    /**
     * 统计活跃区域数量（按类型分组）
     */
    public Map<String, Long> countActiveAreasByType() {
        try {
            List<Object[]> results = airportAreaRepository.countActiveAreasByType();
            return results.stream()
                .collect(java.util.stream.Collectors.toMap(
                    row -> (String) row[0],
                    row -> (Long) row[1]
                ));
        } catch (Exception e) {
            log.error("区域统计失败", e);
            return Map.of();
        }
    }

    /**
     * 更新区域激活状态
     */
    @Transactional
    public void updateAreaActiveStatus(String areaName, boolean isActive) {
        try {
            Optional<AirportArea> areaOpt = airportAreaRepository.findByName(areaName);
            if (areaOpt.isPresent()) {
                AirportArea area = areaOpt.get();
                area.setEnabled(isActive);
                airportAreaRepository.save(area);
                log.info("更新区域激活状态: areaName={}, isActive={}", areaName, isActive);
            } else {
                log.warn("区域不存在: areaName={}", areaName);
            }
        } catch (Exception e) {
            log.error("更新区域激活状态失败: areaName={}", areaName, e);
            throw new RuntimeException("更新区域激活状态失败", e);
        }
    }

    /**
     * 删除区域
     */
    @Transactional
    public void deleteArea(String areaName) {
        try {
            Optional<AirportArea> areaOpt = airportAreaRepository.findByName(areaName);
            if (areaOpt.isPresent()) {
                airportAreaRepository.delete(areaOpt.get());
                log.info("删除区域: areaName={}", areaName);
            } else {
                log.warn("区域不存在: areaName={}", areaName);
            }
        } catch (Exception e) {
            log.error("删除区域失败: areaName={}", areaName, e);
            throw new RuntimeException("删除区域失败", e);
        }
    }

    /**
     * 验证区域几何形状的有效性
     */
    public boolean isValidGeometry(String geometryWkt) {
        try {
            Geometry geometry = wktReader.read(geometryWkt);
            return geometry.isValid();
        } catch (ParseException e) {
            log.warn("无效的几何形状格式: {}", geometryWkt, e);
            return false;
        } catch (Exception e) {
            log.warn("几何形状验证失败: {}", geometryWkt, e);
            return false;
        }
    }

    /**
     * 获取区域的边界框
     */
    public Optional<Geometry> getAreaBoundingBox(Long areaId) {
        try {
            return airportAreaRepository.getAreaBoundingBox(areaId);
        } catch (Exception e) {
            log.error("获取区域边界框失败: areaId={}", areaId, e);
            return Optional.empty();
        }
    }

    /**
     * 获取所有活跃区域
     */
    public List<AirportArea> getAllActiveAreas() {
        try {
            return airportAreaRepository.findAll()
                .stream()
                .filter(AirportArea::getEnabled)
                .toList();
        } catch (Exception e) {
            log.error("获取所有活跃区域失败", e);
            return List.of();
        }
    }
} 