using System;
using System.Collections.Generic;
using System.Drawing.Drawing2D;
using System.Linq;
using System.Runtime.Serialization.Formatters.Binary;
using System.Runtime.Serialization;
using System.Text;
using System.Threading.Tasks;
using CanFly.Canvas.Helper;
using Newtonsoft.Json;
using System.Diagnostics;
using System.Net.NetworkInformation;
using System.Drawing;


namespace CanFly.Canvas.Shape
{
    [Serializable]
    public class FlyShape
    {
        private const float DFT_VTX_EPSILON = 4f;
        private float _epsilon = DFT_VTX_EPSILON;

        public float LineWidth { get; set; } = 2f;


        #region Shape颜色

        #region drawing
        public Color line_color = Color.FromArgb(128, 0, 255, 0);
        public Color fill_color = Color.FromArgb(64, 0, 0, 0);
        public Color vertex_fill_color = Color.FromArgb(255, 0, 255, 0);
        #endregion

        #region selecting / hovering
        public Color select_line_color = Color.FromArgb(255, 255, 255, 255);
        public Color select_fill_color = Color.FromArgb(64, 0, 255, 0);
        public Color hvertex_fill_color = Color.FromArgb(255, 255, 255, 255);
        #endregion

        #endregion


        private PointTypeEnum point_type = PointTypeEnum.ROUND;
        private float point_size = 8.0f;

        private float _scale = 1.0f;
        private float scale
        {
            get
            {
                return _scale;
            }
            set
            {
                _scale = value;
            }
        }




        private ShapeTypeEnum _shape_type;
        private Matrix _matrix = new Matrix();




        public ShapeTypeEnum ShapeType
        {
            get => _shape_type;
            set { _shape_type = value; }
        }


        public string label = "";
        public int? group_id = null;
        private List<PointF> _points
        {
            get;
            set;
        } = new List<PointF>();

        public List<PointF> Points
        {
            get { return _points; }
            set
            {
                this._points = value;
            }
        }


        private List<PointF> _pointsRaw = new List<PointF>();


        /// <summary>
        /// 辅助节点
        /// </summary>
        public List<PointF> GuidePoints = new List<PointF>();

        public float _currentRotateAngle;
        private bool _isRotating = false;


        public List<int> point_labels = new List<int>();


        private ShapeTypeEnum _shape_type_raw;


        /// <summary>
        /// 是否填充多边形 使用:select_fill_color 或 fill_color 填充 
        /// </summary>
        public bool fill = false;


        public bool Selected { get; set; } = false;
        public object? flags;
        public string description = "";
        private List<object> other_data = new List<object>();


        private int _highlightIndex = -1;
        private HighlightModeEnum _highlightMode = HighlightModeEnum.NEAR_VERTEX;


        private Dictionary<HighlightModeEnum, HighlightSetting> _highlightSettings = new Dictionary<HighlightModeEnum, HighlightSetting>()
        {
            { HighlightModeEnum.NEAR_VERTEX,new HighlightSetting(4,PointTypeEnum.ROUND)},
            { HighlightModeEnum.MOVE_VERTEX,new HighlightSetting(1.5f,PointTypeEnum.SQUARE)},
        };


        private bool _closed = false;
        private Color _vertex_fill_color;


        /// <summary>
        /// 当图形是Line时,是否绘制辅助矩形框
        /// </summary>
        public bool IsDrawLineVirtualRect { get; set; } = false;
        /// <summary>
        /// 画Line时辅助矩形的宽度
        /// </summary>
        public float LineVirtualRectWidth = 40;
        public PointF[] LineVirtualRectPoints = new PointF[4];


        public FlyShape()
        {

        }



        private PointF ScalePoint(PointF point)
        {
            return point;

            //return new PointF(
            //    (float)(point.X * scale),
            //    (float)(point.Y * scale));
        }




        public void Close()
        {
            this._closed = true;
        }


        public void AddPoint(PointF point, int label = 1)
        {
            if (_points != null && _points.Count > 0 && point.Equals(_points.ElementAt(0)))
            {
                Close();
            }
            else
            {
                if (_points.Count > 0 && this[-1].Equals(point))
                {
                    return;
                }
                _points.Add(point);
                point_labels.Add(label);
            }
        }



        public bool CanAddPoint()
        {
            return ShapeType == ShapeTypeEnum.Polygon
                || ShapeType == ShapeTypeEnum.LineStrip;
        }



        public PointF? PopPoint()
        {
            if (_points != null && _points.Count > 0)
            {
                if (point_labels != null && point_labels.Count > 0)
                {
                    point_labels.RemoveAt(point_labels.Count - 1);
                }

                PointF lastPoint = _points[_points.Count - 1];
                _points.RemoveAt(_points.Count - 1);
                return lastPoint;
            }
            return null;

        }



        public void InsertPoint(int i, PointF point, int label = 1)
        {
            _points.Insert(i, point);
            point_labels.Insert(i, label);
        }


        public void RemovePoint(int i)
        {
            if (!CanAddPoint())
            {
                return;
            }

            if (ShapeType == ShapeTypeEnum.Polygon && _points.Count <= 3)
            {
                return;
            }
            else if (ShapeType == ShapeTypeEnum.LineStrip && _points.Count <= 2)
            {
                return;
            }


            _points.RemoveAt(_points.Count - 1);
            point_labels.RemoveAt(point_labels.Count - 1);
        }



        public bool IsClosed() => _closed;


        public void SetOpen() { _closed = false; }


        #region 矩形辅助函数

        /// <summary>
        /// 矩形模式下,选中的点索引
        /// </summary>
        [JsonIgnore]
        private int _rectSelectedVertex = -1;
        [JsonIgnore]
        private PointF _rectSelectedMoveVertex;
        [JsonIgnore]
        private PointF _rectCenterPoint;

        [JsonIgnore]
        private bool isVertexMoving;

        /// <summary>
        /// 正在移动节点
        /// </summary>
        [JsonIgnore]
        public bool IsVertexMoving
        {
            get
            {
                return isVertexMoving;
            }
            internal set
            {
                //float centerX = (_points[0].X + _points[2].X) / 2f;
                //float centerY = (_points[0].Y + _points[2].Y) / 2f;
                //_rectCenterVertex = new PointF(centerX, centerY);
                isVertexMoving = value;
            }
        }
        //private PointF[] TransformPoints(List<PointF> points, PointF center, float angle)
        //{
        //    PointF[] ptsArray = points.ToArray();
        //    using (Matrix matrix = new Matrix())
        //    {
        //        matrix.RotateAt(angle, center);
        //        matrix.TransformPoints(ptsArray);
        //    }
        //    return ptsArray;
        //}
        //GraphicsPath vrtx_path = new GraphicsPath();

        #endregion


        public void Paint(Graphics painter)
        {
            if (_points == null || _points.Count == 0)
            {
                return;
            }

            Color color = Selected ? select_line_color : line_color;
            using Pen pen = new Pen(color, LineWidth);

            // Create paths
            GraphicsPath line_path = new GraphicsPath();
            GraphicsPath vrtx_path = new GraphicsPath();
            GraphicsPath guide_vrtx_path = new GraphicsPath();

            switch (ShapeType)
            {
                //case ShapeTypeEnum.Rectangle:
                //    {
                //        if (_points.Count == 2)
                //        {
                //            float centerX = (_points[0].X + _points[1].X) / 2f;
                //            float centerY = (_points[0].Y + _points[1].Y) / 2f;
                //            _rectCenterPoint = new PointF(centerX, centerY);


                //            line_path.StartFigure();

                //            if (_points[1].X < _points[0].X)
                //            {
                //                _points[1] = new PointF(_points[0].X + LineWidth / 2f, _points[1].Y);
                //            }
                //            if (_points[1].Y < _points[0].Y)
                //            {
                //                _points[1] = new PointF(_points[1].X, _points[0].Y + LineWidth / 2f);
                //            }

                //            //float x = Math.Min(_points[0].X, _points[1].X);
                //            //float y = Math.Min(_points[0].Y, _points[1].Y);

                //            float w = Math.Abs(ScalePoint(_points[1]).X - ScalePoint(_points[0]).X);
                //            float h = Math.Abs(ScalePoint(_points[1]).Y - ScalePoint(_points[0]).Y);

                //            RectangleF drawRect = new(new PointF(_points[0].X, _points[0].Y), new SizeF(w, h));

                //            bool bRotated = false;
                //            NomalizeRotateAngle();

                //            Matrix oMatrix = null;

                //            if (_currentRotateAngle > 0)
                //            {
                //                // Create rotation matrix
                //                oMatrix = new Matrix();
                //                oMatrix.RotateAt(_currentRotateAngle, _rectCenterPoint, MatrixOrder.Append);
                //                painter.Transform = oMatrix;
                //                bRotated = true;
                //            }
                //            //Store rectangle region
                //            //Region _drawRectRegion = new Region(drawRect);
                //            if (oMatrix != null)
                //                line_path.Transform(oMatrix);


                //            line_path.AddRectangle(drawRect);


                //            //  Reset transform
                //            if (bRotated)
                //            {
                //                bRotated = false;
                //                painter.ResetTransform();
                //            }
                //            //_matrix.Reset();
                //            //_matrix.RotateAt(_currentRotateAngle, new PointF(
                //            //    (_points[0].X + _points[1].X) / 2,
                //            //    (_points[0].Y + _points[1].Y) / 2));
                //            //line_path.Transform(_matrix);


                //            //line_path.AddPolygon(_pointsRaw.ToArray());

                //        }

                //        if (_regionVertex.Length != _points.Count)
                //        {
                //            _regionVertex = new Region[_points.Count];
                //        }


                //        for (int i = 0; i < _points.Count; i++)
                //        {
                //            DrawVertex(vrtx_path, i);
                //        }

                //        vrtx_path.Transform(_matrix);

                //    }

                //    break;
                case ShapeTypeEnum.Rectangle:
                    {
                        if (_points.Count == 2)
                        {
                            float centerX = (_points[0].X + _points[1].X) / 2f;
                            float centerY = (_points[0].Y + _points[1].Y) / 2f;
                            _rectCenterPoint = new PointF(centerX, centerY);

                            line_path.StartFigure();

                            if (_points[1].X < _points[0].X)
                            {
                                _points[1] = new PointF(_points[0].X + LineWidth / 2f, _points[1].Y);
                            }
                            if (_points[1].Y < _points[0].Y)
                            {
                                _points[1] = new PointF(_points[1].X, _points[0].Y + LineWidth / 2f);
                            }

                            float w = Math.Abs(ScalePoint(_points[1]).X - ScalePoint(_points[0]).X);
                            float h = Math.Abs(ScalePoint(_points[1]).Y - ScalePoint(_points[0]).Y);

                            RectangleF drawRect = new(new PointF(_points[0].X, _points[0].Y), new SizeF(w, h));

                            line_path.AddRectangle(drawRect);

                            _matrix.Reset();
                            _matrix.RotateAt(_currentRotateAngle, _rectCenterPoint); // 使用更新后的旋转角度
                            line_path.Transform(_matrix);
                        }

                        if (_regionVertex.Length != _points.Count)
                        {
                            _regionVertex = new Region[_points.Count];
                        }

                        for (int i = 0; i < _points.Count; i++)
                        {
                            DrawVertex1(vrtx_path, i);
                        }

                        vrtx_path.Transform(_matrix);


                    }
                    break;
                case ShapeTypeEnum.Circle:
                    {
                        if (_points.Count == 2)
                        {
                            float radius = PointHelper.Distance(ScalePoint(_points[0]), ScalePoint(_points[1]));
                            line_path.AddEllipse(
                                ScalePoint(_points[0]).X - radius,
                                ScalePoint(_points[0]).Y - radius,
                                radius * 2,
                                radius * 2);
                        }
                        for (int i = 0; i < _points.Count; i++)
                        {
                            DrawVertex(vrtx_path, i);
                        }
                    }
                    break;

                case ShapeTypeEnum.LineStrip:
                    {
                        line_path.StartFigure();
                        line_path.AddLine(ScalePoint(_points[0]), ScalePoint(_points[0]));

                        for (int i = 0; i < _points.Count; i++)
                        {
                            PointF pt = _points[i];
                            line_path.AddLine(ScalePoint(pt), ScalePoint(pt));
                            DrawVertex(vrtx_path, i);
                        }
                    }
                    break;

                case ShapeTypeEnum.Line:
                    {
                        // 添加框线到路径
                        var tmpPoints = _points.Select(p => ScalePoint(p)).ToList();
                        line_path.AddLines(tmpPoints.ToArray());

                        if (IsDrawLineVirtualRect && tmpPoints.Count == 2)
                        {
                            var center = new PointF((tmpPoints[0].X + tmpPoints[1].X) / 2,
                                (tmpPoints[0].Y + tmpPoints[1].Y) / 2);

                            // 计算两点之间的角度
                            float dx = tmpPoints[1].X - tmpPoints[0].X;
                            float dy = tmpPoints[1].Y - tmpPoints[0].Y;
                            float distance = PointHelper.Distance(tmpPoints[0], tmpPoints[1]);
                            double angle = Math.Atan2(dy, dx) * (180.0 / Math.PI); // 转换为度数

                            float l = center.X - distance / 2;
                            float t = center.Y - LineVirtualRectWidth / 2;
                            float r = center.X + distance / 2;
                            float b = center.Y + LineVirtualRectWidth / 2;

                            PointF ptLT = new PointF(l, t);
                            PointF ptRT = new PointF(r, t);
                            PointF ptRB = new PointF(r, b);
                            PointF ptLB = new PointF(l, b);
#if false
                            RectangleF rect = new RectangleF(ptLT, new SizeF(distance, LineVirtualRectWidth));

                            GraphicsPath rectPath = new GraphicsPath();
                            rectPath.AddRectangle(rect);

                            //// 设置矩阵以进行旋转和位移
                            Matrix matrix = new Matrix();
                            matrix.RotateAt((float)angle, center); // 旋转

                            // 应用变换
                            rectPath.Transform(matrix);
                            // 画框线
                            painter.DrawPath(pen, rectPath);
#else
                            RectangleF rect = new RectangleF(ptLT, new SizeF(distance, LineVirtualRectWidth));

                            LineVirtualRectPoints = new PointF[4] {
                                ptLT,ptRT,ptRB,ptLB
                            };

                            //// 设置矩阵以进行旋转和位移
                            Matrix matrix = new Matrix();
                            matrix.RotateAt((float)angle, center); // 旋转
                            matrix.TransformPoints(LineVirtualRectPoints);

                            GraphicsPath rectPath = new GraphicsPath();
                            rectPath.AddPolygon(LineVirtualRectPoints);

                            Pen rectpen = new Pen(Color.FromArgb(60, 0, 255, 0), 1);

                            // 画框线
                            painter.DrawPath(rectpen, rectPath);

#endif 
                        }


                        // 添加节点到路径  
                        for (int i = 0; i < _points.Count; i++)
                        {
                            DrawVertex(vrtx_path, i);
                        }

                        if (IsClosed())
                        {
                            line_path.AddLine(ScalePoint(_points[0]), ScalePoint(_points[0]));
                        }
                    }
                    break;
                case ShapeTypeEnum.Polygon:
                case ShapeTypeEnum.Point:
                default:
                    {
                        // 添加多边形框线到路径
                        line_path.AddLines(_points.Select(p => ScalePoint(p)).ToArray());

                        // 添加节点到路径  
                        for (int i = 0; i < _points.Count; i++)
                        {
                            DrawVertex(vrtx_path, i);
                        }

                        if (IsClosed())
                        {
                            line_path.AddLine(ScalePoint(_points[0]), ScalePoint(_points[0]));
                        }
                    }
                    break;

            }


            #region 将点绘制到画布上

            // 画框线
            painter.DrawPath(pen, line_path);

            // 填充节点
            if (vrtx_path.PointCount > 0)
            {
                painter.DrawPath(pen, vrtx_path);
                painter.FillPath(new SolidBrush(vertex_fill_color), vrtx_path);
            }


            if (fill) // 是否填充多边形
            {
                Color fillColor = Selected ? select_fill_color : fill_color;
                painter.FillPath(new SolidBrush(fillColor), line_path);
            }

            #endregion

        }


        private Region[] _regionVertex = new Region[] { };

        private void DrawVertex1(GraphicsPath path, int i)
        {
            PointF pt = _points[i];
            _regionVertex[i] = new Region(new RectangleF(
                pt.X - _epsilon, pt.Y - _epsilon,
                _epsilon * 2, _epsilon * 2));

            // 将节点变换
            PointF[] transformedPoint = new PointF[] { pt };
            _matrix.TransformPoints(transformedPoint);  // 变换节点位置

            pt = transformedPoint[0];  // 获取变换后的节点位置

            // 绘制节点
            float d = point_size; // Point size
            PointTypeEnum shape = point_type; // Point shape
            PointF point = ScalePoint(pt);

            if (i == _highlightIndex)
            {
                var setting = _highlightSettings[_highlightMode];
                var size = setting.PointSize;
                shape = setting.PointType;
                d *= size; // Example for highlighting
            }

            if (_highlightIndex >= 0)
            {
                _vertex_fill_color = hvertex_fill_color;
            }
            else
            {
                _vertex_fill_color = vertex_fill_color;
            }

            switch (shape)
            {
                case PointTypeEnum.SQUARE:
                    path.AddRectangle(new RectangleF(point.X - d / 2, point.Y - d / 2, d, d));
                    break;
                case PointTypeEnum.ROUND:
                    path.AddEllipse(point.X - d / 2, point.Y - d / 2, d, d);
                    break;
                default:
                    throw new InvalidOperationException("Unsupported vertex shape");
            }
        }
        private void DrawVertex(GraphicsPath path, int i)
        {
            PointF pt = _points[i];

            float d = point_size; // Point size
            PointTypeEnum shape = point_type; // Point shape
            PointF point = ScalePoint(pt);

            if (i == _highlightIndex)
            {
                var setting = _highlightSettings[_highlightMode];
                var size = setting.PointSize;
                shape = setting.PointType;
                d *= size; // Example for highlighting
            }

            if (_highlightIndex >= 0)
            {
                _vertex_fill_color = hvertex_fill_color;
            }
            else
            {
                _vertex_fill_color = vertex_fill_color;
            }

            switch (shape)
            {
                case PointTypeEnum.SQUARE:
                    path.AddRectangle(new RectangleF(point.X - d / 2, point.Y - d / 2, d, d));
                    break;
                case PointTypeEnum.ROUND:
                    path.AddEllipse(point.X - d / 2, point.Y - d / 2, d, d);
                    break;
                default:
                    throw new InvalidOperationException("Unsupported vertex shape");
            }


        }


        /// <summary>
        /// 查找离鼠标最近且距离小于阈值的节点
        /// </summary>
        /// <param name="point">鼠标位置</param>
        /// <param name="epsilon">阈值</param>
        /// <returns>返回节点的索引</returns>
        public int NearestVertex(PointF point, float epsilon = DFT_VTX_EPSILON)
        {
            switch (ShapeType)
            {
                case ShapeTypeEnum.Rectangle:
                    {

                        for (int i = 0; i < _regionVertex.Length; i++)
                        {
                            if (_regionVertex[i] == null)
                            {
                               break;
                            }
                            if (_regionVertex[i].IsVisible(point))
                            {
                                return i;
                            }
                        }
                    }
                    break;
                default:
                    {
                        _epsilon = epsilon;
                        float min_distance = float.MaxValue;
                        int min_i = -1;

                        PointF scaledPoint = new PointF(point.X * scale, point.Y * scale);

                        for (int i = 0; i < _points.Count; i++)
                        {
                            // 缩放顶点
                            PointF scaledVertex = new PointF(_points[i].X * scale, _points[i].Y * scale);
                            float dist = PointHelper.Distance(scaledVertex, scaledPoint);

                            // 检查距离是否在 epsilon 范围内
                            if (dist <= epsilon && dist < min_distance)
                            {
                                min_distance = dist;
                                min_i = i;
                            }
                        }

                        return min_i;
                    }
            }

            return -1;

        }


        public int NearestEdge(PointF point, float epsilon)
        {
            float min_distance = float.MaxValue;
            int post_i = -1;

            PointF scaledPoint = new PointF(point.X * scale, point.Y * scale);



            for (int i = 0; i < _points.Count; i++)
            {
                // 计算边的两个端点
                PointF start = new PointF(this[i - 1].X * scale, this[i - 1].Y * scale);
                PointF end = new PointF(this[i].X * scale, this[i].Y * scale);

                // 计算到线段的距离
                float dist = PointHelper.DistanceToLine(scaledPoint, start, end);

                // 检查距离是否在 epsilon 范围内
                if (dist <= epsilon && dist < min_distance)
                {
                    min_distance = dist;
                    post_i = i;
                }
            }

            return post_i;
        }


        public bool ContainsPoint(PointF point)
        {
            return MakePath().IsVisible(point);
        }



        private GraphicsPath MakePath()
        {
            GraphicsPath path = new GraphicsPath();

            if (ShapeType == ShapeTypeEnum.Rectangle)
            {
                if (_points.Count == 2)
                {
                    // 创建矩形路径
                    RectangleF rect = new RectangleF(
                        Math.Min(_points[0].X, _points[1].X),
                        Math.Min(_points[0].Y, _points[1].Y),
                        Math.Abs(_points[1].X - _points[0].X),
                        Math.Abs(_points[1].Y - _points[0].Y));

                    path.AddRectangle(rect);
                }
            }
            else if (ShapeType == ShapeTypeEnum.Circle)
            {
                if (_points.Count == 2)
                {
                    // 计算半径
                    float radius = PointHelper.Distance(_points[0], _points[1]);
                    path.AddEllipse(_points[0].X - radius, _points[0].Y - radius, radius * 2, radius * 2);
                }
            }
            else
            {
                // 处理多边形
                path.StartFigure();
                path.AddLine(_points[0], _points[1]);

                for (int i = 2; i < _points.Count; i++)
                {
                    path.AddLine(_points[i - 1], _points[i]);
                }
                path.CloseFigure(); // 结束图形
            }

            return path;
        }


        public RectangleF BoundingRect()
        {
            return MakePath().GetBounds();
        }



        public void MoveBy(PointF offset)
        {
            for (int i = 0; i < _points.Count; i++)
            {
                _points[i] = new PointF(_points[i].X + offset.X, _points[i].Y + offset.Y);
            }
        }


        /// <summary>
        /// 移动特定顶点
        /// </summary>
        /// <param name="index"></param>
        /// <param name="offset"></param>
        /// <exception cref="ArgumentOutOfRangeException"></exception>
        public void MoveVertexBy(int index, PointF offset)
        {
            if (index >= 0 && index < _points.Count)
            {
                _rectSelectedVertex = index;
                _rectSelectedMoveVertex = new PointF(_points[index].X, _points[index].Y);
                _points[index] = new PointF(_points[index].X + offset.X, _points[index].Y + offset.Y);
            }
            else
            {
                throw new ArgumentOutOfRangeException(nameof(index), "Index is out of range.");
            }
        }


        public void HighlightVertex(int i, HighlightModeEnum action)
        {
            this._highlightIndex = i;
            this._highlightMode = action;
        }



        public void HighlightClear()
        {
            _highlightIndex = -1;
        }


        public FlyShape Copy()
        {
            var jsonStr = JsonConvert.SerializeObject(this);
            FlyShape copyShp = JsonConvert.DeserializeObject<FlyShape>(jsonStr);
            return copyShp;
        }



        public int Length => _points.Count();



        public PointF this[int index]
        {

            get
            {
                if (index == -1)
                {
                    return _points[_points.Count - 1];
                }
                return _points[index];
            }
            set
            {
                if (index == -1)
                {
                    _points[_points.Count - 1] = value;
                }
                else
                {
                    _points[index] = value;
                }
            }

        }



        private void NomalizeRotateAngle()
        {
            if (_currentRotateAngle >= 360)
            {
                _currentRotateAngle %= 360;
            }
            else if (_currentRotateAngle < 0)
            {
                _currentRotateAngle = 360 - (-_currentRotateAngle % 360);
            }
        }

    }
}