using System;
using Server.Items;

namespace Server.Spells.Mysticism;

public abstract class MysticSpell : Spell
{
    private static int[] _manaTable = { 4, 6, 9, 11, 14, 20, 40, 50 };
    private static double[] _requiredSkill = { 0.0, 8.0, 20.0, 33.0, 45.0, 58.0, 70.0, 83.0 };

    public MysticSpell(Mobile caster, Item scroll, SpellInfo info) : base(caster, scroll, info)
    {
    }

    public abstract SpellCircle Circle { get; }

    public override TimeSpan CastDelayBase => TimeSpan.FromSeconds(0.5 + 0.25 * (int)Circle);

    public virtual double RequiredSkill
    {
        get
        {
            var circle = (int)Circle;

            if (Scroll != null)
            {
                circle -= 2;
            }

            return _requiredSkill[circle];
        }
    }

    public override SkillName CastSkill => SkillName.Mysticism;

    /*
     * As per OSI Publish 64:
     * Imbuing is not the only skill associated with Mysticism now.
     * Players can use EITHER their Focus skill or Imbuing skill.
     * Evaluate Intelligence no longer has any effect on a Mystic’s spell power.
     */
    public override double GetDamageSkill(Mobile m) => Math.Max(m.Skills.Imbuing.Value, m.Skills.Focus.Value);

    public override int GetDamageFixed(Mobile m) => Math.Max(m.Skills.Imbuing.Fixed, m.Skills.Focus.Fixed);

    public override void GetCastSkills(out double min, out double max)
    {
        var requiredSkill = RequiredSkill;

        // As per Mysticism page at the UO Herald Playguide
        // This means that we have 25% success chance at min Required Skill
        min = requiredSkill - 12.5;
        max = requiredSkill + 37.5;
    }

    public override int GetMana() => Scroll is BaseWand ? 0 : _manaTable[(int)Circle];

    public override bool CheckCast()
    {
        if (!base.CheckCast())
        {
            return false;
        }

        var mana = ScaleMana(GetMana());

        if (Caster.Mana < mana)
        {
            // You must have at least ~1_MANA_REQUIREMENT~ Mana to use this ability.
            Caster.SendLocalizedMessage(1060174, mana.ToString());
            return false;
        }

        var requiredSkill = RequiredSkill;

        if (Caster.Skills[CastSkill].Value < requiredSkill)
        {
            // You need at least ~1_SKILL_REQUIREMENT~ ~2_SKILL_NAME~ skill to use that ability.
            Caster.SendLocalizedMessage(1063013, $"{requiredSkill:F1}\t{CastSkill}\t ");
            return false;
        }

        return true;
    }

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

        SendCastEffect();
    }

    public virtual void SendCastEffect()
    {
        Caster.FixedEffect(0x37C4, 10, (int)(GetCastDelay().TotalSeconds * 28), 0x66C, 3);
    }

    public static double GetBaseSkill(Mobile m) => m.Skills.Mysticism.Value;

    public virtual bool CheckResisted(Mobile target)
    {
        var n = GetResistPercent(target);

        n /= 100.0;

        if (n <= 0.0)
        {
            return false;
        }

        if (n >= 1.0)
        {
            return true;
        }

        var maxSkill = (1 + (int)Circle) * 10;
        maxSkill += (1 + (int)Circle / 6) * 25;

        if (target.Skills.MagicResist.Value < maxSkill)
        {
            target.CheckSkill(SkillName.MagicResist, 0.0, target.Skills.MagicResist.Cap);
        }

        return n >= Utility.RandomDouble();
    }

    public virtual double GetResistPercentForCircle(Mobile target, SpellCircle circle)
    {
        var magicResist = target.Skills.MagicResist.Value;
        var firstPercent = magicResist / 5.0;
        var secondPercent = magicResist -
                            ((Caster.Skills[CastSkill].Value - 20.0) / 5.0 + (1 + (int)circle) * 5.0);

        // Seems should be about half of what stratics says.
        return (firstPercent > secondPercent ? firstPercent : secondPercent) / 2.0;
    }

    public virtual double GetResistPercent(Mobile target) => GetResistPercentForCircle(target, Circle);
}