using PkmnLib.Dynamic.ScriptHandling;
using PkmnLib.Static.Utils;

namespace PkmnLib.Dynamic.Models.Choices;

/// <summary>
/// The choice of a Pokémon to use a move.
/// </summary>
public interface IMoveChoice : ITurnChoice
{
    /// <summary>
    /// The move that is used.
    /// </summary>
    ILearnedMove ChosenMove { get; }

    /// <summary>
    /// The side the move is targeted at.
    /// </summary>
    byte TargetSide { get; }

    /// <summary>
    /// The position the move is targeted at.
    /// </summary>
    byte TargetPosition { get; }

    /// <summary>
    /// The priority of the move.
    /// </summary>
    sbyte Priority { get; set; }

    /// <summary>
    /// The underlying script of the move.
    /// </summary>
    ScriptContainer Script { get; set; }

    Dictionary<StringKey, object?>? AdditionalData { get; }

    IScriptSet Volatile { get; }
}

/// <inheritdoc cref="IMoveChoice"/>
public class MoveChoice : TurnChoice, IMoveChoice
{
    /// <inheritdoc cref="MoveChoice"/>
    public MoveChoice(IPokemon user, ILearnedMove usedMove, byte targetSide, byte targetPosition) : base(user)
    {
        ChosenMove = usedMove;
        TargetSide = targetSide;
        TargetPosition = targetPosition;

        var secondaryEffect = usedMove.MoveData.SecondaryEffect;
        if (secondaryEffect != null)
        {
            if (user.Library.ScriptResolver.TryResolve(ScriptCategory.Move, secondaryEffect.Name,
                    secondaryEffect.Parameters, out var script))
            {
                Script.Set(script);
            }
        }
    }

    /// <inheritdoc />
    public ILearnedMove ChosenMove { get; }

    /// <inheritdoc />
    public byte TargetSide { get; }

    /// <inheritdoc />
    public byte TargetPosition { get; }

    /// <inheritdoc />
    public sbyte Priority { get; set; }

    /// <inheritdoc />
    public ScriptContainer Script { get; set; } = new();

    /// <inheritdoc />
    public Dictionary<StringKey, object?>? AdditionalData { get; }

    /// <inheritdoc />
    public IScriptSet Volatile { get; } = new ScriptSet();

    /// <inheritdoc />
    public override int ScriptCount => 2 + User.ScriptCount;

    /// <inheritdoc />
    public override void GetOwnScripts(List<IEnumerable<ScriptContainer>> scripts)
    {
        scripts.Add(Volatile);
        scripts.Add(Script);
    }

    /// <inheritdoc />
    public override void CollectScripts(List<IEnumerable<ScriptContainer>> scripts)
    {
        GetOwnScripts(scripts);
        User.CollectScripts(scripts);
    }
}