using Server.ContextMenus;
using Server.Engines.Quests;
using Server.Items;
using Server.SkillHandlers;

using System;
using System.Collections.Generic;

namespace Server.Mobiles
{
    [CorpseName("a wisp corpse")]
    public class MysteriousWisp : BaseCreature
    {
        public static readonly int MinBudget = 300;
        public static readonly int MaxBudget = 600;
        public static readonly int ItemCount = 10;

        [CommandProperty(AccessLevel.GameMaster)]
        public bool ForceRestock { get { return false; } set { if (value) DoRestock(true); } }

        private readonly Dictionary<Mobile, int> m_Conversation = new Dictionary<Mobile, int>();

        [Constructable]
        public MysteriousWisp()
            : base(AIType.AI_Mage, FightMode.None, 10, 1, 0.2, 0.4)
        {
            CantWalk = true;
            Blessed = true;
            SpeechHue = 52;

            Name = "a mysterious wisp";
            Body = 58;
            BaseSoundID = 466;

            SetStr(196, 225);
            SetDex(196, 225);
            SetInt(196, 225);

            SetHits(118, 135);

            SetDamage(17, 18);

            SetDamageType(ResistanceType.Physical, 50);
            SetDamageType(ResistanceType.Energy, 50);

            SetResistance(ResistanceType.Physical, 35, 45);
            SetResistance(ResistanceType.Fire, 20, 40);
            SetResistance(ResistanceType.Cold, 10, 30);
            SetResistance(ResistanceType.Poison, 5, 10);
            SetResistance(ResistanceType.Energy, 50, 70);

            SetSkill(SkillName.EvalInt, 80.0);
            SetSkill(SkillName.Magery, 80.0);
            SetSkill(SkillName.MagicResist, 80.0);
            SetSkill(SkillName.Tactics, 80.0);
            SetSkill(SkillName.Wrestling, 80.0);

            if (Backpack != null)
                Backpack.Delete();

            DoRestock();
        }

        public override bool HandlesOnSpeech(Mobile from)
        {
            return m_Conversation.ContainsKey(from);
        }

        public override void OnDoubleClick(Mobile from)
        {
            if (from.InRange(Location, 4))
            {
                if (!m_Conversation.ContainsKey(from))
                {
                    SayTo(from, m_Responses[0]);
                    m_Conversation[from] = 1;
                }

                if (Backpack != null)
                {
                    Backpack.DisplayTo(from);
                }
            }

            if (from is PlayerMobile pm && QuestHelper.CheckDoneOnce(pm, typeof(WishesOfTheWispQuest), null, false))
            {
                WhisperingWithWispsQuest q = QuestHelper.GetQuest<WhisperingWithWispsQuest>(pm);

                if (q == null)
                {
                    BaseQuest quest = QuestHelper.RandomQuest(pm, new Type[] { typeof(WhisperingWithWispsQuest) }, this);

                    if (quest != null)
                    {
                        pm.CloseGump(typeof(MondainQuestGump));
                        pm.SendGump(new MondainQuestGump(quest));
                    }
                }
                else if (q.Completed)
                {
                    q.CompleteQuest();
                }           
            }
        }

        public override void OnMovement(Mobile m, Point3D oldLocation)
        {
            if (m is PlayerMobile && InRange(m.Location, 5) && !InRange(oldLocation, 5))
            {
                WishesOfTheWispQuest quest = QuestHelper.GetQuest<WishesOfTheWispQuest>((PlayerMobile)m);

                if (quest != null)
                {
                    quest.CompleteQuest();
                }
            }
        }

        public override void OnSpeech(SpeechEventArgs e)
        {
            if (!m_Conversation.ContainsKey(e.Mobile))
                return;

            string speech = e.Speech.ToLower();
            int idx = m_Conversation[e.Mobile];

            if (idx < 0 || idx >= m_Keywords.Length)
            {
                m_Conversation.Remove(e.Mobile);
                return;
            }

            foreach (string str in m_Keywords[idx])
            {
                if (speech.Contains(str))
                {
                    SayTo(e.Mobile, m_Responses[idx]);

                    if (idx + 1 >= m_Keywords.Length)
                        m_Conversation.Remove(e.Mobile);
                    else
                        m_Conversation[e.Mobile]++;

                    break;
                }
            }
        }

        private readonly string[][] m_Keywords = new string[][]
        {
            new string[] { },
            new string[] { "corporeal" },
            new string[] { "sentient" },
            new string[] { "deal" },
            new string[] { "learn", "teach" },
            new string[] { "good and evil", "good", "evil" },
            new string[] { "guide" },
            new string[] { "follow" },
            new string[] { "fight" },
            new string[] { "resonate" },
            new string[] { "join" },
            new string[] { "command" },
            new string[] { "trade" },
        };

        private readonly int[] m_Responses = new int[]
        {
            1153441,
            1153443,
            1153445,
            1153447,
            1153449,
            1153451,
            1153453,
            1153455,
            1153457,
            1153459,
            1153461,
            1153463,
            1153467
        };

        private void DoRestock()
        {
            DoRestock(false);
        }

        private void DoRestock(bool wipe)
        {
            int count;

            if (Backpack == null)
            {
                var pack = new BuyBackpack();

                AddItem(pack);
            }

            if (wipe)
            {
                count = ItemCount;
                ColUtility.SafeDelete(Backpack.Items);
            }
            else
            {
                count = ItemCount - Backpack.Items.Count;
            }

            if (count > 0)
            {
                for (var i = 0; i < count; i++)
                {
                    Item item;

                    switch (Utility.Random(3))
                    {
                        default:
                        case 0: item = Loot.RandomArmorOrShieldOrWeaponOrJewelry(false, false, true); break;
                        case 1: item = Loot.RandomArmorOrShieldOrWeaponOrJewelry(false, true, false); break;
                        case 2: item = Loot.RandomArmorOrShieldOrWeaponOrJewelry(true, false, false); break;
                    }

                    var failSafe = 0;
                    bool success = true;

                    do
                    {
                        RunicReforging.GenerateRandomItem(item, null, Utility.RandomMinMax(MinBudget, MaxBudget), 0, ReforgedPrefix.None, ReforgedSuffix.None);

                        if (++failSafe == 25 && Imbuing.GetTotalWeight(item, -1, false, true) == 0)
                        {
                            item.Delete();
                            success = false;
                            i--;
                            break;
                        }
                    }
                    while (Imbuing.GetTotalWeight(item, -1, false, true) == 0);

                    if (success)
                    {
                        item.Movable = false;
                        PackItem(item);
                    }
                }
            }
        }

        public int GetCostFor(Item item)
        {
            return (int)((double)Imbuing.GetTotalWeight(item, -1, false, true) * 2.18);
        }

        public void TryBuyItem(Mobile from, Item item)
        {
            if (item.Deleted || !Backpack.Items.Contains(item))
            {
                from.SendLocalizedMessage(1150244); // Transaction no longer available
                return;
            }

            int points = (int)Engines.Points.PointsSystem.DespiseCrystals.GetPoints(from);
            int cost = GetCostFor(item);

            if (points >= cost)
            {
                Engines.Points.PointsSystem.DespiseCrystals.DeductPoints(from, cost);
                item.Movable = true;

                if (from.Backpack == null || !from.Backpack.TryDropItem(from, item, false))
                {
                    item.MoveToWorld(from.Location, from.Map);
                }

                from.SendLocalizedMessage(1153431, cost.ToString()); // You purchase the item for ~1_AMT~ Despise Crystals.

                if (Backpack.Items.Count == 0)
                {
                    Timer.DelayCall(TimeSpan.FromSeconds(Utility.RandomMinMax(30, 180)), DoRestock);
                }
            }
            else
            {
                from.SendLocalizedMessage(1153430); // You cannot afford that
            }
        }

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

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

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

            if (version == 0)
            {
                reader.ReadInt();
                reader.ReadInt();
                reader.ReadInt();
                reader.ReadInt();
                reader.ReadDouble();
            }

            Timer.DelayCall(() => DoRestock(true));
        }

        public class BuyBackpack : Backpack
        {
            public BuyBackpack()
            {
                Movable = false;
                Layer = Layer.Backpack;
                Weight = 1.0;
            }

            public override int DefaultMaxWeight => 0;

            public override bool IsAccessibleTo(Mobile m)
            {
                return true;
            }

            public override void GetChildProperties(ObjectPropertyList list, Item item)
            {
                base.GetChildProperties(list, item);

                MysteriousWisp wisp = RootParent as MysteriousWisp;

                if (wisp == null)
                {
                    return;
                }

                list.Add(1153425, wisp.GetCostFor(item).ToString()); // Price: ~1_AMT~ Despise Crystals
            }

            public override void GetChildContextMenuEntries(Mobile from, List<ContextMenuEntry> list, Item item)
            {
                base.GetChildContextMenuEntries(from, list, item);

                list.Add(new SimpleContextMenuEntry<Item>(from, 1062219, (m, i) => // Buy
                {
                    var wisp = RootParent as MysteriousWisp;

                    if (wisp != null && i.IsChildOf(this))
                    {
                        wisp.TryBuyItem(m, i);
                    }
                },
                item, nonlocalUse: true));

                list.Add(new SimpleContextMenuEntry<Item>(from, 1153469, (m, i) => // Move
                {
                    if (i.IsChildOf(this))
                    {
                        DropItem(i);
                    }
                },
                item, nonlocalUse: true));
            }

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

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

                writer.Write(0); // version
            }

            public override void Deserialize(GenericReader reader)
            {
                base.Deserialize(reader);

                int version = reader.ReadInt();
            }
        }
    }
}