using Server.Items;
using Server.Mobiles;
using Server.Spells;
using Server.Spells.Necromancy;
using System;
using System.Collections.Generic;
using System.Linq;

namespace Server.Engines.Blackthorn
{
    public class Invader : BaseCreature
    {
        public static SkillName RandomSpecialty()
        {
            return _Specialties[Utility.Random(_Specialties.Length)];
        }

        private static readonly SkillName[] _Specialties =
        {
            SkillName.Swords,
            SkillName.Fencing,
            SkillName.Macing,
            SkillName.Archery,
            SkillName.Magery,
            SkillName.Mysticism,
            SkillName.Spellweaving,
            SkillName.Bushido,
            SkillName.Bushido,
            SkillName.Ninjitsu,
            SkillName.Chivalry,
            SkillName.Necromancy,
            SkillName.Poisoning
        };

        private InvasionType _InvasionType;
        private SkillName _Specialty;

        private bool _Sampire;
        private DateTime _NextSpecial;

        public override bool AlwaysMurderer => true;
        public override double HealChance => AI == AIType.AI_Melee || AI == AIType.AI_Paladin ? 1.0 : 0.0;
        public override double WeaponAbilityChance => AI == AIType.AI_Melee || AI == AIType.AI_Paladin ? 0.4 : 0.1;
        public override bool CanStealth => _Specialty == SkillName.Ninjitsu;

        public override WeaponAbility GetWeaponAbility()
        {
            BaseWeapon wep = Weapon as BaseWeapon;

            if (wep != null)
            {
                return 0.6 > Utility.RandomDouble() ? wep.PrimaryAbility : wep.SecondaryAbility;
            }

            return null;
        }

        public override bool UseSmartAI => true;
        public virtual bool CanDoSpecial => SpellCaster;

        public virtual double MinSkill => 100.0;
        public virtual double MaxSkill => 120.0;
        public virtual int MinResist => 10;
        public virtual int MaxResist => 20;

        public bool SpellCaster => AI != AIType.AI_Melee && AI != AIType.AI_Ninja && AI != AIType.AI_Samurai && AI != AIType.AI_Paladin;

        [Constructable]
        public Invader(InvasionType type)
            : this(RandomSpecialty(), type)
        {
        }

        [Constructable]
        public Invader(SkillName specialty, InvasionType type)
            : base(GetAI(specialty), FightMode.Closest, 10, 1, .2, .1)
        {
            _Specialty = specialty;
            _InvasionType = type;

            if (_Specialty == SkillName.Bushido && Utility.RandomBool())
                _Sampire = true;

            if (Female = Utility.RandomBool())
            {
                //Body = 0x191;
                Name = NameList.RandomName("female");
            }
            else
            {
                //Body = 0x190;
                Name = NameList.RandomName("male");
            }

            SetBody();

            string title;

            if (_Sampire)
            {
                title = "the sampire";
            }
            else if (specialty == SkillName.Magery)
            {
                title = "the wizard";
            }
            else
            {
                title = string.Format("the {0}", Skills[specialty].Info.Title);
                if (Female && title.EndsWith("man"))
                    title = title.Substring(0, title.Length - 3) + "woman";
            }

            Title = title;

            SetStr(120, 170);
            SetDex(SpellCaster ? 75 : 150);
            SetInt(SpellCaster ? 1800 : 500);

            SetHits(800, 1250);

            if (AI == AIType.AI_Melee)
                SetDamage(15, 28);
            else if (!SpellCaster)
                SetDamage(12, 22);
            else
                SetDamage(8, 18);

            Fame = 8000;
            Karma = -8000;

            SetResists();
            SetSkills();
            EquipSpecialty();

            _NextSpecial = DateTime.UtcNow;

            if (_Sampire)
            {
                Timer.DelayCall(TimeSpan.FromSeconds(1), () =>
                    {
                        VampiricEmbraceSpell spell = new VampiricEmbraceSpell(this, null);
                        spell.Cast();
                    });
            }

            SetAreaEffect(AreaEffect.AuraOfEnergy);
        }

        public virtual void SetBody()
        {
            switch (_Specialty)
            {
                default:
                    if (0.75 > Utility.RandomDouble())
                        Race = Race.Human;
                    else
                        Race = Race.Elf; break;
                case SkillName.Archery:
                case SkillName.Spellweaving: Race = Race.Elf; break;
            }

            HairItemID = Race.RandomHair(Female);
            HairHue = Race.RandomHairHue();

            FacialHairItemID = Race.RandomFacialHair(Female);
            FacialHairHue = Race.RandomHairHue();

            Hue = Race.RandomSkinHue();
        }

        public virtual void SetResists()
        {
            SetResistance(ResistanceType.Physical, MinResist, MaxResist);
            SetResistance(ResistanceType.Fire, MinResist, MaxResist);
            SetResistance(ResistanceType.Cold, MinResist, MaxResist);
            SetResistance(ResistanceType.Poison, MinResist, MaxResist);
            SetResistance(ResistanceType.Energy, MinResist, MaxResist);
        }

        public virtual void SetSkills()
        {
            SetSkill(SkillName.Fencing, MinSkill, MaxSkill);
            SetSkill(SkillName.Macing, MinSkill, MaxSkill);
            SetSkill(SkillName.MagicResist, MinSkill, MaxSkill);
            SetSkill(SkillName.Swords, MinSkill, MaxSkill);
            SetSkill(SkillName.Tactics, MinSkill, MaxSkill);
            SetSkill(SkillName.Wrestling, MinSkill, MaxSkill);
            SetSkill(SkillName.Archery, MinSkill, MaxSkill);
            SetSkill(SkillName.Parry, MinSkill, MaxSkill);

            if (SpellCaster)
            {
                SetSkill(SkillName.Magery, MinSkill, MaxSkill);
                SetSkill(SkillName.EvalInt, MinSkill, MaxSkill);
            }

            if (Skills[_Specialty].Base < MinSkill)
                SetSkill(_Specialty, MinSkill, MaxSkill);

            if (_Sampire)
            {
                SetSkill(SkillName.Necromancy, MinSkill, MaxSkill);
            }

            if (_Sampire || _Specialty == SkillName.Necromancy)
            {
                SetSkill(SkillName.SpiritSpeak, MinSkill, MaxSkill);
            }

            if (_Specialty == SkillName.Ninjitsu)
            {
                SetSkill(SkillName.Hiding, 100);
                SetSkill(SkillName.Stealth, 100);
            }
        }

        public virtual void EquipSpecialty()
        {
            SetWearable(new ThighBoots());
            SetWearable(new BodySash(), Utility.RandomSlimeHue());

            switch (_Specialty)
            {
                case SkillName.Chivalry:
                    SetWearable(RandomSwordWeapon());
                    PaladinEquip();
                    break;
                case SkillName.Swords:
                    SetWearable(RandomSwordWeapon());
                    StandardMeleeEquip();
                    break;
                case SkillName.Fencing:
                    SetWearable(RandomFencingWeapon());
                    StandardMeleeEquip();
                    break;
                case SkillName.Macing:
                    SetWearable(RandomMaceWeapon());
                    StandardMeleeEquip();
                    break;
                case SkillName.Archery:
                    SetWearable(RandomArhceryWeapon());
                    StandardMeleeEquip();
                    break;
                case SkillName.Magery:
                    SetWearable(RandomMageWeapon());
                    StandardMageEquip();
                    break;
                case SkillName.Mysticism:
                    SetWearable(RandomMageWeapon());
                    StandardMageEquip();
                    break;
                case SkillName.Spellweaving:
                    SetWearable(RandomMageWeapon());
                    StandardMageEquip();
                    break;
                case SkillName.Necromancy:
                    SetWearable(RandomMageWeapon());
                    StandardMageEquip();
                    break;
                case SkillName.Bushido:
                    BaseWeapon w = RandomSamuraiWeapon() as BaseWeapon;
                    SetWearable(w);

                    SetWearable(new LeatherSuneate());
                    SetWearable(new LeatherJingasa());
                    SetWearable(new LeatherDo());
                    SetWearable(new LeatherHiroSode());
                    SetWearable(new SamuraiTabi(Utility.RandomNondyedHue()));

                    if (_Sampire)
                        w.WeaponAttributes.HitLeechHits = 100;

                    SetSkill(SkillName.Parry, 120);
                    break;
                case SkillName.Ninjitsu:
                    SetWearable(RandomNinjaWeapon());

                    LeatherNinjaBelt belt = new LeatherNinjaBelt
                    {
                        UsesRemaining = 20,
                        Poison = Poison.Greater,
                        PoisonCharges = 20
                    };
                    SetWearable(belt);

                    for (int i = 0; i < 2; i++)
                    {
                        Fukiya f = new Fukiya
                        {
                            UsesRemaining = 10,
                            Poison = Poison.Greater,
                            PoisonCharges = 10,
                            Movable = false
                        };
                        PackItem(f);
                    }

                    SetWearable(new NinjaTabi());
                    SetWearable(new LeatherNinjaJacket());
                    SetWearable(new LeatherNinjaHood());
                    SetWearable(new LeatherNinjaPants());
                    SetWearable(new LeatherNinjaMitts());

                    break;
                case SkillName.Poisoning:
                    BaseWeapon wep = RandomAssassinWeapon() as BaseWeapon;
                    wep.Poison = Poison.Lethal;
                    wep.PoisonCharges = 100;
                    SetWearable(wep);

                    SetWearable(new LeatherChest());
                    SetWearable(new LeatherLegs());
                    SetWearable(new LeatherGloves());
                    SetWearable(new LeatherGorget());
                    break;
            }
        }

        private void PaladinEquip()
        {
            SetWearable(Loot.Construct(new Type[] { typeof(Bascinet), typeof(Helmet), typeof(PlateHelm) }), 1153);

            SetWearable(new PlateChest());
            SetWearable(new PlateLegs());
            SetWearable(new PlateGloves());
            SetWearable(new PlateGorget());
            SetWearable(new PlateArms());
            SetWearable(new MetalKiteShield());

            SetSkill(SkillName.Parry, 120);
        }

        private void StandardMeleeEquip()
        {
            SetWearable(Loot.Construct(new Type[] { typeof(Bascinet), typeof(Helmet), typeof(LeatherCap), typeof(RoyalCirclet) }));

            SetWearable(new ChainChest());
            SetWearable(new ChainLegs());
            SetWearable(new RingmailGloves());
            SetWearable(new LeatherGorget());
        }

        private void StandardMageEquip()
        {
            bool mage = AI == AIType.AI_Mage;

            SetWearable(new WizardsHat(), mage ? Utility.RandomBlueHue() : Utility.RandomRedHue());
            SetWearable(new Robe(), mage ? Utility.RandomBlueHue() : Utility.RandomRedHue());
            SetWearable(new LeatherGloves());
        }

        public static AIType GetAI(SkillName skill)
        {
            switch (skill)
            {
                default: return AIType.AI_Melee;
                case SkillName.Ninjitsu: return AIType.AI_Ninja;
                case SkillName.Bushido: return AIType.AI_Samurai;
                case SkillName.Chivalry: return AIType.AI_Paladin;
                case SkillName.Magery: return AIType.AI_Mage;
                case SkillName.Necromancy: return AIType.AI_NecroMage;
                case SkillName.Spellweaving: return AIType.AI_Spellweaving;
                case SkillName.Mysticism: return AIType.AI_Mystic;
            }
        }

        public Item RandomSwordWeapon()
        {
            if (Race == Race.Elf)
                return Loot.Construct(new Type[] { typeof(ElvenMachete), typeof(RadiantScimitar) });

            return Loot.Construct(new Type[] { typeof(Broadsword), typeof(Longsword), typeof(Katana), typeof(Halberd), typeof(Bardiche), typeof(VikingSword) });
        }

        public Item RandomFencingWeapon()
        {
            if (Race == Race.Elf)
                return Loot.Construct(new Type[] { typeof(Leafblade), typeof(WarCleaver), typeof(AssassinSpike) });

            return Loot.Construct(new Type[] { typeof(Kryss), typeof(Spear), typeof(ShortSpear), typeof(Lance), typeof(Pike) });
        }

        public Item RandomMaceWeapon()
        {
            return Loot.Construct(new Type[] { typeof(Mace), typeof(WarHammer), typeof(WarAxe), typeof(BlackStaff), typeof(QuarterStaff), typeof(WarMace), typeof(DiamondMace), typeof(Scepter) });
        }

        public Item RandomArhceryWeapon()
        {
            if (Race == Race.Elf)
                return Loot.Construct(new Type[] { typeof(MagicalShortbow), typeof(ElvenCompositeLongbow) });

            return Loot.Construct(new Type[] { typeof(Bow), typeof(Crossbow), typeof(HeavyCrossbow), typeof(CompositeBow), typeof(RepeatingCrossbow) });
        }

        public Item RandomMageWeapon()
        {
            return Loot.Construct(new Type[] { typeof(Spellbook), typeof(GnarledStaff), typeof(BlackStaff), typeof(QuarterStaff), typeof(WildStaff) });
        }

        public Item RandomSamuraiWeapon()
        {
            return Loot.Construct(new Type[] { typeof(Lajatang), typeof(Wakizashi), typeof(NoDachi) });
        }

        public Item RandomNinjaWeapon()
        {
            return Loot.Construct(new Type[] { typeof(Wakizashi), typeof(Tessen), typeof(Nunchaku), typeof(Daisho), typeof(Sai), typeof(Tekagi), typeof(Kama), typeof(Katana) });
        }

        public Item RandomAssassinWeapon()
        {
            return Loot.Construct(new Type[] { typeof(Cleaver), typeof(ButcherKnife), typeof(Kryss), typeof(Dagger) });
        }

        public override void GetProperties(ObjectPropertyList list)
        {
            base.GetProperties(list);

            list.Add(1154196 + (int)_InvasionType);
        }

        public override void OnThink()
        {
            base.OnThink();

            if (Combatant == null)
                return;

            if (CanDoSpecial && InRange(Combatant, 4) && 0.1 > Utility.RandomDouble() && _NextSpecial < DateTime.UtcNow)
            {
                DoSpecial();

                _NextSpecial = DateTime.UtcNow + TimeSpan.FromSeconds(Utility.RandomMinMax(30, 60));
            }
            else if (_Sampire)
            {
                if (0.1 > Utility.RandomDouble() && Weapon is BaseWeapon && !CurseWeaponSpell.IsCursed(this, (BaseWeapon)Weapon))
                {
                    CurseWeaponSpell spell = new CurseWeaponSpell(this, null);
                    spell.Cast();
                }
                else if (!TransformationSpellHelper.UnderTransformation(this, typeof(VampiricEmbraceSpell)))
                {
                    VampiricEmbraceSpell spell = new VampiricEmbraceSpell(this, null);
                    spell.Cast();
                }
            }
        }

        private void DoSpecial()
        {
            if (Map == null || Map == Map.Internal)
                return;

            Map m = Map;

            for (int i = 0; i < 4; i++)
            {
                Timer.DelayCall(TimeSpan.FromMilliseconds(i * 50), o =>
                {
                    Misc.Geometry.Circle2D(Location, m, o, (pnt, map) =>
                    {
                        Effects.SendLocationEffect(pnt, map, Utility.RandomBool() ? 14000 : 14013, 14, 20, 2018, 0);
                    });
                }, i);
            }

            Timer.DelayCall(TimeSpan.FromMilliseconds(200), () =>
                {
                    if (m != null)
                    {
                        List<Mobile> list = new List<Mobile>();
                        IPooledEnumerable eable = m.GetMobilesInRange(Location, 4);

                        foreach (Mobile mob in eable)
                        {
                            if (mob.AccessLevel > AccessLevel.Player)
                                continue;

                            if (mob is PlayerMobile || (mob is BaseCreature && ((BaseCreature)mob).GetMaster() is PlayerMobile) && CanBeHarmful(mob))
                                list.Add(mob);
                        }

                        list.ForEach(mob =>
                            {
                                AOS.Damage(mob, this, Utility.RandomMinMax(80, 90), 0, 0, 0, 0, 0, 100, 0);
                            });

                        list.Clear();
                        list.TrimExcess();
                    }
                });
        }

        public override void GenerateLoot()
        {
            AddLoot(LootPack.UltraRich, 2);
            AddLoot(LootPack.LootItemCallback(CheckAbilityLootItem, 100.0, Utility.RandomMinMax(10, 25), false, true));
        }

        protected Item CheckAbilityLootItem(IEntity e)
        {
            if (AbilityProfile != null && AbilityProfile.HasAbility(SpecialAbility.Heal))
            {
                return new Bandage();
            }

            return null;
        }

        public Invader(Serial serial)
            : base(serial)
        {
        }

        public override void Serialize(GenericWriter writer)
        {
            base.Serialize(writer);
            writer.Write(0);

            writer.Write((int)_Specialty);
            writer.Write((int)_InvasionType);
            writer.Write(_Sampire);
        }

        public override void Deserialize(GenericReader reader)
        {
            base.Deserialize(reader);
            int version = reader.ReadInt();

            _Specialty = (SkillName)reader.ReadInt();
            _InvasionType = (InvasionType)reader.ReadInt();
            _Sampire = reader.ReadBool();

            _NextSpecial = DateTime.UtcNow;
        }
    }

    public class InvaderCaptain : Invader
    {
        public override double MinSkill => 105.0;
        public override double MaxSkill => 130.0;
        public override int MinResist => 20;
        public override int MaxResist => 30;

        [Constructable]
        public InvaderCaptain(InvasionType type) : base(type)
        {
            SetStr(250);
            SetDex(SpellCaster ? 150 : 200);
            SetInt(SpellCaster ? 1000 : 5000);

            SetHits(8000, 12000);

            if (AI == AIType.AI_Melee)
                SetDamage(22, 30);
            else if (!SpellCaster)
                SetDamage(20, 28);
            else
                SetDamage(10, 20);

            Fame = 48000;
            Karma = -48000;
        }

        public override void OnDeath(Container c)
        {
            base.OnDeath(c);

            List<DamageStore> rights = GetLootingRights();
            rights.Sort();

            List<Mobile> list = rights.Select(x => x.m_Mobile).Where(m => m.InRange(c.Location, 20)).ToList();

            if (list.Count > 0)
            {
                for (int i = 0; i < 2; i++)
                {
                    Mobile drop;
                    Item item = InvasionController.CreateItem(list[0]);

                    if (list.Count == 1 || i >= list.Count)
                        drop = list[0];
                    else
                        drop = list[i];

                    drop.SendLocalizedMessage(1154530); // You notice the crest of Minax on your fallen foe's equipment and decide it may be of some value...

                    if (drop.Backpack == null || !drop.Backpack.TryDropItem(drop, item, false))
                    {
                        drop.BankBox.DropItem(item);
                        drop.SendLocalizedMessage(1079730); // // The item has been placed into your bank box.
                    }
                }
            }

            ColUtility.Free(list);
        }

        public override void GenerateLoot()
        {
            AddLoot(LootPack.UltraRich, 2);
            AddLoot(LootPack.SuperBoss, 1);
        }

        public InvaderCaptain(Serial serial)
            : base(serial)
        {
        }

        public override void Serialize(GenericWriter writer)
        {
            base.Serialize(writer);
            writer.Write(0);
        }

        public override void Deserialize(GenericReader reader)
        {
            base.Deserialize(reader);
            int version = reader.ReadInt();
        }
    }
}
