using PkmnLib.Dynamic.Models.Choices;
using PkmnLib.Dynamic.ScriptHandling;

namespace PkmnLib.Dynamic.Models;

/// <summary>
/// A side in a battle.
/// </summary>
public interface IBattleSide : IScriptSource
{
    /// <summary>
    /// The index of the side on the battle.
    /// </summary>
    byte Index { get; }
    
    /// <summary>
    /// The number of Pokémon that can be on the side.
    /// </summary>
    byte NumberOfPositions { get; }
    
    /// <summary>
    /// A list of Pokémon currently on the battlefield.
    /// </summary>
    IReadOnlyList<IPokemon?> Pokemon { get; }
    
    /// <summary>
    /// The currently set choices for all Pokémon on the battlefield. Cleared when the turn starts.
    /// </summary>
    IReadOnlyList<ITurnChoice?> SetChoices { get; }
    
    /// <summary>
    /// Whether every Pokémon on this side has its choices  
    /// </summary>
    bool AllChoicesSet { get; }
    
    /// <summary>
    /// The slots on the side that can still be filled. Once all slots are set to false, this side
    /// has lost the battle.
    /// </summary>
    IReadOnlyList<bool> FillablePositions { get; }
    
    /// <summary>
    /// A reference to the battle this side is in.
    /// </summary>
    IBattle Battle { get; }
    
    /// <summary>
    /// Whether this side has fled.
    /// </summary>
    bool HasFledBattle { get; }
    
    /// <summary>
    /// The volatile scripts that are attached to the side.
    /// </summary>
    IScriptSet VolatileScripts { get; }
    
    /// <summary>
    /// Returns true if there are slots that need to be filled with a new pokemon, that have parties
    /// responsible for them. Returns false if all slots are filled with usable pokemon, or slots are
    /// empty, but can't be filled by any party anymore.
    /// </summary>
    void AllPositionsFilled();

    /// <summary>
    /// Sets a choice for a Pokémon on this side.
    /// </summary>
    void SetChoice(byte position, ITurnChoice choice);
    
    /// <summary>
    /// Resets all choices on this side.
    /// </summary>
    void ResetChoices();
    
    /// <summary>
    /// Forcibly removes a Pokémon from the field.
    /// </summary>
    void ForceClearPokemonFromField();

    /// <summary>
    /// Switches out a spot on the field for a different Pokémon. If null is passed, the spot is
    /// cleared. Returns the Pokémon that was previously in the spot.
    /// </summary>
    IPokemon? SwapPokemon(byte position, IPokemon? pokemon);

    /// <summary>
    /// Swaps two Pokémon on the side.
    /// </summary>
    void SwapPokemon(byte position1, byte position2);

    /// <summary>
    /// Checks whether a Pokemon is on the field in this side.
    /// </summary>
    bool IsPokemonOnSide(IPokemon pokemon);

    /// <summary>
    /// Marks a slot as unfillable. This happens when no parties are able to fill the slot anymore.
    /// If this happens, the slot can not be used again.
    /// </summary>
    void MarkPositionAsUnfillable(byte position);

    /// <summary>
    /// Checks whether a slot is fillable. If it is not, the slot can not be used anymore.
    /// </summary>
    bool IsPositionFillable(byte position);

    /// <summary>
    /// Checks whether the side has been defeated.
    /// </summary>
    bool IsDefeated();

    /// <summary>
    /// Mark the side as fled.
    /// </summary>
    void MarkAsFled();

    /// <summary>
    /// Gets a random Pokémon on the given side.
    /// </summary>
    byte GetRandomPosition();
}