using System.Collections;
using System.Collections.Generic;
using NUnit.Framework;
using Set.Data;

namespace Tests.Editor
{
    [TestFixture]
    public class TestTraitsUtils
    {
        [Test]
        [TestCaseSource(typeof(TraitTestCases), "EmblemsSynergies")]
        public void TestMergeEmblems(
            Dictionary<int, int> emblem,
            Dictionary<int, int> synergies,
            Dictionary<int, int> expected
        )
        {
            var output = TraitsMapping.MergeEmblems(emblem, synergies);
            foreach (KeyValuePair<int, int> pair in expected)
            {
                Assert.IsTrue(output[pair.Key] == pair.Value);
            }
        }

        [Test]
        [TestCaseSource(typeof(TraitTestCases), "ActiveTraits")]
        public void TestActiveSynergyFilter(Dictionary<int, int> synergies, int expected)
        {
            int output = TraitsMapping.FilterActiveTraits(synergies);
            Assert.IsTrue(Equals(output, expected));
        }

        [Test]
        public void TestMapping()
        {
            foreach (var champTraits in TraitsMapping.ChampsTraits)
            {
                var champion = champTraits.Key;
                var traits = TraitUtils.FromInt(champTraits.Value);
                foreach (var trait in traits)
                {
                    var allChampofTrait = TraitsMapping.TraitsChamp[(int)trait];
                    HashSet<ChampionsEnum> champions = ChampionUtils.FromLong(allChampofTrait);
                    Assert.IsTrue(
                        ChampionUtils.ContainsChampion(
                            allChampofTrait,
                            champion
                        )
                    );
                }
            }

            foreach (var traitChamp in TraitsMapping.TraitsChamp)
            {
                var trait = traitChamp.Key;
                var champions = ChampionUtils.FromLong(traitChamp.Value);
                foreach (var champion in champions)
                {
                    var allTraitsOfChamp = TraitsMapping.ChampsTraits[(long)champion];
                    Assert.IsTrue(
                        TraitUtils.ContainsTrait(
                            allTraitsOfChamp,
                            trait
                        )
                    );
                }
            }
        }

        [Test]
        [TestCaseSource(typeof(TraitTestCases), "traitsEnum")]
        public void TestIntTrait(int traitInt)
        {
            var traits = TraitUtils.FromInt(traitInt);
            long output = TraitUtils.ToInt(traits);
            Assert.IsTrue(traitInt == output);
        }

        [Test]
        [TestCaseSource(typeof(TraitTestCases), "traitsToInt")]
        public void TestTraitToInt(HashSet<TraitsEnum> traits, int expectedInt)
        {
            int output = TraitUtils.ToInt(traits);
            Assert.IsTrue(output == expectedInt);
        }
    }

    public class TraitTestCases
    {
        public static IEnumerable EmblemsSynergies
        {
            get
            {
                yield return new TestCaseData(
                    new Dictionary<int, int> { { (int)TraitsEnum.BATTLEACADEMIA, 1 } },
                    new Dictionary<int, int> { { (int)TraitsEnum.BATTLEACADEMIA, 1 } },
                    new Dictionary<int, int> { { (int)TraitsEnum.BATTLEACADEMIA, 2 } }
                );
                yield return new TestCaseData(
                    new Dictionary<int, int>
                    {
                        { (int)TraitsEnum.BATTLEACADEMIA, 1 },
                        { (int)TraitsEnum.CRYSTALGAMBIT, 2 },
                        { (int)TraitsEnum.LUCHADOR, 3 },
                        { (int)TraitsEnum.MIGHTYMECH, 4 },
                        { (int)TraitsEnum.SOULFIGHTER, 5 },
                        { (int)TraitsEnum.BASTION, 6 },
                    },
                    new Dictionary<int, int>
                    {
                        { (int)TraitsEnum.BATTLEACADEMIA, 1 },
                        { (int)TraitsEnum.CRYSTALGAMBIT, 2 },
                        { (int)TraitsEnum.LUCHADOR, 3 },
                        { (int)TraitsEnum.MIGHTYMECH, 4 },
                        { (int)TraitsEnum.SOULFIGHTER, 5 },
                        { (int)TraitsEnum.BASTION, 6 },
                    },
                    new Dictionary<int, int>
                    {
                        { (int)TraitsEnum.BATTLEACADEMIA, 2 },
                        { (int)TraitsEnum.CRYSTALGAMBIT, 4 },
                        { (int)TraitsEnum.LUCHADOR, 6 },
                        { (int)TraitsEnum.MIGHTYMECH, 8 },
                        { (int)TraitsEnum.SOULFIGHTER, 10 },
                        { (int)TraitsEnum.BASTION, 12 },
                    }
                );
                /*
                Set 15 traits list:
                Origins: BATTLEACADEMIA, CRYSTALGAMBIT, LUCHADOR, MIGHTYMECH, MONSTERTRAINER, 
                         SOULFIGHTER, STARGUARDIAN, SUPREMECELLS, THECREW, WRAITH, MENTOR, 
                         PRODIGY, THECHAMP, STANCEMASTER, ROGUECAPTAIN
                Classes: BASTION, DUELIST, EDGELORD, EXECUTIONER, HEAVYWEIGHT, JUGGERNAUT, 
                         PROTECTOR, SNIPER, SORCERER, STRATEGIST
                */
            }
        }

        public static IEnumerable ActiveTraits
        {
            get
            {
                yield return new TestCaseData(
                    new Dictionary<int, int>
                    {
                        { (int)TraitsEnum.BATTLEACADEMIA, 1 },
                        { (int)TraitsEnum.CRYSTALGAMBIT, 2 },
                        { (int)TraitsEnum.LUCHADOR, 3 },
                        { (int)TraitsEnum.MIGHTYMECH, 4 },
                        { (int)TraitsEnum.SOULFIGHTER, 1 },
                        { (int)TraitsEnum.BASTION, 1 },
                    },
                    TraitUtils.ToInt(
                        new HashSet<TraitsEnum>
                        {
                            TraitsEnum.CRYSTALGAMBIT,
                            TraitsEnum.LUCHADOR,
                            TraitsEnum.MIGHTYMECH
                        }
                    )
                );

                yield return new TestCaseData(
                    new Dictionary<int, int>
                    {
                        { (int)TraitsEnum.BATTLEACADEMIA, 5 },
                        { (int)TraitsEnum.LUCHADOR, 2 },
                        { (int)TraitsEnum.STARGUARDIAN, 7 },
                        { (int)TraitsEnum.SOULFIGHTER, 4 },
                        { (int)TraitsEnum.BASTION, 3 },
                    },
                    TraitUtils.ToInt(
                        new HashSet<TraitsEnum>
                        {
                            TraitsEnum.BATTLEACADEMIA,
                            TraitsEnum.STARGUARDIAN,
                            TraitsEnum.SOULFIGHTER,
                            TraitsEnum.BASTION
                        }
                    )
                );
            }
        }

        public static IEnumerable traitsEnum
        {
            get
            {
                yield return 156;
                yield return 621;
                yield return 123456;
                yield return 5;
                yield return 4194303; // max value 
                yield return 4194302;
            }
        }

        public static IEnumerable traitsToInt
        {
            get
            {
                yield return new TestCaseData(
                    new HashSet<TraitsEnum>
                    {
                        TraitsEnum.BATTLEACADEMIA,
                        TraitsEnum.CRYSTALGAMBIT
                    },
                    1 << 0 | 1 << 1
                );
                yield return new TestCaseData(
                    new HashSet<TraitsEnum>
                    {
                        TraitsEnum.BATTLEACADEMIA,
                        TraitsEnum.CRYSTALGAMBIT,
                        TraitsEnum.LUCHADOR,
                        TraitsEnum.MIGHTYMECH,
                        TraitsEnum.SOULFIGHTER,
                        TraitsEnum.BASTION
                    },
                    1 << 0 | 1 << 1 | 1 << 2 | 1 << 3 | 1 << 5 | 1 << 15
                );
                yield return new TestCaseData(new HashSet<TraitsEnum> { TraitsEnum.BATTLEACADEMIA }, 1 << 0);
                yield return new TestCaseData(new HashSet<TraitsEnum> { TraitsEnum.CRYSTALGAMBIT }, 1 << 1);
                yield return new TestCaseData(new HashSet<TraitsEnum> { TraitsEnum.LUCHADOR }, 1 << 2);
                yield return new TestCaseData(new HashSet<TraitsEnum> { TraitsEnum.MIGHTYMECH }, 1 << 3);
                yield return new TestCaseData(new HashSet<TraitsEnum> { TraitsEnum.MONSTERTRAINER }, 1 << 4);
                yield return new TestCaseData(new HashSet<TraitsEnum> { TraitsEnum.SOULFIGHTER }, 1 << 5);
                yield return new TestCaseData(new HashSet<TraitsEnum> { TraitsEnum.STARGUARDIAN }, 1 << 6);
                yield return new TestCaseData(new HashSet<TraitsEnum> { TraitsEnum.SUPREMECELLS }, 1 << 7);
                yield return new TestCaseData(new HashSet<TraitsEnum> { TraitsEnum.THECREW }, 1 << 8);
                yield return new TestCaseData(new HashSet<TraitsEnum> { TraitsEnum.WRAITH }, 1 << 9);
                yield return new TestCaseData(new HashSet<TraitsEnum> { TraitsEnum.MENTOR }, 1 << 10);
                yield return new TestCaseData(new HashSet<TraitsEnum> { TraitsEnum.PRODIGY }, 1 << 11);
                yield return new TestCaseData(new HashSet<TraitsEnum> { TraitsEnum.THECHAMP }, 1 << 12);
                yield return new TestCaseData(new HashSet<TraitsEnum> { TraitsEnum.STANCEMASTER }, 1 << 13);
                yield return new TestCaseData(new HashSet<TraitsEnum> { TraitsEnum.ROGUECAPTAIN }, 1 << 14);
                yield return new TestCaseData(new HashSet<TraitsEnum> { TraitsEnum.BASTION }, 1 << 15);
                yield return new TestCaseData(new HashSet<TraitsEnum> { TraitsEnum.DUELIST }, 1 << 16);
                yield return new TestCaseData(new HashSet<TraitsEnum> { TraitsEnum.EDGELORD }, 1 << 17);
                yield return new TestCaseData(new HashSet<TraitsEnum> { TraitsEnum.EXECUTIONER }, 1 << 18);
                yield return new TestCaseData(new HashSet<TraitsEnum> { TraitsEnum.HEAVYWEIGHT }, 1 << 19);
                yield return new TestCaseData(new HashSet<TraitsEnum> { TraitsEnum.JUGGERNAUT }, 1 << 20);
                yield return new TestCaseData(new HashSet<TraitsEnum> { TraitsEnum.PROTECTOR }, 1 << 21);
                yield return new TestCaseData(new HashSet<TraitsEnum> { TraitsEnum.SNIPER }, 1 << 22);
                yield return new TestCaseData(new HashSet<TraitsEnum> { TraitsEnum.SORCERER }, 1 << 23);
                yield return new TestCaseData(new HashSet<TraitsEnum> { TraitsEnum.STRATEGIST }, 1 << 24);
            }
        }
    }
}
