using LY.App.Model;
using NetTopologySuite.Features;
using NetTopologySuite.Geometries;
using NetTopologySuite.IO;
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
namespace LY.App.Common
{
    public class GeoJsonHelper
    {
        /// 
        /// 格式为json字符串
        /// 
        /// 
        /// 
        public static string ConvertJsonString(string str)
        {
            try
            {
                //格式化json字符串
                JsonSerializer serializer = new JsonSerializer();
                TextReader tr = new StringReader(str);
                JsonTextReader jtr = new JsonTextReader(tr);
                object obj = serializer.Deserialize(jtr);
                if (obj != null)
                {
                    StringWriter textWriter = new StringWriter();
                    JsonTextWriter jsonWriter = new JsonTextWriter(textWriter)
                    {
                        Formatting = Formatting.Indented,
                        Indentation = 4,
                        IndentChar = ' '
                    };
                    serializer.Serialize(jsonWriter, obj);
                    return textWriter.ToString();
                }
                else
                {
                    return str;
                }
            }
            catch (Exception)
            {
            }
            return str;
        }
        /// 
        /// 转换为geojson格式字符串
        /// 
        /// 
        /// 
        public static string GetGeoJson(object? value)
        {
            if (value == null)
                return "";
            var serializer = GeoJsonSerializer.Create();
            using (var sw = new System.IO.StringWriter())
            {
                serializer.Serialize(sw, value);
                return sw.ToString();
            }
        }
        /// 
        /// 将坐标转换为点
        /// 
        /// 经度
        /// 纬度
        /// 
        public static NetTopologySuite.Geometries.Point ConvertToPoint(double x, double y)
        {
            return new NetTopologySuite.Geometries.Point(x, y);
        }
        public static object? GetDynamicFeature(Geometry geometry, IDictionary attributes)
        {
            var f = GetGeoFeature(geometry, attributes);
            var geoJson = GetGeoJson(f);
            return geoJson;
            // return JsonConvert.DeserializeObject(geoJson);
        }
        /// 
        /// 获取集合中能够组成多面的几何数据
        /// 
        /// 
        /// 
        public static List GetGeoMultiPolygon(FeatureCollection features)
        {
            var result = new List();
            if (features == null)
                return result;
            foreach (var feature in features)
            {
                if (feature.Geometry is MultiPolygon)
                {
                    result.Add(feature.Geometry as MultiPolygon);
                }
                else if (feature.Geometry is Polygon)
                {
                    result.Add(new MultiPolygon(new Polygon[] { feature.Geometry as Polygon }));
                }
                else if (feature.Geometry is LineString)
                {
                    var line = (LineString)feature.Geometry;
                    if (line.IsRing)
                    {
                        result.Add(new MultiPolygon(new Polygon[] { new Polygon(new LinearRing(line.Coordinates)) }));
                    }
                }
            }
            return result;
        }
        /// 
        /// 获取集合中能够组成多线的几何数据
        /// 
        /// 
        /// 
        public static List GetGeoMultiLineString(FeatureCollection features)
        {
            var result = new List();
            if (features == null)
                return result;
            foreach (var feature in features)
            {
                if (feature.Geometry is MultiLineString)
                {
                    result.Add(feature.Geometry as MultiLineString);
                }
                else if (feature.Geometry is LineString)
                {
                    result.Add(new MultiLineString(new LineString[] { feature.Geometry as LineString }));
                }
                else if (feature.Geometry is MultiPoint)
                {
                    var mp = (MultiPoint)feature.Geometry;
                    if (mp.Count() > 1)
                    {
                        result.Add(new MultiLineString(new LineString[] { new LineString(mp.Coordinates) }));
                    }
                }
            }
            return result;
        }
        /// 
        /// 将geojson转为FeatureCollection,
        /// 原json支持点、线面等
        /// 
        /// 
        /// 
        public static FeatureCollection? GetGeoFeatureCollectionBuild(string geoJson)
        {
            if (string.IsNullOrWhiteSpace(geoJson)) return null;
            try
            {
                var jObj = JObject.Parse(geoJson);
                if (jObj != null)
                {
                    if (jObj.TryGetValue("type", out var jToken))
                    {
                        if (jToken != null)
                        {
                            if (string.Compare(jToken.ToString(), "FeatureCollection") == 0)
                            {
                                return GetGeoFeatureCollection(geoJson);
                            }
                            else
                            {
                                var f = GetGeoFeatureBuild(geoJson);
                                if (f != null)
                                {
                                    var result = new FeatureCollection();
                                    result.Add(f);
                                    return result;
                                }
                            }
                        }
                    }
                }
            }
            catch (Exception)
            {
                throw new Exception("geojson无效");
            }
            return null;
        }
        public static Feature? GetGeoFeatureBuild(string geoJson)
        {
            var jObj = JObject.Parse(geoJson);
            if (jObj != null)
            {
                //先判断type  
                if (jObj.TryGetValue("type", out var jToken))
                {
                    if (jToken != null)
                    {
                        if (string.Compare(jToken.ToString(), "Feature") == 0)
                        {
                            return GetGeoFeature(geoJson);
                        }
                        Geometry? geometry = null;
                        if (string.Compare(jToken.ToString(), "Point") == 0)
                        {
                            geometry = GetGeoPoint(geoJson);
                        }
                        if (string.Compare(jToken.ToString(), "MultiPoint") == 0)
                        {
                            geometry = GetGeoMultiPoint(geoJson);
                        }
                        if (string.Compare(jToken.ToString(), "LineString") == 0)
                        {
                            geometry = GetGeoLineString(geoJson);
                        }
                        if (string.Compare(jToken.ToString(), "MultiLineString") == 0)
                        {
                            geometry = GetGeoMultiLineString(geoJson);
                        }
                        if (string.Compare(jToken.ToString(), "Polygon") == 0)
                        {
                            geometry = GetGeoPolygon(geoJson);
                        }
                        if (string.Compare(jToken.ToString(), "MultiPolygon") == 0)
                        {
                            geometry = GetGeoMultiPolygon(geoJson);
                        }
                        if (geometry != null)
                            return new Feature(geometry, new AttributesTable());
                    }
                }
            }
            return null;
        }
        public static Feature? GetGeoFeature(Geometry geometry, IDictionary attributes)
        {
            AttributesTable attributesTable = new AttributesTable();
            foreach (var item in attributes)
            {
                attributesTable.Add(item.Key, item.Value);
            }
            var result = new Feature(geometry, attributesTable);
            return result;
        }
        public static Feature? GetGeoFeature(string geoJson)
        {
            var serializer = GeoJsonSerializer.Create();
            using (var stringReader = new StringReader(geoJson))
            using (var jsonReader = new JsonTextReader(stringReader))
            {
                return serializer.Deserialize(jsonReader);
            }
        }
        public static FeatureCollection? GetGeoFeatureCollection(string geoJson)
        {
            var serializer = GeoJsonSerializer.Create();
            using (var stringReader = new StringReader(geoJson))
            using (var jsonReader = new JsonTextReader(stringReader))
            {
                return serializer.Deserialize(jsonReader);
            }
        }
        public static NetTopologySuite.Geometries.Point? GetGeoPoint(string geoJson)
        {
            var jObj = JObject.Parse(geoJson);
            if (jObj != null)
            {
                //先判断type  
                if (jObj.TryGetValue("type", out var jToken))
                {
                    if (jToken != null)
                    {
                        if (string.Compare(jToken.ToString(), "Feature") == 0)
                        {
                            var f = GetGeoFeature(geoJson);
                            if (f.Geometry is Point)
                                return f.Geometry as NetTopologySuite.Geometries.Point;
                        }
                        else
                        {
                            var serializer = GeoJsonSerializer.Create();
                            using (var stringReader = new StringReader(geoJson))
                            using (var jsonReader = new JsonTextReader(stringReader))
                            {
                                return serializer.Deserialize(jsonReader);
                            }
                        }
                    }
                }
            }
            return null;
        }
        public static NetTopologySuite.Geometries.MultiPoint? GetGeoMultiPoint(string geoJson)
        {
            var serializer = GeoJsonSerializer.Create();
            using (var stringReader = new StringReader(geoJson))
            using (var jsonReader = new JsonTextReader(stringReader))
            {
                return serializer.Deserialize(jsonReader);
            }
        }
        public static NetTopologySuite.Geometries.LineString? GetGeoLineString(string geoJson)
        {
            var serializer = GeoJsonSerializer.Create();
            using (var stringReader = new StringReader(geoJson))
            using (var jsonReader = new JsonTextReader(stringReader))
            {
                return serializer.Deserialize(jsonReader);
            }
        }
        public static NetTopologySuite.Geometries.MultiLineString? GetGeoMultiLineString(string geoJson)
        {
            var serializer = GeoJsonSerializer.Create();
            using (var stringReader = new StringReader(geoJson))
            using (var jsonReader = new JsonTextReader(stringReader))
            {
                return serializer.Deserialize(jsonReader);
            }
        }
        public static NetTopologySuite.Geometries.Polygon? GetGeoPolygon(string geoJson)
        {
            var serializer = GeoJsonSerializer.Create();
            using (var stringReader = new StringReader(geoJson))
            using (var jsonReader = new JsonTextReader(stringReader))
            {
                return serializer.Deserialize(jsonReader);
            }
        }
        public static NetTopologySuite.Geometries.MultiPolygon? GetGeoMultiPolygon(string geoJson)
        {
            var serializer = GeoJsonSerializer.Create();
            using (var stringReader = new StringReader(geoJson))
            using (var jsonReader = new JsonTextReader(stringReader))
            {
                return serializer.Deserialize(jsonReader);
            }
        }
        public static bool TryGetGeomWKTFromGeoJson(string? geoJson, out MultiPolygon? geometry)
        {
            geometry = null;
            try
            {
                if (!string.IsNullOrWhiteSpace(geoJson))
                {
                    var features = GeoJsonHelper.GetGeoFeatureCollectionBuild(geoJson);
                    var multPolygons = GeoJsonHelper.GetGeoMultiPolygon(features);
                    if (multPolygons?.Count > 0)
                    {
                        geometry = multPolygons[0];
                        geometry.SRID = 4326;
                        return true;
                    }
                }
            }
            catch
            {
            }
            return false;
        }
        public static Geometry FromWKT(string wktData)
        {
            WKTReader reader = new WKTReader();
            return reader.Read(wktData);
        }
        public static Geometry FromWKB(byte[] wkbData)
        {
            WKBReader reader = new WKBReader();
            return reader.Read(wkbData);
        }
        public static Polygon Transfer2CoordinateByCoords(List Coords)
        {
            if (Coords.Any())
            {
                var list = Coords.Select(s => s.X + "" + s.Y).ToList();
                var content = $"POLYGON(({string.Join(",", list)}))";
                WKTReader wktReader = new WKTReader();
                Polygon polygon = wktReader.Read(content) as Polygon;
                return polygon;
            }
            return null;
        }
        #region 坐标相关方法
        private static GeometryFactory _gf = NetTopologySuite.NtsGeometryServices.Instance.CreateGeometryFactory(4326);
        public static bool IsWithin(BasePoint pnt, BasePoint[] polygon)
        {
            if (IsValidPolygon(polygon))
            {
                var point = CreatPoint(pnt);
                var region = CreatePolygon(polygon);
                return point.Within(region);
            }
            return false;
        }
        /// 
        /// 判断点是否在多边形内
        /// 
        /// 
        /// 
        /// 
        public static bool isWithin(BasePoint pnt, MultiPolygon multiPolygon)
        {
            var point = CreatPoint(pnt);
            return point.Within(multiPolygon);
        }
        /// 
        /// 基本判断点数据是否有效转为面
        /// 
        /// 
        /// 
        public static bool IsValidPolygon(BasePoint[] polygon)
        {
            if (polygon?.Count() >= 4)
            {
                //polygon.Distinct();//重复点?
                return polygon[0].Equal(polygon[polygon.Count() - 1]);
            }
            return false;
        }
        /// 
        /// 基本判断点数据是否有效转为线
        /// 
        /// 
        /// 
        public static bool IsValidLineString(BasePoint[] polygon)
        {
            if (polygon?.Count() >= 2)
            {
                //polygon.Distinct();//重复点?
                return true;
            }
            return false;
        }
        /// 
        /// 创建点
        /// 
        /// 
        /// 
        public static Point CreatPoint(BasePoint pnt)
        {
            return _gf.CreatePoint(GetCoordinate(pnt));
        }
        /// 
        /// 创建点
        /// 
        /// 
        /// 
        public static Point CreatPoint(double x, double y)
        {
            return _gf.CreatePoint(GetCoordinate(x, y));
        }
        /// 
        /// 创建线
        /// 
        /// 
        /// 
        public static LineString CreateLineString(BasePoint[] points)
        {
            return _gf.CreateLineString(GetCoordinate(points));
        }
        /// 
        /// 创建面
        /// 
        /// 
        /// 
        public static Polygon CreatePolygon(BasePoint[] polygon)
        {
            return _gf.CreatePolygon(GetCoordinate(polygon));
        }
        /// 
        /// 点转换到坐标
        /// 
        /// 
        /// 
        public static NetTopologySuite.Geometries.Coordinate GetCoordinate(BasePoint pnt)
        {
            return new NetTopologySuite.Geometries.Coordinate(pnt.X, pnt.Y);
        }
        /// 
        /// 点转换到坐标
        /// 
        /// 
        /// 
        public static NetTopologySuite.Geometries.Coordinate GetCoordinate(double x, double y)
        {
            return new NetTopologySuite.Geometries.Coordinate(x, y);
        }
        /// 
        /// 点组转换坐标组
        /// 
        /// 
        /// 
        public static NetTopologySuite.Geometries.Coordinate[] GetCoordinate(BasePoint[] polygon)
        {
            List coordinates = new List();
            foreach (var item in polygon)
            {
                coordinates.Add(GetCoordinate(item));
            }
            return coordinates.ToArray();
        }
        public static Geometry CreateCircleMercator(double x, double y, double radius)
        {
            var geometryFactory = new GeometryFactory();
            var wbp = CoordConvert.WGS84ToMercator(x, y);
            var point1 = geometryFactory.CreatePoint(new NetTopologySuite.Geometries.Coordinate(wbp.X, wbp.Y));
            var geo = point1.Buffer(radius, 80);
            //var geo1 = point1.Buffer(radius);
            return geo;
        }
        /// 
        /// 创建圆形
        /// 
        /// 
        /// 
        /// 
        /// 
        public static Geometry CreateCircle(double x, double y, double radius, int pnts = 100)
        {
            var geo1 = CreateCircleMercator(x, y, radius);
            var coordinates = geo1.Coordinates;
            List points = new List();
            foreach (var item in coordinates)
            {
                var wgs84 = CoordConvert.MercatorToWGS84(item.X, item.Y);
                points.Add(new BasePoint(wgs84.Lon, wgs84.Lat, 0));
            }
            return CreatePolygon(points.ToArray());
        }
        public static double CalculateCircleAreaKmUnit(double x, double y, double radius)
        {
            if (x > 0 && y > 0 && radius > 0)
            {
                var area11 = CalculateCircleArea(x, y, radius);
                return Math.Round(area11 / 1000000, 5);
            }
            return 0;
        }
        public static double CalculateCircleArea(double x, double y, double radius)
        {
            if (x > 0 && y > 0 && radius > 0)
            {
                var geo1 = CreateCircleMercator(x, y, radius);
                return geo1.Area;
            }
            return 0;
        }
        /// 
        /// 计算合并后的总面积
        /// 
        /// 
        /// 
        public static double CalculateAreaMercator(Geometry[] geometries)
        {
            //将多个 Geometry 合并成一个 Geometry,避免交集重复计算
            var unionedGeometry = _gf.BuildGeometry(geometries).Union();
            string geojson = GetGeoJson(unionedGeometry);
            var area = unionedGeometry.Area;
            // 计算合并后的总面积
            return area;
        }
        ///// 
        ///// 计算合并后的总面积
        ///// 
        ///// 
        ///// 
        //public static double CalculateArea(Geometry[] geometries)
        //{
        //    //将多个 Geometry 合并成一个 Geometry,避免交集重复计算
        //    var unionedGeometry = _gf.BuildGeometry(geometries).Union();
        //    string geojson = GetGeoJson(unionedGeometry);
        //    var area = Math.Round(unionedGeometry.ProjectTo(2855).Area / 1000000.0, 5);
        //    // 计算合并后的总面积
        //    return area;
        //}
        #endregion
    }
}