﻿using System;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;

namespace JLGames.RocketDriver.Actions.Component2D
{
    /// <summary>
    /// polygon view
    /// 多边形视图
    /// </summary>
    public class PolygonView2D : MaskableGraphic
    {
        [Header("Border settings 边框设置")] 
        [Tooltip("whether to enable borders\n是否启用边框")] [SerializeField] 
        protected bool Line = true;
        [Tooltip("stroke size\n笔触大小")] [SerializeField] 
        protected float Thickness = 5;
        [Tooltip("stroke color\n笔触颜色")] [SerializeField] 
        protected Color LineColor = Color.black;

        [Header("Fill settings 填充设置")] 
        [Tooltip("Whether to enable padding\n是否启用填充")] [SerializeField] 
        protected bool Fill = true;

        [Header("Polygon settings 多边形设置")] 
        [Tooltip("number of sides\n边数")] [Range(3, 360)] [SerializeField] 
        protected int Sides = 3;
        [Tooltip("Rotation angle\n旋转角度")] [Range(0, 360)] [SerializeField] 
        protected float Rotation = 0;
        [Tooltip("Center distance\n中心距离")] [Range(0, 1)] [SerializeField]
        protected float[] VertDistances = new float[3];

        private Color FillColor => color;
        private int VertCount => Sides + 1;
        private readonly Vector2[] m_Uvs = {new Vector2(0, 1), new Vector2(1, 1), new Vector2(1, 0), new Vector2(0, 0)};

        private float m_Size = 0;

        private readonly List<Vector2> m_Vertexs = new List<Vector2>();
//        private float _diameter = 0;
//        private float _radius = 0;

        public void DrawPolygon(int sides)
        {
            Sides = sides;
            VertDistances = new float[sides + 1];
            for (var i = 0; i < sides; i++) VertDistances[i] = 1;
            Rotation = 0;
            SetAllDirty();
        }

        public void DrawPolygon(int sides, float[] vertDistances)
        {
            Sides = sides;
            SetVertDistances(vertDistances);
            Rotation = 0;
            SetAllDirty();
        }

        public void DrawPolygon(int sides, float[] vertDistances, float rotation)
        {
            Sides = sides;
            SetVertDistances(vertDistances);
            Rotation = rotation;
            SetAllDirty();
        }

        public void DrawPolygon(float[] vertDistances)
        {
            SetVertDistances(vertDistances);
            SetAllDirty();
//            DebugUtil.Log("DrawPolygon");
        }
        
        public Vector2[] GetVerterPolygon()
        {
            LimitSizeThickness();
            var vertices = CheckVertDistances();
            var degrees = 360f / Sides;
            VerterPolygon(vertices,degrees);
            return m_Vertexs.ToArray();
        }

//        void Update()
//        {
//            _size = rectTransform.rect.width;
//            if (rectTransform.rect.width > rectTransform.rect.height)
//                _size = rectTransform.rect.height;
//            else
//                _size = rectTransform.rect.width;
//            Thickness = Mathf.Clamp(Thickness, 0, _size / 2);
//        }

        protected override void OnPopulateMesh(VertexHelper vh)
        {
//            DebugUtil.Log("OnPopulateMesh");
            vh.Clear();
            if (!Fill && !Line) return;

            LimitSizeThickness();
            var vertices = CheckVertDistances();
            var degrees = 360f / Sides;
            if (Fill)
            {
                FillPolygon(vh, vertices, degrees);
            }

            if (Line)
            {
                LinePolygon(vh, vertices, degrees);
            }
        }

        protected void SetVertDistances(float[] vertDistances)
        {
            if (null != vertDistances)
            {
                var vertCount = VertCount;
                var dataLen = vertDistances.Length;
                if (vertCount == dataLen)
                {
                    VertDistances = vertDistances;
                    return;
                }

                if (vertCount == dataLen + 1)
                {
                    VertDistances = new float[vertCount];
                    Array.Copy(vertDistances, VertDistances, dataLen);
                    VertDistances[vertCount - 1] = VertDistances[0];
                    return;
                }
            }

            CheckVertDistances();
        }

        protected void LimitSizeThickness()
        {
            m_Size = rectTransform.rect.width;
            if (rectTransform.rect.width > rectTransform.rect.height)
                m_Size = rectTransform.rect.height;
            else
                m_Size = rectTransform.rect.width;

            Thickness = Mathf.Clamp(Thickness, 0, m_Size / 2);
        }

        protected int CheckVertDistances()
        {
            var vertCount = VertCount;
//            DebugUtil.Log("CheckVertDistances:", VertDistances.Length, vertCount);
            if (VertDistances.Length != vertCount)
            {
                VertDistances = new float[vertCount];
                for (var i = 0; i < vertCount - 1; i++) VertDistances[i] = 1;
            }

            VertDistances[vertCount - 1] = VertDistances[0];
            return vertCount;
        }

        private readonly UIVertex[] _lineVbo = new UIVertex[4];
        
        public void VerterPolygon(int vertices, float degrees)
        {
            m_Vertexs.Clear();
            Vector2 pos0;
            for (var i = 0; i < vertices; i++)
            {
                var outer = -rectTransform.pivot.x * m_Size * VertDistances[i];
                var rad = Mathf.Deg2Rad * (i * degrees + Rotation);
                var c = Mathf.Cos(rad);
                var s = Mathf.Sin(rad);
                pos0 = new Vector2(outer * c, outer * s);
                m_Vertexs.Add(pos0);
            }
        }
        
        private void LinePolygon(VertexHelper vh, int vertices, float degrees)
        {
            Vector2 pos0;
            Vector2 pos1;
            Vector2 pos2;
            Vector2 pos3;
            var prevX = Vector2.zero;
            var prevY = Vector2.zero;

            for (var i = 0; i < vertices; i++)
            {
                var outer = -rectTransform.pivot.x * m_Size * VertDistances[i];
                var inner = -rectTransform.pivot.x * m_Size * VertDistances[i] + Thickness;
                var rad = Mathf.Deg2Rad * (i * degrees + Rotation);
                var c = Mathf.Cos(rad);
                var s = Mathf.Sin(rad);
                pos0 = prevX;
                pos1 = new Vector2(outer * c, outer * s);

                //Line
                pos2 = new Vector2(inner * c, inner * s);
                pos3 = prevY;

                prevX = pos1;
                prevY = pos2;
                SetVbo(new[] {pos0, pos1, pos2, pos3}, m_Uvs, LineColor, _lineVbo);
                vh.AddUIVertexQuad(_lineVbo);
            }
        }

        private readonly UIVertex[] _fillVbo = new UIVertex[4];

        private void FillPolygon(VertexHelper vh, int vertices, float degrees)
        {
            Vector2 pos0;
            Vector2 pos1;
            Vector2 pos2;
            Vector2 pos3;
            var prevX = Vector2.zero;
            for (var i = 0; i < vertices; i++)
            {
                var outer = -rectTransform.pivot.x * m_Size * VertDistances[i];
                var rad = Mathf.Deg2Rad * (i * degrees + Rotation);
                var c = Mathf.Cos(rad);
                var s = Mathf.Sin(rad);
                pos0 = prevX;
                pos1 = new Vector2(outer * c, outer * s);

                //Fill
                pos2 = Vector2.zero;
                pos3 = Vector2.zero;

                prevX = pos1;
                SetVbo(new[] {pos0, pos1, pos2, pos3}, m_Uvs, FillColor, _fillVbo);
                vh.AddUIVertexQuad(_fillVbo);
            }
        }

        private void SetVbo(Vector2[] vertices, Vector2[] uvs, Color newColor, UIVertex[] targetVbo)
        {
            for (var i = 0; i < vertices.Length; i++)
            {
                var vert = UIVertex.simpleVert;
                vert.color = newColor;
                vert.position = vertices[i];
                vert.uv0 = uvs[i];
                targetVbo[i] = vert;
            }
        }


        private void ClearVertex()
        {
            transform.DetachChildren();
        }
    }
}