using SessionCompanion.Database.Tables;
using SessionCompanion.ViewModels.Enums;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace SessionCompanion.Database
{
    public static class SeedFromJsons
    {
        static public Weapon SingleWeaponSeeder(dynamic item)
        {
            Weapon weapon = new Weapon();

            // Id
            weapon.Id = item.index;

            // Name
            weapon.Name = item.name;

            // Weapon type
            weapon.WeaponType = item.category_range;

            // Cost
            weapon.Cost = item.cost.quantity;

            // CurrnecyType
            switch ((string)item.cost.unit)
            {
                case "sp":
                    weapon.CurrencyType = CurrencyType.sp;
                    break;
                case "gp":
                    weapon.CurrencyType = CurrencyType.gp;
                    break;
            }

            // DiceCount
            weapon.DiceCount = item.damage.dice_count;

            // DiceValue
            weapon.DiceValue = item.damage.dice_value;

            // RangeMeele
            weapon.RangeMeele = item.range.normal;

            // RangeLong
            weapon.RangeLong = item.range._long;

            // RangeThrow
            if (item.throw_range != null)
            {
                weapon.RangeThrowNormal = item.throw_range.normal;
                weapon.RangeThrowLong = item.throw_range._long;
            }

            // Weight
            weapon.Weight = item.weight;

            
            // Twohand
            if (item.two_hand_damage != null)
            {
                weapon.TwoHandDiceCount = item.two_hand_damage.dice_count;
                weapon.TwoHandDiceValue = item.two_hand_damage.dice_value;
            }
            if (item.special != null)
                weapon.Description = item.special[0];
            return weapon;
        }
        static public Armor SingleArmorSeeder(dynamic item, int id)
        {
            Armor armor = new Armor();

            armor.Id = id;
            armor.Name = item.name;
            armor.Category = item.armor_category;
            armor.ArmorClassBase = item.armor_class["base"];
            armor.HaveDexterityBonus = item.armor_class["dex_bonus"];
            armor.MinimumStrength = item.str_minimum;
            armor.HaveStealthDisadvantage = item.stealth_disadvantage;
            armor.Weight = item.weight;
            armor.Cost = item.cost.quantity;
            switch ((string)item.cost.unit)
            {
                case "sp":
                    armor.CurrencyType = CurrencyType.sp;
                    break;
                case "gp":
                    armor.CurrencyType = CurrencyType.gp;
                    break;
            }

            return armor;
        }
        static public OtherEquipment SingleOtherEquipmentSeeder(dynamic item, int id)
        {
            OtherEquipment otherEq = new OtherEquipment();

            otherEq.Id = id;
            otherEq.Name = item.name;
            if (item.desc != null)
                foreach (dynamic description in item.desc)
                    otherEq.Description += " " + description;
            else
                otherEq.Description = string.Empty;

            otherEq.Cost = item.cost.quantity;
            switch ((string)item.cost.unit)
            {
                case "sp":
                    otherEq.CurrencyType = CurrencyType.sp;
                    break;
                case "gp":
                    otherEq.CurrencyType = CurrencyType.gp;
                    break;
            }

            return otherEq;
        }
        static public Spell SingleSpellSeeder(dynamic item)
        {
            Spell spell = new Spell();

            // Id
            spell.Id = item.index;

            // Name
            spell.Name = item.name;

            // Description
            foreach (dynamic des in item.desc)
                spell.Description += des + ";";
            if (spell.Description != null)
                spell.Description = spell.Description.Remove(spell.Description.Length - 1);

            // HigherLevel
            if (item.higher_level != null)
            {
                foreach (dynamic hl in item.higher_level)
                    spell.HigherLevel += (string)hl + ";";
                if (spell.HigherLevel != null)
                    spell.HigherLevel = spell.HigherLevel.Remove(spell.HigherLevel.Length - 1);
            }

            // Range
            switch ((string)item.range)
            {
                case "90 feet":
                    spell.Range = SpellsEnums.Ranges.Feet_90;
                    break;
                case "60 feet":
                    spell.Range = SpellsEnums.Ranges.Feet_60;
                    break;
                case "30 feet":
                    spell.Range = SpellsEnums.Ranges.Feet_30;
                    break;
                case "10 feet":
                    spell.Range = SpellsEnums.Ranges.Feet_10;
                    break;
                case "120 feet":
                    spell.Range = SpellsEnums.Ranges.Feet_120;
                    break;
                case "150 feet":
                    spell.Range = SpellsEnums.Ranges.Feet_150;
                    break;
                case "1 mile":
                    spell.Range = SpellsEnums.Ranges.Miles_1;
                    break;
                case "300 feet":
                    spell.Range = SpellsEnums.Ranges.Feet_300;
                    break;
                case "500 feet":
                    spell.Range = SpellsEnums.Ranges.Feet_500;
                    break;
                case "100 feet":
                    spell.Range = SpellsEnums.Ranges.Feet_100;
                    break;
                case "500 miles":
                    spell.Range = SpellsEnums.Ranges.Miles_500;
                    break;
                case "5 feet":
                    spell.Range = SpellsEnums.Ranges.Feet_5;
                    break;
                default:
                    if (Enum.TryParse<SpellsEnums.Ranges>((string)item.range, true, out SpellsEnums.Ranges RangeType))
                        if (Enum.IsDefined(typeof(SpellsEnums.Ranges), RangeType))
                            spell.Range = RangeType;
                    break;
            }

            // Components
            foreach (dynamic component in item.components)
            {
                if (Enum.TryParse<SpellsEnums.Components>((string)component, true, out SpellsEnums.Components ComponentType))
                    if (Enum.IsDefined(typeof(SpellsEnums.Components), ComponentType))
                        spell.Components += ComponentType + ";";
            }
            if (spell.Components != null)
                spell.Components = spell.Components.Remove(spell.Components.Length - 1);

            if (item.material != null)
                spell.Material = item.material;

            if ((string)item.ritual == "no")
                spell.Ritual = false;
            else
                spell.Ritual = true;

            // Duration
            switch ((string)item.duration)
            {
                case "8 hours":
                    spell.Duration = SpellsEnums.Durations.Hours_8;
                    break;
                case "1 hour":
                    spell.Duration = SpellsEnums.Durations.Hours_1;
                    break;
                case "24 hours":
                    spell.Duration = SpellsEnums.Durations.Hours_24;
                    break;
                case "1 minute":
                    spell.Duration = SpellsEnums.Durations.Minutes_1;
                    break;
                case "10 days":
                    spell.Duration = SpellsEnums.Durations.Days_10;
                    break;
                case "10 minutes":
                    spell.Duration = SpellsEnums.Durations.Minutes_10;
                    break;
                case "1 round":
                    spell.Duration = SpellsEnums.Durations.Round_1;
                    break;
                case "7 days":
                    spell.Duration = SpellsEnums.Durations.Days_7;
                    break;
                case "30 days":
                    spell.Duration = SpellsEnums.Durations.Days_30;
                    break;
                case "2 hours":
                    spell.Duration = SpellsEnums.Durations.Hours_2;
                    break;
                case "Until dispelled":
                    spell.Duration = SpellsEnums.Durations.Until_dispelled;
                    break;
                default:
                    if (Enum.TryParse<SpellsEnums.Durations>((string)item.duration, true, out SpellsEnums.Durations DurationType))
                        if (Enum.IsDefined(typeof(SpellsEnums.Durations), DurationType))
                            spell.Duration = DurationType;
                    break;
            }

            // Concentration
            if ((string)item.concentration == "no")
                spell.Concentration = false;
            else
                spell.Concentration = true;

            // CastingTime
            switch ((string)item.casting_time)
            {
                case "1 action":
                    spell.CastingTime = SpellsEnums.CastingTimes.Action_1;
                    break;
                case "1 minute":
                    spell.CastingTime = SpellsEnums.CastingTimes.Minutes_1;
                    break;
                case "1 hour":
                    spell.CastingTime = SpellsEnums.CastingTimes.Hours_1;
                    break;
                case "8 hours":
                    spell.CastingTime = SpellsEnums.CastingTimes.Hours_8;
                    break;
                case "1 bonus action":
                    spell.CastingTime = SpellsEnums.CastingTimes.Bonus_Action_1;
                    break;
                case "10 minutes":
                    spell.CastingTime = SpellsEnums.CastingTimes.Minutes_10;
                    break;
                case "1 reaction":
                    spell.CastingTime = SpellsEnums.CastingTimes.Reaction_1;
                    break;
                case "24 hours":
                    spell.CastingTime = SpellsEnums.CastingTimes.Hours_24;
                    break;
                case "12 hours":
                    spell.CastingTime = SpellsEnums.CastingTimes.Hours_12;
                    break;
            }

            // Level
            spell.Level = (int)item.level;

            // School
            if (Enum.TryParse<SpellsEnums.Schools>((string)item.school.name, true, out SpellsEnums.Schools SchoolType))
                if (Enum.IsDefined(typeof(SpellsEnums.Schools), SchoolType))
                    spell.School = SchoolType;

            // Classes
            foreach (dynamic c in item.classes)
            {
                if (Enum.TryParse<SpellsEnums.Classes>((string)c.name, true, out SpellsEnums.Classes ClassType))
                    if (Enum.IsDefined(typeof(SpellsEnums.Classes), ClassType))
                        spell.Classes += ClassType + ";";
            }
            if (spell.Classes != null)
                spell.Classes = spell.Classes.Remove(spell.Classes.Length - 1);

            // Subclasses
            foreach (dynamic s in item.subclasses)
            {
                if (Enum.TryParse<SpellsEnums.Subclass>((string)s.name, true, out SpellsEnums.Subclass SubClassType))
                    if (Enum.IsDefined(typeof(SpellsEnums.Subclass), SubClassType))
                        spell.Subclasses += SubClassType + ";";
            }
            if (spell.Subclasses != null)
                spell.Subclasses = spell.Subclasses.Remove(spell.Subclasses.Length - 1);

            return spell;
        }
        static public SpecialAbility SingleSpecialAbilitySeeder(dynamic item, int id)
        {
            SpecialAbility monsterSpecialAbility = new SpecialAbility();

            monsterSpecialAbility.Id = id;

            monsterSpecialAbility.Name = item.name;

            if (item.damage_dice != null)
            {
                var dice = SplitDice((string)item.damage_dice);
                monsterSpecialAbility.DamageDiceAmount = dice.Item1;
                monsterSpecialAbility.DamageDice = dice.Item2;
            }

            monsterSpecialAbility.Description = item.desc;

            return monsterSpecialAbility;
        }
        static public GameAction SingleActionSeeder(dynamic item, int id)
        {
            GameAction monsterAction = new GameAction();

            monsterAction.Id = id;

            monsterAction.Name = item.name;

            monsterAction.AttackBonus = item.attack_bonus;

            monsterAction.DamageBonus = item.damage_bonus;
            if (item.damage_dice != null)
            {
                var dice = SplitDice((string)item.damage_dice);
                monsterAction.DamageDiceAmount = dice.Item1;
                monsterAction.DamageDice = dice.Item2;
            }
            monsterAction.Description = item.desc;
            return monsterAction;
        }
        static public LegendaryAction SingleLegendaryActionSeeder(dynamic item, int id)
        {
            LegendaryAction monsterLegendaryAction = new LegendaryAction();

            monsterLegendaryAction.Id = id;

            monsterLegendaryAction.Name = item.name;

            monsterLegendaryAction.Description = item.desc;

            return monsterLegendaryAction;
        }
        static public Monster SingleMonsterSeeder(dynamic item)
        {
            Monster monster = new Monster();

            monster.Id = item.index;

            monster.Name = item.name;

            monster.Size = item.size;

            monster.Type = item.type;

            monster.Subtype = item.subtype;

            monster.Alignment = item.alignment;

            monster.ArmorClass = item.armor_class;

            monster.HitPoints = item.hit_points;

            var dice = SplitDice((string)item.hit_dice);
            monster.HitDiceAmount = dice.Item1;
            monster.HitDiceType = dice.Item2;

            monster.WalkSpeed = item.speed.walk;
            monster.FlySpeed = item.speed.fly;
            monster.SwimSpeed = item.speed.swim;

            monster.Strength = item.strength;
            monster.StrengthSave = item.strength_save;

            monster.Dexterity = item.dexterity;
            monster.DexteritySave = item.dexterity_save;

            monster.Constitution = item.constitution;
            monster.ConstitutionSave = item.constitution_save;

            monster.Wisdom = item.wisdom;
            monster.WisdomSave = item.wisdom_save;

            monster.Charisma = item.charisma;
            monster.CharismaSave = item.charsisma_save;

            monster.Intelligence = item.intelligence;
            monster.IntelligenceSave = item.intelligence_save;

            foreach (dynamic dv in item.damage_vulnerabilities)
                monster.MonsterDamageVulnerabilities += dv + ";";
            if (monster.MonsterDamageVulnerabilities != null)
                monster.MonsterDamageVulnerabilities = monster.MonsterDamageVulnerabilities.Remove(monster.MonsterDamageVulnerabilities.Length - 1);

            foreach (dynamic dr in item.damage_resistances)
                monster.MonsterDamageResistances += dr + ";";
            if (monster.MonsterDamageResistances != null)
                monster.MonsterDamageResistances = monster.MonsterDamageResistances.Remove(monster.MonsterDamageResistances.Length - 1);

            foreach (dynamic di in item.damage_immunities)
                monster.MonsterDamageImmunities += di + ";";
            if (monster.MonsterDamageImmunities != null)
                monster.MonsterDamageImmunities = monster.MonsterDamageImmunities.Remove(monster.MonsterDamageImmunities.Length - 1);

            foreach (dynamic ci in item.condition_immunities)
                monster.MonsterConditionImmunities += ci + ";";
            if (monster.MonsterConditionImmunities != null)
                monster.MonsterConditionImmunities = monster.MonsterConditionImmunities.Remove(monster.MonsterConditionImmunities.Length - 1);

            monster.MonsterSenses = item.senses;

            monster.MonsterLanguages = item.languages;

            monster.ChallengeRating = item.challenge_rating;

            return monster;
        }
        static public Tuple<int, int> SplitDice(string dice)
        {
            int stop = dice.IndexOf('d');
            var amount = int.Parse(dice.Substring(0, stop));
            stop++;
            var value = int.Parse(dice.Substring(stop, dice.Length - stop));
            return new Tuple<int, int>(amount, value);
        }
    }
}