using System;
using Jovian.InspectorTools.Internal;
using Jovian.Utilities.Editor;
using UnityEngine;
#if UNITY_EDITOR
using UnityEditor;
#endif

namespace Jovian.InspectorTools {
    public class RequireArraySizeAttribute : ArrayAttribute, IPropertyCondition {

        public readonly int size;
        public readonly SizeComparison comparison;

        public enum SizeComparison {

            Equal,
            LessThan,
            LessThanOrEqual,
            GreaterThan,
            GreaterThanOrEqual

        }

        public RequireArraySizeAttribute(int size, SizeComparison comparison = SizeComparison.Equal) {
            this.size = size;
            this.comparison = comparison;
        }

#if UNITY_EDITOR
        private bool DoesArraySizeMeetCondition(int arraySize) {
            return comparison switch {
                SizeComparison.Equal => arraySize == size,
                SizeComparison.LessThan => arraySize < size,
                SizeComparison.LessThanOrEqual => arraySize <= size,
                SizeComparison.GreaterThan => arraySize > size,
                SizeComparison.GreaterThanOrEqual => arraySize >= size,
                _ => throw new ArgumentOutOfRangeException()
            };
        }

        private string GetConditionString(int arraySize) {
            return comparison switch {
                SizeComparison.Equal => $"Array.size must be equal to {size} (current={arraySize})",
                SizeComparison.LessThan => $"Array.size must be less than {size} (current={arraySize})",
                SizeComparison.LessThanOrEqual => $"Array.size must be less than or equal to {size} (current={arraySize})",
                SizeComparison.GreaterThan => $"Array.size must be greater than {size} (current={arraySize})",
                SizeComparison.GreaterThanOrEqual => $"Array.size must be greater than or equal to {size} (current={arraySize})",
                _ => throw new ArgumentOutOfRangeException()
            };
        }

        public bool DoesPropertyMeetCondition(SerializedProperty property, out string description) {
            description = string.Empty;
            if (!property.isArray && (property.propertyPath.EndsWith(".Array.size") || EditorSerializationUtility.IsPropertyAnArrayElement(property))) {
                return true; // don't check array conditions for elements
            }

            if (!property.isArray) {
                description = $"{property.name} must be an array";
                return false;
            }

            if (!(property.isArray && DoesArraySizeMeetCondition(property.arraySize))) {
                description = GetConditionString(property.arraySize);
                return false;
            }

            return true;
        }

        public override void OnPreGUI(ref Rect position, SerializedProperty property, ref GUIContent label) {
            if (!DoesPropertyMeetCondition(property, out string description)) {
                RequiredUtil.LayoutRequired(ref position, description, indent: true);
            }
        }

        public override void OnPostGUI(ref Rect position, SerializedProperty property, ref GUIContent label) {
            if (!DoesPropertyMeetCondition(property, out string description)) {
                RequiredUtil.DrawRequired(ref position, description, indent: true);
            }
        }
#endif

    }
}
