using PkmnLib.Static.Moves;

namespace PkmnLib.Plugin.Gen7.Scripts.Side;

/// <summary>
/// This move reduces damage from physical and special moves for five turns. This can be used only in a hailstorm. 
/// </summary>
/// <remarks>
/// Aurora Veil reduces the damage done to the user by physical and special moves for five turns by half; in battles
/// beside Single Battles, Aurora Veil protects the user and all allies, but only reduces damage by (roughly) a third
/// rather than half (specifically, with a multiplier of 2732/4096). It does not reduce damage done by self-inflicted
/// confusion damage, critical hits, or moves that deal direct damage. Aurora Veil can only be used during hail or snow,
/// but the effect remains even after hail or snow ends; Cloud Nine and Air Lock will cause Aurora Veil to fail even if
/// it is hailing or snowing.
/// <br/>
/// While it can be active at the same time as Reflect and Light Screen, the damage reduction effects do not stack.
/// Aurora Veil is removed from a Pokémon's side of the field if it is hit by Brick Break, Defog, Psychic Fangs, or
/// Raging Bull, or if a Pokémon with Screen Cleaner is sent out. Pokémon with the Ability Infiltrator ignore the effects
/// of Aurora Veil when attacking.
/// <br/>
/// If a Light Clay is held when Aurora Veil is used, it will extend the duration of Aurora Veil from 5 to 8 turns. 
/// </remarks>
[Script(ScriptCategory.Side, "aurora_veil")]
public class AuroraVeilEffect : Script, IScriptChangeIncomingMoveDamage, IScriptOnEndTurn
{
    public int NumberOfTurns { get; set; }

    private AuroraVeilEffect()
    {
    }

    public AuroraVeilEffect(int numberOfTurns)
    {
        NumberOfTurns = numberOfTurns;
    }

    /// <param name="owner"></param>
    /// <param name="battle"></param>
    /// <inheritdoc />
    public void OnEndTurn(IScriptSource owner, IBattle battle)
    {
        if (NumberOfTurns > 0)
            NumberOfTurns--;
        if (NumberOfTurns == 0)
            RemoveSelf();
    }

    /// <inheritdoc />
    public void ChangeIncomingMoveDamage(IExecutingMove move, IPokemon target, byte hit, ref uint damage)
    {
        var hitData = move.GetHitData(target, hit);
        if (hitData.IsCritical)
            return;
        if (move.User.BattleData?.SideIndex == target.BattleData?.SideIndex)
            return;
        var targetSide = target.BattleData?.SideIndex;
        if (targetSide == null)
            return;
        var side = move.User.BattleData!.Battle.Sides[targetSide.Value];
        switch (move.UseMove.Category)
        {
            case MoveCategory.Physical when side.VolatileScripts.Contains(ScriptUtils.ResolveName<ReflectEffect>()):
            case MoveCategory.Special when side.VolatileScripts.Contains(ScriptUtils.ResolveName<LightScreenEffect>()):
                return;
        }

        var modifier = 0.5f;
        if (target.BattleData!.Battle.PositionsPerSide > 1)
            modifier = 2732f / 4096f;
        damage = (uint)(damage * modifier);
    }
}