using System;
using Server.Items;
using Server.Misc;
using Server.Targeting;

namespace Server.SkillHandlers
{
    public static class Begging
    {
        public static void Initialize()
        {
            SkillInfo.Table[(int)SkillName.Begging].Callback = OnUse;
        }

        public static TimeSpan OnUse(Mobile m)
        {
            m.RevealingAction();

            m.Target = new InternalTarget();
            m.RevealingAction();

            m.SendLocalizedMessage(500397); // To whom do you wish to grovel?

            return TimeSpan.FromSeconds(30.0);
        }

        private class InternalTarget : Target
        {
            public InternalTarget() : base(12, false, TargetFlags.None)
            {
            }

            protected override void OnTargetCancel(Mobile from, TargetCancelType cancelType)
            {
                from.NextSkillTime = Core.TickCount;
            }

            protected override void OnTarget(Mobile from, object targeted)
            {
                if (targeted is not Mobile targ)
                {
                    from.SendLocalizedMessage(500399); // There is little chance of getting money from that!
                }
                else if (targ.Player) // We can't beg from players
                {
                    from.SendLocalizedMessage(500398); // Perhaps just asking would work better.
                }
                else if (!targ.Body.IsHuman) // Make sure the NPC is human
                {
                    from.SendLocalizedMessage(500399); // There is little chance of getting money from that!
                }
                else if (!from.InRange(targ, 2))
                {
                    if (!targ.Female)
                    {
                        from.SendLocalizedMessage(500401); // You are too far away to beg from him.
                    }
                    else
                    {
                        from.SendLocalizedMessage(500402); // You are too far away to beg from her.
                    }
                }
                // If we're on a mount, who would give us money? TODO: guessed it's removed since ML
                else if (!Core.ML && from.Mounted)
                {
                    from.SendLocalizedMessage(500404); // They seem unwilling to give you any money.
                }
                else
                {
                    from.RevealingAction();

                    // Face each other
                    from.Direction = from.GetDirectionTo(targ);
                    targ.Direction = targ.GetDirectionTo(from);

                    from.Animate(32, 5, 1, true, false, 0); // Bow

                    new InternalTimer(from, targ).Start();
                    return;
                }

                from.NextSkillTime = Core.TickCount;
            }

            private class InternalTimer : Timer
            {
                private readonly Mobile _from;
                private readonly Mobile _target;

                public InternalTimer(Mobile from, Mobile target) : base(TimeSpan.FromSeconds(2.0))
                {
                    _from = from;
                    _target = target;
                }

                protected override void OnTick()
                {
                    var theirPack = _target.Backpack;

                    var badKarmaChance = 0.5 - (double)_from.Karma / 8570;

                    if (theirPack == null)
                    {
                        _from.SendLocalizedMessage(500404); // They seem unwilling to give you any money.
                    }
                    else if (_from.Karma < 0 && badKarmaChance > Utility.RandomDouble())
                    {
                        // Thou dost not look trustworthy... no gold for thee today!
                        _target.PublicOverheadMessage(MessageType.Regular, _target.SpeechHue, 500406);
                    }
                    else if (_from.CheckTargetSkill(SkillName.Begging, _target, 0.0, 100.0))
                    {
                        var toConsume = theirPack.GetAmount(typeof(Gold)) / 10;
                        var max = Math.Clamp(10 + _from.Fame / 2500, 10, 14);

                        if (toConsume > max)
                        {
                            toConsume = max;
                        }

                        if (toConsume > 0)
                        {
                            var consumed = theirPack.ConsumeUpTo(typeof(Gold), toConsume);

                            if (consumed > 0)
                            {
                                // I feel sorry for thee...
                                _target.PublicOverheadMessage(MessageType.Regular, _target.SpeechHue, 500405);

                                var gold = new Gold(consumed);

                                _from.AddToBackpack(gold);
                                _from.PlaySound(gold.GetDropSound());

                                if (_from.Karma > -3000)
                                {
                                    var toLose = _from.Karma + 3000;

                                    if (toLose > 40)
                                    {
                                        toLose = 40;
                                    }

                                    Titles.AwardKarma(_from, -toLose, true);
                                }
                            }
                            else
                            {
                                // I have not enough money to give thee any!
                                _target.PublicOverheadMessage(MessageType.Regular, _target.SpeechHue, 500407);
                            }
                        }
                        else
                        {
                            // I have not enough money to give thee any!
                            _target.PublicOverheadMessage(MessageType.Regular, _target.SpeechHue, 500407);
                        }
                    }
                    else
                    {
                        _target.SendLocalizedMessage(500404); // They seem unwilling to give you any money.
                    }

                    const int TargeterCooldown = 30000; // 30s
                    const int SkillCooldown = 10000;    // 10s

                    // Calculate how much time has passed since the targeter was opened
                    var ticksSinceTargeter = (int)(Core.TickCount - (_from.NextSkillTime - TargeterCooldown));
                    var remainingCooldown = Math.Max(0, SkillCooldown - ticksSinceTargeter);
                    _from.NextSkillTime = Core.TickCount + remainingCooldown;
                }
            }
        }
    }
}
