using System;
using System.Collections.Generic;
using Server;
using Server.Mobiles;
using Server.Items;

namespace Server.Regions
{
    public static class CustomDungeonTraps
    {
        private static Dictionary<PlayerMobile, Timer> m_KarmaTimers = new Dictionary<PlayerMobile, Timer>();

        public static bool SavingThrow(PlayerMobile pm, string saveType)
        {
            int saveThrow = 0;
            string area = "";

            if (saveType == "Magic")
            {
                area = "magical resistance";
                saveThrow = (int)((pm.Int + pm.Skills[SkillName.MagicResist].Value + pm.EnergyResistance) / 4);
            }
            else if (saveType == "Physical")
            {
                area = "physical endurance";
                saveThrow = (int)((pm.Str + pm.PhysicalResistance) / 3);
            }
            else if (saveType == "Agility")
            {
                area = "quick reflexes";
                saveThrow = pm.Dex;
            }
            else if (saveType == "Poison")
            {
                area = "poison resistance";
                saveThrow = (int)((pm.Str + pm.Skills[SkillName.Poisoning].Value + pm.PoisonResistance) / 4);
            }

            // Cap the maximum possible save chance at 60% 
            if (saveThrow > 60)
            {
                saveThrow = 60;
            }

            // If their save score is higher than a random 1-100 roll, they succeed!
            if (saveThrow >= Utility.RandomMinMax(1, 100))
            {
                pm.LocalOverheadMessage(Server.Network.MessageType.Emote, 0x3B2, false, "You triggered a trap, but with your " + area + "...you avoid the brunt of it.");
                pm.PlaySound(pm.Female ? 778 : 1049);
                return true; 
            }

            return false;
        }

        public static void TriggerRandomTrap(PlayerMobile pm)
        {
            // Increase this number as you add more cases below!
            int roll = Utility.Random(6); 

            switch (roll)
            {
                case 0: ApplyPotionBreakTrap(pm); break;
                case 1: ApplySpikeTrap(pm); break;
                case 2: ApplyGasTrap(pm); break;
                case 3: ApplyTripWireTrap(pm); break;
                case 4: ApplyTransmutationTrap(pm); break;
                case 5: ApplyKarmaTrap(pm); break;
            }
        }

        public static void ApplyPotionBreakTrap(PlayerMobile pm)
        {
            if (SavingThrow(pm, "Agility"))
                return;

            pm.PlaySound(0x38D); 

            if (pm.Backpack != null)
            {
                List<BasePotion> potions = pm.Backpack.FindItemsByType<BasePotion>();

                if (potions.Count > 0)
                {
                    BasePotion targetPotion = potions[Utility.Random(potions.Count)];
                    targetPotion.Consume(1);
                    
                    pm.FixedParticles(0x374A, 10, 15, 5021, EffectLayer.Waist);
                    pm.SendMessage(33, "A concealed tripwire snaps! A flask in your backpack breaks!");
                    return;
                }
            }

            pm.Damage(Utility.RandomMinMax(10, 20));
            pm.SendMessage(33, "You trip over a hidden wire and take a nasty spill!");
        }

        public static void ApplySpikeTrap(PlayerMobile pm)
        {
            if (SavingThrow(pm, "Physical"))
                return;
            pm.PlaySound(0x22C);
            pm.FixedParticles(0x3728, 10, 10, 5021, EffectLayer.Waist);
            pm.Damage(Utility.RandomMinMax(15, 30));
            pm.SendMessage(33, "Spikes spring from the floor!");
        }

        public static void ApplyGasTrap(PlayerMobile pm)
        {
            if (SavingThrow(pm, "Poison"))
                return;
            pm.PlaySound(0x231);
            pm.FixedParticles(0x3709, 10, 30, 5052, EffectLayer.Waist);
            pm.ApplyPoison(pm, Poison.Regular);
            pm.SendMessage(33, "You trigger a noxious gas vent!");
        }
        public static void ApplyTripWireTrap(PlayerMobile pm)
        {
            if (SavingThrow(pm, "Agility"))
                return;

            pm.PlaySound(pm.Female ? 812 : 1086);

            Item dropped = GetRandomEquippedItem(pm);

            if (dropped != null && dropped.LootType != LootType.Blessed)
            {
                // Drops it right at their feet
                dropped.MoveToWorld(pm.Location, pm.Map);
                pm.LocalOverheadMessage(Server.Network.MessageType.Emote, 33, true, "You tripped over a wire and dropped one of your equipped items!");
            }
            else
            {
                // Fallback if they are completely naked or only have blessed gear
                pm.Damage(Utility.RandomMinMax(5, 10));
                pm.SendMessage(33, "You trip over a hidden wire and take a nasty spill!");
            }
        }

        private static Item GetRandomEquippedItem(PlayerMobile pm)
        {
            List<Item> wornItems = new List<Item>();

            Layer[] validLayers = { Layer.OneHanded, Layer.TwoHanded, Layer.Helm, Layer.Neck, Layer.Arms, Layer.Gloves, Layer.Ring, Layer.Bracelet, Layer.Shoes };
            
            foreach (Layer layer in validLayers)
            {
                Item item = pm.FindItemOnLayer(layer);

                if (item != null && item.LootType != LootType.Blessed)
                {
                    wornItems.Add(item);
                }
            }

            if (wornItems.Count == 0)
            {
                return null;
            }
            return wornItems[Utility.Random(wornItems.Count)];
        }

        public static void ApplyTransmutationTrap(PlayerMobile pm)
        {
            if (SavingThrow(pm, "Magic"))
                return;

            if (pm.Backpack != null)
            {
                int goldAmount = pm.Backpack.GetAmount(typeof(Gold));

                if (goldAmount > 0)
                {
                    // Calculate a 10% to 25% tax on their gold
                    int goldToDestroy = (int)(goldAmount * Utility.RandomMinMax(10, 25) / 100.0);
                    
                    if (goldToDestroy > 0 && pm.Backpack.ConsumeTotal(typeof(Gold), goldToDestroy))
                    {
                        pm.PlaySound(0x1E1);
                        pm.FixedParticles(0x374A, 10, 15, 5028, EffectLayer.Waist);
                        pm.LocalOverheadMessage(Server.Network.MessageType.Emote, 33, true, "A magical trap triggers, turning a chunk of your gold into useless dust!");
                        return;
                    }
                }
            }

            // Fallback if they have zero gold
            pm.PlaySound(0x1DF);
            pm.Mana -= 20;
            pm.SendMessage(33, "A magical trap drains your mana!");
        }

        public static void ApplyKarmaTrap(PlayerMobile pm)
        {
            if (SavingThrow(pm, "Magic"))
                return;

            if (pm.Karma == 0)
            {
                pm.PlaySound(0x1DF);
                pm.Mana -= 20;
                pm.SendMessage(33, "A dark energy washes over you, draining your mana!");
                return;
            }

            KarmaCurseToken token = pm.Backpack.FindItemByType<KarmaCurseToken>();

            if (token == null)
            {
                pm.Karma *= -1; 
                pm.PlaySound(0x1E1); 
                pm.FixedParticles(0x374A, 10, 15, 5028, EffectLayer.Waist);
                pm.LocalOverheadMessage(Server.Network.MessageType.Emote, 33, true, "A mind-warping trap triggers, completely inverting your morality!");

                token = new KarmaCurseToken(pm, TimeSpan.FromMinutes(3));
                pm.Backpack.DropItem(token);
            }
            else
            {
                token.ExtendCurse(TimeSpan.FromMinutes(5));
                pm.SendMessage(33, "The mind-warping curse intensifies, extending its duration!");
            }
        }
    }
    public class KarmaCurseToken : Item
    {
        private Mobile m_Owner;
        private DateTime m_Expires;
        private Timer m_Timer;

        public KarmaCurseToken(Mobile owner, TimeSpan duration) : base(0x1EA7)
        {
            Movable = false;
            Visible = false;
            Weight = 0.0;
            m_Owner = owner;
            m_Expires = DateTime.UtcNow + duration;

            StartTimer();
        }

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

        private void StartTimer()
        {
            if (m_Timer != null)
                m_Timer.Stop();

            TimeSpan delay = m_Expires - DateTime.UtcNow;

            if (delay <= TimeSpan.Zero)
            {
                RemoveCurse();
            }
            else
            {
                m_Timer = Timer.DelayCall(delay, RemoveCurse);
            }
        }

        public void ExtendCurse(TimeSpan duration)
        {
            m_Expires = DateTime.UtcNow + duration;
            StartTimer();
        }

        private void RemoveCurse()
        {
            if (m_Owner != null && !m_Owner.Deleted)
            {
                m_Owner.Karma *= -1;
                m_Owner.SendMessage(0x3B2, "The morality-warping curse fades, and your true nature returns.");
            }

            if (m_Timer != null)
                m_Timer.Stop();

            Delete();
        }

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

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

            StartTimer(); 
        }
    }
}
