package com.ruoyi.common.utils.map;

import com.alibaba.fastjson2.JSONArray;
import lombok.experimental.UtilityClass;
import lombok.extern.slf4j.Slf4j;
import org.locationtech.jts.geom.Coordinate;
import org.locationtech.jts.geom.Geometry;
import org.locationtech.jts.geom.GeometryFactory;
import org.locationtech.jts.geom.Point;
import org.locationtech.jts.io.WKTReader;
import org.locationtech.jts.io.WKTWriter;

import java.util.Collection;


/**
 * GeoUtils.
 *
 * @author qiuzhenzhao
 * @date 2024/04/19
 */
@Slf4j
@UtilityClass
public class GeoUtils {
    private static final GeometryFactory GEOMETRY_FACTORY = new GeometryFactory();
    private static final String AUTO = "AUTO:42001,%s,%s";
    private static final WKTWriter WKT_WRITER = new WKTWriter();
    private static final WKTReader WKT_READER = new WKTReader();
//    private static final GeometryJSON GEOMETRY_JSON = new GeometryJSON(15);
//    private final static FeatureJSON FEATURE_JSON = new FeatureJSON(GEOMETRY_JSON);

    private static final double EARTH_RADIUS = 6371000; // 地球半径，单位：米

    /**
     * 合并多边形  Geographic
     * */
    public Geometry union(Collection<Geometry> geometries) {
        return GEOMETRY_FACTORY.buildGeometry(geometries).union();
    }

    /**
     * 判断经纬度是否在多边形区域内
     * */
    public boolean isInCircle(String longitude, String latitude,Geometry polygon){
        /**创建一个点*/
        GeometryFactory geometryFactory = new GeometryFactory();
        Coordinate coordinate = new Coordinate(Double.parseDouble(longitude), Double.parseDouble(latitude));
        Point point = geometryFactory.createPoint(coordinate);
        return polygon.contains(point);
    }

    /**
     * 判断一个点是否在一个圆形区域内（考虑误差距离）
     * */
    public static boolean isInPolygonWithTolerance(String longitude, String latitude, Geometry polygon, double tolerance) {
        double lon = Double.parseDouble(longitude);
        double lat = Double.parseDouble(latitude);

        GeometryFactory geometryFactory = new GeometryFactory();
        Coordinate coordinate = new Coordinate(lon, lat);
        Point point = geometryFactory.createPoint(coordinate);

        if (polygon.contains(point)) {
            return true;
        } else {
            // 获取多边形的外边界
            Coordinate[] coordinates = polygon.getCoordinates();
            for (Coordinate coord : coordinates) {
                double distance = calculateDistance(lat, lon, coord.y, coord.x);
                log.info("距离----distance:{}",distance);
                if (distance <= tolerance) {
                    return true;
                }
            }
            return false;
        }
    }

    // 将角度转换为弧度
    private static double deg2rad(double deg) {
        return deg * (Math.PI / 180);
    }

    // 使用 Haversine 公式计算两点间的距离
    public static double calculateDistance(double lat1, double lon1, double lat2, double lon2) {
        double dLat = deg2rad(lat2 - lat1);
        double dLon = deg2rad(lon1 - lon2); // 修正此处为 (lon1 - lon2)
        double a = Math.sin(dLat / 2) * Math.sin(dLat / 2) +
                Math.cos(deg2rad(lat1)) * Math.cos(deg2rad(lat2)) *
                        Math.sin(dLon / 2) * Math.sin(dLon / 2);
        double c = 2 * Math.atan2(Math.sqrt(a), Math.sqrt(1 - a));
        return EARTH_RADIUS * c;
    }

    public static double[][] parseJsonTrack(String jsonString) {
        JSONArray jsonArray = JSONArray.parseArray(jsonString);
        double[][] track = new double[jsonArray.size()][2];
        for (int i = 0; i < jsonArray.size(); i++) {
            JSONArray coord = jsonArray.getJSONArray(i);
            track[i][0] = coord.getDouble(0);
            track[i][1] = coord.getDouble(1);
        }
        return track;
    }


    /**
     * 计算一段轨迹的总距离
     * */
    public static double calculateTotalDistance(double[][] track) {
        double totalDistance = 0;
        for (int i = 0; i < track.length - 1; i++) {
            totalDistance += haversineDistance(track[i], track[i + 1]);
        }
        return totalDistance;
    }

    /**
     * 计算两点之间的距离
     * */
    public static double haversineDistance(double[] coord1, double[] coord2) {
        double lat1 = deg2rad(coord1[1]);
        double lon1 = deg2rad(coord1[0]);
        double lat2 = deg2rad(coord2[1]);
        double lon2 = deg2rad(coord2[0]);

        double dLat = lat2 - lat1;
        double dLon = lon2 - lon1;

        double a = Math.sin(dLat / 2) * Math.sin(dLat / 2) +
                Math.cos(lat1) * Math.cos(lat2) *
                        Math.sin(dLon / 2) * Math.sin(dLon / 2);

        double c = 2 * Math.atan2(Math.sqrt(a), Math.sqrt(1 - a));

        return EARTH_RADIUS * c; // 距离（米）
    }
}
