using System;
using Server;
using System.Collections.Generic;
using Server.ContextMenus;
using Server.Engines.Despise;
using Server.Items;
using Server.Gumps;
using Server.Network;
using Server.Engines.Quests;

namespace Server.Mobiles
{
    [CorpseName("a wisp corpse")]
    public class MysteriousWisp : BaseCreature
    {
        private int m_ItemCountMin;
        private int m_ItemCountMax;
        private int m_IntensityMin;
        private int m_IntensityMax;
        private int m_RestockMin;
        private int m_RestockMax;
        private double m_MutateChance;

        [CommandProperty(AccessLevel.GameMaster)]
        public int ItemCountMin { get { return m_ItemCountMin; } set { m_ItemCountMin = value; } }

        [CommandProperty(AccessLevel.GameMaster)]
        public int ItemCountMax { get { return m_ItemCountMax; } set { m_ItemCountMax = value; } }

        [CommandProperty(AccessLevel.GameMaster)]
        public int IntensityMin { get { return m_IntensityMin; } set { m_IntensityMin = value; } }

        [CommandProperty(AccessLevel.GameMaster)]
        public int IntensityMax { get { return m_IntensityMax; } set { m_IntensityMax = value; } }

        [CommandProperty(AccessLevel.GameMaster)]
        public int RestockMin { get { return m_RestockMin; } set { m_RestockMin = value; } }

        [CommandProperty(AccessLevel.GameMaster)]
        public int RestockMax { get { return m_RestockMax; } set { m_RestockMax = value; } }

        [CommandProperty(AccessLevel.GameMaster)]
        public double MutateChance { get { return m_MutateChance; } set { m_MutateChance = value; } }

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

        [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();

            m_ItemCountMin = 14;
            m_ItemCountMax = 20;
            m_IntensityMin = 40;
            m_IntensityMax = 100;
            m_RestockMin = 45;
            m_RestockMax = 65;
            m_MutateChance = 0.10;

            AddItem(new BuyBackpack());
            DoRestock();
        }

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

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

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

            if (from is PlayerMobile)
            {
                var pm = from as PlayerMobile;

                if (QuestHelper.CheckDoneOnce(pm, typeof(WishesOfTheWispQuest), null, false))
                {
                    var 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 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 int[] m_Responses = new int[]
        {
            1153441,
            1153443,
            1153445,
            1153447,
            1153449,
            1153451,
            1153453,
            1153455,
            1153457,
            1153459,
            1153461,
            1153463,
            1153467
        };

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

            list.Add(new InternalEntry(this, from));
        }

        private Dictionary<Item, int> m_ItemTable = new Dictionary<Item, int>();

        public void CheckRestock()
        {
            if (m_NextRestock <= DateTime.UtcNow)
                DoRestock();
        }

        private void DoRestock()
        {
            List<Item> list = new List<Item>(this.Backpack.Items);
            m_ItemTable.Clear();

            InternalGump.Clear();

            foreach (Item item in list)
                item.Delete();

            int count = Utility.RandomMinMax(m_ItemCountMin, m_ItemCountMax);

            for (int 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;
                }

                int weight = 0;

                if (0.10 > Utility.RandomDouble())
                {
                    int budget = Utility.RandomMinMax(500, 860);
                    RunicReforging.GenerateRandomItem(item, null, Utility.RandomMinMax(500, 860), 0, ReforgedPrefix.None, ReforgedSuffix.None);
                    weight += budget / 3;
                }
                else
                {
                    int props = Utility.RandomMinMax(3, 5);

                    if (props == 5 && 0.05 > Utility.RandomDouble())
                    {
                        props++;
                        weight += 100;
                    }

                    if (item is BaseWeapon)
                    {
                        BaseRunicTool.ApplyAttributesTo((BaseWeapon)item, false, 0, props, m_IntensityMin, m_IntensityMax);
                    }
                    else if (item is BaseArmor)
                    {
                        BaseRunicTool.ApplyAttributesTo((BaseArmor)item, false, 0, props, m_IntensityMin, m_IntensityMax);
                    }
                    else if (item is BaseJewel)
                    {
                        BaseRunicTool.ApplyAttributesTo((BaseJewel)item, false, 0, props, m_IntensityMin, m_IntensityMax);
                    }
                    else if (item is BaseHat)
                    {
                        BaseRunicTool.ApplyAttributesTo((BaseHat)item, false, 0, props, m_IntensityMin, m_IntensityMax);
                    }
                }

                m_ItemTable[item] = (int)((weight + Server.SkillHandlers.Imbuing.GetTotalWeight(item, -1, false, true)) * 31.5);
                item.Movable = false;
                this.Backpack.DropItem(item);
            }

            m_NextRestock = DateTime.UtcNow + TimeSpan.FromMinutes(Utility.RandomMinMax(m_RestockMin, m_RestockMax));
        }

        public int GetCostFor(Item item)
        {
            if (!m_ItemTable.ContainsKey(item))
                return -1;

            return m_ItemTable[item];
        }

        public void TryBuyItem(Mobile from, Item item)
        {
            if (item.Deleted || !this.Backpack.Items.Contains(item) || !m_ItemTable.ContainsKey(item))
            {
                from.SendMessage("This item is no longer available.");
                return;
            }

            int points = (int)Server.Engines.Points.PointsSystem.DespiseCrystals.GetPoints(from);
            int cost = m_ItemTable[item];

            if (points >= cost)
            {
                //DespiseController.Instance.DeductDespisePoints(from, cost);
                Server.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(1153427, cost.ToString()); // You have spent ~1_AMT~ Dungeon Crystal Points of Despise.

                InternalGump.Resend(this);
            }
            else
                from.SendMessage("You need {0} more Despise dungeon crystal points for this.", cost - points);
        }

        private class InternalEntry : ContextMenuEntry
        {
            private Mobile m_Clicker;
            private MysteriousWisp m_Wisp;

            public InternalEntry(MysteriousWisp wisp, Mobile clicker)
                : base(1150143, 3)
            {
                m_Clicker = clicker;
                m_Wisp = wisp;
            }

            public override void OnClick()
            {
                if (m_Clicker.Alive && !m_Wisp.Deleted && m_Clicker.InRange(m_Wisp.Location, 3))
                {
                    if (m_Wisp.Backpack == null)
                    {
                        Console.WriteLine("Error, wisp backpack is null");
                        return;
                    }

                    m_Wisp.CheckRestock();
                    m_Clicker.SendGump(new InternalGump(m_Wisp, m_Clicker));
                }
            }
        }

        private DateTime m_NextRestock;

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

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

            writer.Write(m_ItemCountMin);
            writer.Write(m_ItemCountMax);
            writer.Write(m_IntensityMin);
            writer.Write(m_IntensityMax);
            writer.Write(m_MutateChance);
        }

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

            m_ItemCountMin = reader.ReadInt();
            m_ItemCountMax = reader.ReadInt();
            m_IntensityMin = reader.ReadInt();
            m_IntensityMax = reader.ReadInt();
            m_MutateChance = reader.ReadDouble();

            m_NextRestock = DateTime.UtcNow;
        }

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

            public override int DefaultMaxWeight { get { return 0; } }

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

            public override bool CheckItemUse(Mobile from, Item item)
            {
                from.SendLocalizedMessage(500447); // That is not accessible.
                return false;
            }

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

                MysteriousWisp wisp = RootParent as MysteriousWisp;

                if (wisp == null)
                    return;

                int cost = wisp.GetCostFor(item);

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

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

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

                writer.Write((int)0); // version
            }

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

                int version = reader.ReadInt();
            }
        }

        private class InternalGump : Gump
        {
            private static List<Mobile> m_Viewers = new List<Mobile>();

            private MysteriousWisp m_Wisp;
            private List<Item> m_Items;

            public InternalGump(MysteriousWisp wisp, Mobile viewer) : base(40, 40)
            {
                m_Wisp = wisp;
                if (!m_Viewers.Contains(viewer))
                    m_Viewers.Add(viewer);

                AddBackground(0, 0, 320, 404, 0x13BE);
                AddImageTiled(10, 10, 300, 20, 0xA40);
                AddImageTiled(10, 40, 300, 324, 0xA40);
                AddImageTiled(10, 374, 300, 20, 0xA40);
                AddAlphaRegion(10, 10, 300, 384);

                AddHtml(14, 12, 500, 20, "<BASEFONT COLOR=#FFFFFF>Mysterious Wisp Inventory</BASEFONT>", false, false);

                AddButton(10, 374, 0xFB1, 0xFB2, 0, GumpButtonType.Reply, 0);
                AddHtmlLocalized(45, 376, 450, 20, 1011012, 0x7FFF, false, false); // CANCEL

                m_Items = new List<Item>(m_Wisp.Backpack.Items);
                int current = 0;

                for (int i = 0; i < m_Items.Count; i++)
                {
                    Item item = m_Items[i];

                    int page = current / 5 + 1;
                    int pos = current % 5;

                    if (pos == 0)
                    {
                        if (page > 1)
                        {
                            AddButton(200, 374, 0xFA5, 0xFA7, 0, GumpButtonType.Page, page);
                            AddHtmlLocalized(240, 376, 60, 20, 1043353, 0x7FFF, false, false); // Next
                        }

                        AddPage(page);

                        if (page > 1)
                        {
                            AddButton(100, 374, 0xFAE, 0xFB0, 0, GumpButtonType.Page, page - 1);
                            AddHtmlLocalized(140, 376, 60, 20, 1011393, 0x7FFF, false, false); // Back
                        }
                    }

                    if (item != null && !item.Deleted)
                    {
                        int x = 14;
                        int y = (pos * 64) + 44;

                        Rectangle2D b = ItemBounds.Table[item.ItemID];

                        AddImageTiledButton(x, y, 0x918, 0x919, i + 1, GumpButtonType.Reply, 0, item.ItemID, item.Hue, 40 - b.Width / 2 - b.X, 30 - b.Height / 2 - b.Y);
                        AddItemProperty(item.Serial);

                        string cost = m_Wisp.GetCostFor(item) > -1 ? m_Wisp.GetCostFor(item).ToString("###,###,###") : "No Longer Available";

                        AddHtmlLocalized(x + 84, y, 250, 60, item.LabelNumber, 0x7FFF, false, false);
                        AddHtml(x + 84, y + 20, 250, 60, "<BASEFONT COLOR=#FFFFFF>" + cost + "</BASEFONT>", false, false);

                        current++;
                    }
                }
            }

            public override void OnResponse(NetState state, RelayInfo info)
            {
                Mobile from = state.Mobile;

                if (m_Viewers.Contains(from))
                    m_Viewers.Remove(from);

                int idx = info.ButtonID - 1;

                if (idx >= 0 && idx < m_Items.Count)
                {
                    Item item = m_Items[idx];

                    if (item != null && !item.Deleted && m_Wisp.Backpack != null && m_Wisp.Backpack.Items.Contains(item))
                    {
                        from.SendGump(new InternalGump2(m_Wisp, item));
                    }
                }
            }

            public static void Resend(MysteriousWisp wisp)
            {
                if (m_Viewers == null || m_Viewers.Count == 0)
                    return;

                List<Mobile> viewers = new List<Mobile>(m_Viewers);
                Type t = typeof(Server.Mobiles.MysteriousWisp.InternalGump);

                foreach (Mobile m in viewers)
                {
                    if (m.HasGump(t))
                    {
                        m.CloseGump(t);

                        if (m_Viewers.Contains(m))
                            m_Viewers.Remove(m);

                        if(wisp.InRange(m.Location, 5) && wisp.Backpack != null)
                            m.SendGump(new InternalGump(wisp, m));
                    }
                }
            }

            public static void Clear()
            {
                if (m_Viewers == null || m_Viewers.Count == 0)
                    return;

                List<Mobile> viewers = new List<Mobile>(m_Viewers);
                Type t = typeof(Server.Mobiles.MysteriousWisp.InternalGump);

                foreach (Mobile m in viewers)
                {
                    if (m.HasGump(t))
                        m.CloseGump(t);
                }

                m_Viewers.Clear();
            }
        }

        private class InternalGump2 : Gump
        {
            private MysteriousWisp m_Wisp;
            private Item m_Item;
            private bool m_Available;

            public InternalGump2(MysteriousWisp wisp, Item item) : base(40, 40)
            {
                m_Wisp = wisp;
                m_Item = item;

                AddImageTiled(0, 0, 300, 180, 0xA8E);
                AddAlphaRegion(0, 0, 300, 180);
                AddBackground(150, 10, 130, 130, 0xBB8);

                AddHtml(10, 10, 150, 20, "<BASEFONT COLOR=#FFFFFF>CONFIRM PURCHASE:</BASEFONT>", false, false);
                AddHtmlLocalized(10, 30, 140, 20, item.LabelNumber, 0x7FFF, false, false);

                m_Available = m_Wisp.GetCostFor(item) > -1;
                string cost = m_Available ? m_Wisp.GetCostFor(item).ToString() : "No Longer Available";

                AddHtml(10, 100, 140, 20, "<BASEFONT COLOR=#FFFFFF>Despise Crystals:</BASEFONT>", false, false);
                AddHtml(10, 120, 140, 20, "<BASEFONT COLOR=#FFFFFF>"+cost+"</BASEFONT>", false, false);

                Rectangle2D b = ItemBounds.Table[item.ItemID];
                AddItem(210 - b.Width / 2 - b.X, 70 - b.Height / 2 - b.Y, item.ItemID, item.Hue);
                AddItemProperty(item.Serial);

                if (m_Available)
                    AddButton(90, 150, 2128, 2129, 1, GumpButtonType.Reply, 0);

                AddButton(155, 150, 2119, 2120, 0, GumpButtonType.Reply, 0);
            }

            public override void OnResponse(NetState state, RelayInfo info)
            {
                Mobile from = state.Mobile;

                if (info.ButtonID == 1)
                {
                    if (m_Available)
                        m_Wisp.TryBuyItem(from, m_Item);
                    else
                        from.SendMessage("That item is no longer available");
                }
            }
        }
    }
}
