﻿using System.Collections;
using System.Collections.Generic;
using System.Linq;
using UnityEngine;
using UnityEditor;
using Arugula.Math;

namespace Arugula.Games
{
    [CustomPropertyDrawer(typeof(Stats))]
    public class StatsDrawer : PropertyDrawer
    {
        static StatsDrawer()
        {
            EditorStyles.label.richText = true;
        }

        bool HasType(SerializedProperty types, StatType t)
        {
            for (int i = 0; i < types.arraySize; i++)
            {
                StatType type = (StatType)types.GetArrayElementAtIndex(i).objectReferenceValue;
                if (type == t)
                    return true;
            }

            return false;
        }

        public override void OnGUI(Rect position, SerializedProperty property, GUIContent label)
        {
            var types = property.FindPropertyRelative("types");
            var values = property.FindPropertyRelative("values");
            var modes = property.FindPropertyRelative("modes");

            int count = types.arraySize;

            Rect r = position;

            Event e = Event.current;

            if (r.Contains(e.mousePosition))
            {
                switch (e.type)
                {
                    case EventType.DragUpdated:
                        if (DragAndDrop.objectReferences.Count(x => x is StatType) > 0)
                            DragAndDrop.visualMode = DragAndDropVisualMode.Link;
                        else
                            DragAndDrop.visualMode = DragAndDropVisualMode.Rejected;

                        e.Use();
                        break;
                    case EventType.DragPerform:
                        var dragTypes = DragAndDrop.objectReferences.Where(x => x is StatType).ToList();

                        foreach (var t in dragTypes)
                        {
                            if (!HasType(types, (StatType)t))
                            {
                                types.arraySize++;
                                values.arraySize++;
                                modes.arraySize++;

                                types.GetArrayElementAtIndex(types.arraySize - 1).objectReferenceValue = t;
                                values.GetArrayElementAtIndex(values.arraySize - 1).floatValue = 0;
                                modes.GetArrayElementAtIndex(modes.arraySize - 1).enumValueIndex = 0;

                                property.serializedObject.ApplyModifiedProperties();

                            }
                        }
                        e.Use();

                        break;
                }
            }

            r.height = EditorGUIUtility.singleLineHeight;

            EditorGUI.PropertyField(r, property, new GUIContent(property.displayName + $" ({types.arraySize})"), false);

            if (property.isExpanded)
            {
                r.xMin += 0;

                for (int i = 0; i < count; i++)
                {
                    r.y += EditorGUIUtility.singleLineHeight;


                    Rect line = r;
                    var t = (StatType)types.GetArrayElementAtIndex(i).objectReferenceValue;
                    SerializedProperty v = values.GetArrayElementAtIndex(i);
                    SerializedProperty mode = modes.GetArrayElementAtIndex(i);
                    if (t.icon != null)
                    {
                        Rect iconRect = line;
                        iconRect.width = EditorGUIUtility.singleLineHeight;
                        GUI.DrawTextureWithTexCoords(iconRect, t.icon.texture, new Rect(t.icon.rect.xMin / t.icon.texture.width, t.icon.rect.yMin / t.icon.texture.height, t.icon.rect.xMax / t.icon.texture.width, t.icon.rect.yMax / t.icon.texture.height));
                    }

                    line.xMin += EditorGUIUtility.singleLineHeight + 5;
                    EditorGUI.BeginChangeCheck();
                    float f = v.floatValue;

                    Rect numberRect = line;
                    numberRect.width -= 75;

                    Rect modeRect = line;
                    modeRect.xMin = modeRect.xMax - 75;

                    if (t.snap != 1)
                        f = EditorGUI.FloatField(numberRect, t.displayName + $"  <size=8>{t.id}</size>", v.floatValue);
                    else
                        f = EditorGUI.IntField(numberRect, t.displayName + $"  <size=8>{t.id}</size>", (int)v.floatValue);

                    int modeIndex = (int)(Stats.CombineMode)EditorGUI.EnumPopup(modeRect, (Stats.CombineMode)mode.enumValueIndex);


                    if (EditorGUI.EndChangeCheck())
                    {
                        v.floatValue = f.Clamp(t.min, t.max).Snap(t.snap);
                        mode.enumValueIndex = modeIndex;
                        v.serializedObject.ApplyModifiedProperties();
                    }



                    line.width /= 3;
                    if (e.type == EventType.MouseUp && e.button == 1 && line.Contains(e.mousePosition))
                    {
                        ShowContext(property, i);
                        break;
                    }
                }

                r.y += EditorGUIUtility.singleLineHeight;
            }
        }

        public override float GetPropertyHeight(SerializedProperty property, GUIContent label)
        {
            var types = property.FindPropertyRelative("types");

            return property.isExpanded ? EditorGUIUtility.singleLineHeight * (types.arraySize + 1) : EditorGUIUtility.singleLineHeight;
        }

        void ShowContext(SerializedProperty property, int index)
        {
            GenericMenu menu = new GenericMenu();
            menu.AddItem(new GUIContent("Delete"), false, OnDelete, new object[] { property, index });
            menu.ShowAsContext();
        }

        void OnDelete(object data)
        {
            object[] arr = (object[])data;
            SerializedProperty property = (SerializedProperty)arr[0];
            int index = (int)arr[1];

            property.FindPropertyRelative("values").DeleteArrayElementAtIndex(index);
            property.FindPropertyRelative("modes").DeleteArrayElementAtIndex(index);

            var types = property.FindPropertyRelative("types");

            bool isNull = types.GetArrayElementAtIndex(index).objectReferenceValue == null;
            if (!isNull)
                types.DeleteArrayElementAtIndex(index);

            types.DeleteArrayElementAtIndex(index);

            property.serializedObject.ApplyModifiedProperties();
        }
    }
}