using System;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
#if UNITY_EDITOR
using System.Reflection;
using UnityEditor;
#endif

namespace Jovian.InspectorTools {

    [AttributeUsage(AttributeTargets.Field)]
    public abstract class ArrayAttribute : Attribute {
        #if UNITY_EDITOR
        public virtual void OnPreGUI(ref Rect position, SerializedProperty property, ref GUIContent label) {
        }
        public virtual void OnPostGUI(ref Rect position, SerializedProperty property, ref GUIContent label) {
        }
        #endif
    }

#if UNITY_EDITOR
    public static class ArrayAttributePropertyHandler {
        public static bool DrawArrayProperty(SerializedProperty property) {
            return DrawArrayProperty(property,
                new GUIContent(ObjectNames.NicifyVariableName(property.name), property.tooltip),
                true
            );
        }
        
        public static bool DrawArrayProperty(SerializedProperty property, GUIContent label, bool includeChildren, params GUILayoutOption[] options) {
            Rect rect = EditorGUILayout.GetControlRect(LabelHasContent(label), EditorGUI.GetPropertyHeight(property, label, includeChildren), options);
            
            bool hasArrayAttributes = TryGetAttributes(property, true, out List<ArrayAttribute> arrayAttributes);
            
            bool isGuiEnabled = GUI.enabled;
            Color contentColor = GUI.contentColor;
            Color backgroundColor = GUI.backgroundColor;
            Color guiColor = GUI.color;

            Rect preRect = new Rect(rect);
            Rect postRect = new Rect(rect);
            
            if (hasArrayAttributes) {
                foreach (ArrayAttribute arrayAttribute in arrayAttributes) {
                    arrayAttribute.OnPreGUI(ref preRect, property, ref label);
                }
            }
            
            bool hasChildPropertiesNotShown = EditorGUI.PropertyField(preRect, property, label, includeChildren);
            
            if (hasArrayAttributes) {
                foreach (ArrayAttribute arrayAttribute in arrayAttributes) {
                    arrayAttribute.OnPostGUI(ref postRect, property, ref label);
                }
            }
            
            GUI.enabled = isGuiEnabled;
            GUI.contentColor = contentColor;
            GUI.backgroundColor = backgroundColor;
            GUI.color = guiColor;

            return hasChildPropertiesNotShown;
        }
        
        private static bool LabelHasContent(GUIContent label)
        {
            return label == null || label.text != string.Empty || (UnityEngine.Object) label.image != (UnityEngine.Object) null;
        }
        
        public static bool TryGetAttributes<TAttribute>(SerializedProperty serializedProperty, bool inherit, out List<TAttribute> attributes)
            where TAttribute : Attribute {
            if(serializedProperty == null) {
                throw new ArgumentNullException(nameof(serializedProperty));
            }

            Type targetObjectType = serializedProperty.serializedObject.targetObject.GetType();

            if(targetObjectType == null) {
                throw new ArgumentException($"Could not find the {nameof(targetObjectType)} of {nameof(serializedProperty)}");
            }

            attributes = new List<TAttribute>();
            
            foreach(string pathSegment in serializedProperty.propertyPath.Split('.')) {
                FieldInfo fieldInfo = targetObjectType.GetRuntimeField(pathSegment);
                if(fieldInfo != null) {
                    IEnumerable<TAttribute> fieldAttributes = fieldInfo.GetCustomAttributes<TAttribute>(inherit);
                    foreach (TAttribute fieldAttribute in fieldAttributes) {
                        attributes.Add(fieldAttribute);
                    }
                }
                
                PropertyInfo propertyInfo = targetObjectType.GetRuntimeProperty(pathSegment);
                if(propertyInfo != null) {
                    IEnumerable<TAttribute> fieldAttributes = propertyInfo.GetCustomAttributes<TAttribute>(inherit);
                    foreach (TAttribute fieldAttribute in fieldAttributes) {
                        attributes.Add(fieldAttribute);
                    }
                }
            }

            return attributes.Count > 0;
        }
    }
    #endif
}