using System.Diagnostics.CodeAnalysis;
using PkmnLib.Dynamic.BattleFlow;

namespace PkmnLib.Plugin.Gen7.Scripts.Battle;

[Script(ScriptCategory.Battle, "snatch_effect")]
public class SnatchEffect : Script, IScriptStopBeforeMove, IScriptOnEndTurn
{
    private Queue<IPokemon> _snatchers = new();

    public void AddSnatcher(IPokemon snatcher)
    {
        if (_snatchers.Contains(snatcher))
        {
            _snatchers = new Queue<IPokemon>(_snatchers.Where(s => s != snatcher));
        }
        _snatchers.Enqueue(snatcher);
    }

    private bool TryGetSnatcher([NotNullWhen(true)] out IPokemon? snatcher)
    {
        while (_snatchers.Any())
        {
            var s = _snatchers.Dequeue();
            if (s.BattleData != null && s.IsUsable)
            {
                snatcher = s;
                return true;
            }
        }
        snatcher = null;
        return false;
    }

    /// <inheritdoc />
    public void StopBeforeMove(IExecutingMove move, ref bool stop)
    {
        if (move.UseMove.HasFlag(MoveFlags.Snatch) && TryGetSnatcher(out var snatcher))
        {
            stop = true;
            var battleData = snatcher.BattleData;
            if (battleData == null)
                return;

            var moveChoice = new MoveChoice(snatcher, move.MoveChoice.ChosenMove, battleData.SideIndex,
                battleData.Position);
            var executingMove = new ExecutingMoveImpl([snatcher], move.NumberOfHits, move.ChosenMove, move.UseMove,
                moveChoice, move.Battle);
            // ExecuteMove will once again call StopBeforeMove, which will try to pass the move to the next snatcher
            // if one exists.
            MoveTurnExecutor.ExecuteMove(executingMove);
        }
    }

    /// <inheritdoc />
    public void OnEndTurn(IScriptSource owner, IBattle battle)
    {
        RemoveSelf();
    }
}