namespace PkmnLib.Plugin.Gen7.Scripts.Pokemon;

[Script(ScriptCategory.Pokemon, "whirlpool")]
public class WhirlpoolEffect : Script, IScriptOnEndTurn, IScriptPreventOpponentRunAway, IScriptPreventOpponentSwitch,
    IAIInfoScriptExpectedEndOfTurnDamage
{
    public record PokemonTurn
    {
        public PokemonTurn(IPokemon pokemon, int turns, float damagePercent)
        {
            Pokemon = pokemon;
            Turns = turns;
            DamagePercent = damagePercent;
        }

        public IPokemon Pokemon { get; }
        public int Turns { get; set; }
        public float DamagePercent { get; }
    }

    private IPokemon? _user;
    private readonly IList<PokemonTurn> _targetedPokemon = [];

    /// <inheritdoc />
    public override void OnAddedToParent(IScriptSource source)
    {
        if (source is IPokemon pokemon)
        {
            _user = pokemon;
        }
        else
        {
            throw new InvalidOperationException("WhirlpoolEffect can only be added to a Pokemon.");
        }
    }

    public void AddTargetedPokemon(IPokemon pokemon, int turns, float damagePercent)
    {
        if (_targetedPokemon.All(x => x.Pokemon != pokemon))
        {
            _targetedPokemon.Add(new PokemonTurn(pokemon, turns, damagePercent));
        }
    }

    /// <inheritdoc />
    public void PreventOpponentRunAway(IFleeChoice choice, ref bool prevent)
    {
        if (_targetedPokemon.Any(x => x.Pokemon == choice.User))
            prevent = true;
    }

    /// <inheritdoc />
    public void PreventOpponentSwitch(ISwitchChoice choice, ref bool prevent)
    {
        if (_targetedPokemon.Any(x => x.Pokemon == choice.User))
            prevent = true;
    }

    /// <inheritdoc />
    public void OnEndTurn(IScriptSource owner, IBattle battle)
    {
        if (_user == null)
            return;

        List<PokemonTurn>? pokemonToRemove = null;
        foreach (var pokemonTurn in _targetedPokemon.Where(x => x.Pokemon.BattleData?.IsOnBattlefield == true))
        {
            var pokemon = pokemonTurn.Pokemon;
            pokemon.Damage((uint)(pokemon.MaxHealth * pokemonTurn.DamagePercent), DamageSource.Misc);
            pokemonTurn.Turns--;
            if (pokemonTurn.Turns <= 0)
            {
                pokemonToRemove ??= [];
                pokemonToRemove.Add(pokemonTurn);
            }
        }
        if (pokemonToRemove == null)
            return;
        foreach (var turn in pokemonToRemove)
        {
            _targetedPokemon.Remove(turn);
        }
    }

    /// <inheritdoc />
    public void ExpectedEndOfTurnDamage(IPokemon pokemon, ref int damage)
    {
        var turn = _targetedPokemon.FirstOrDefault(x => x.Pokemon == pokemon);
        if (turn != null)
        {
            damage += (int)(pokemon.MaxHealth * turn.DamagePercent);
        }
    }
}