using System.Collections.Generic;
using NUnit.Framework;
using Sirenix.Utilities;
using Test.Util;
using UnityEditor;
using UnityEngine;
using VOID.Generic.Dict.Ability;
using VOID.ScriptableObjects.Abilities;

namespace Test.EditMode.GameData.Generic
{
    public class BasicAbilityTest
    {
        private List<BasicAbility> _abilities = new();

        [OneTimeSetUp]
        public void Setup()
        {
            AssetDatabase.FindAssets($"t:{nameof(BasicAbility)}").ForEach(guid =>
            {
                var path = AssetDatabase.GUIDToAssetPath(guid);
                var ability = AssetDatabase.LoadAssetAtPath<BasicAbility>(path);

                _abilities.Add(ability);
            });
        }

        [OneTimeTearDown]
        public void Cleanup()
        {
            _abilities.Clear();
            _abilities = null;
        }

        [Test]
        public void FileNameSuffix_MatchesAbility()
        {
            _abilities.ForEach(ability =>
            {
                var assetPath = AssetDatabase.GetAssetPath(ability.GetInstanceID());
                var assetHyperLink = DebugLogUtil.Hyperlink(assetPath);
                if (assetPath.EndsWith("Ability.asset")) return;
                Debug.LogError($"ScriptableObject: {assetHyperLink} does not ends with 'Ability'",
                    ability);
            });
        }

        [Test]
        public void DisplayName_IsPresent()
        {
            _abilities.ForEach(ability =>
            {
                var assetPath = AssetDatabase.GetAssetPath(ability.GetInstanceID());
                var assetHyperLink = DebugLogUtil.Hyperlink(assetPath);
                if (ability.displayName.IsNullOrWhitespace())
                    Debug.LogError($"ScriptableObject: {assetHyperLink} display name is empty",
                        ability);
            });
        }

        [Test]
        public void DisplayIcon_IsPresent()
        {
            _abilities.ForEach(ability =>
            {
                var assetPath = AssetDatabase.GetAssetPath(ability.GetInstanceID());
                var assetHyperLink = DebugLogUtil.Hyperlink(assetPath);
                if (!ability.displayIcon)
                    Debug.LogError($"ScriptableObject: {assetHyperLink} display icon is not selected",
                        ability);
            });
        }

        [Test]
        public void Quality_IsPresent()
        {
            _abilities.ForEach(ability =>
            {
                var assetPath = AssetDatabase.GetAssetPath(ability.GetInstanceID());
                var assetHyperLink = DebugLogUtil.Hyperlink(assetPath);
                if (!ability.quality)
                    Debug.LogError($"ScriptableObject: {assetHyperLink} quality is not selected",
                        ability);
            });
        }

        [Test]
        public void CastingAnimationList_IsPresent()
        {
            _abilities.ForEach(ability =>
            {
                if (ability is BasicAttackAbility) return;
                var assetPath = AssetDatabase.GetAssetPath(ability.GetInstanceID());
                var assetHyperLink = DebugLogUtil.Hyperlink(assetPath);
                if (!ability.castingAnimationList && ability.aimingType != AbilityAimingType.Blank)
                    Debug.LogError($"ScriptableObject: {assetHyperLink} casting animation is not selected",
                        ability);
            });
        }

        [Test]
        public void AbilityAnimationList_IsPresent()
        {
            _abilities.ForEach(ability =>
            {
                var assetPath = AssetDatabase.GetAssetPath(ability.GetInstanceID());
                var assetHyperLink = DebugLogUtil.Hyperlink(assetPath);
                if (!ability.abilityAnimationList && ability.castingType != AbilityCastingType.Instant)
                    Debug.LogError($"ScriptableObject: {assetHyperLink} ability animation is not selected",
                        ability);
            });
        }

        [Test]
        public void Range_MinimalRange()
        {
            _abilities.ForEach(ability =>
            {
                var assetPath = AssetDatabase.GetAssetPath(ability.GetInstanceID());
                var assetHyperLink = DebugLogUtil.Hyperlink(assetPath);
                if (ability.range < 1f)
                    Debug.LogError($"ScriptableObject: {assetHyperLink} range cant be lesser than 1",
                        ability);
            });
        }

        [Test]
        public void Range_IsMelee()
        {
            _abilities.ForEach(ability =>
            {
                var assetPath = AssetDatabase.GetAssetPath(ability.GetInstanceID());
                var assetHyperLink = DebugLogUtil.Hyperlink(assetPath);
                if (!ability.isRanged && ability.range > 1f)
                    Debug.LogError($"ScriptableObject: {assetHyperLink} isRanged=false, range need to be '1'",
                        ability);
            });
        }

        [Test]
        public void CastUsages_AtLeastOne()
        {
            _abilities.ForEach(ability =>
            {
                var assetPath = AssetDatabase.GetAssetPath(ability.GetInstanceID());
                var assetHyperLink = DebugLogUtil.Hyperlink(assetPath);
                if (ability.castUsages < 1)
                    Debug.LogError($"ScriptableObject: {assetHyperLink} cast usages cant be lesser than 1",
                        ability);
            });
        }

        [Test]
        public void Projectile_IsPresent()
        {
            _abilities.ForEach(ability =>
            {
                var assetPath = AssetDatabase.GetAssetPath(ability.GetInstanceID());
                var assetHyperLink = DebugLogUtil.Hyperlink(assetPath);
                if (!ability.projectile)
                    Debug.LogError($"ScriptableObject: {assetHyperLink} projectile is not selected",
                        ability);
            });
        }
    }
}

