using PkmnLib.Static.Moves;

namespace PkmnLib.Dynamic.Models;

/// <summary>
/// The different ways a move can be learned.
/// </summary>
public enum MoveLearnMethod
{
    /// <summary>
    /// We do not know the learn method.
    /// </summary>
    Unknown,

    /// <summary>
    /// The move is learned by leveling up.
    /// </summary>
    LevelUp,

    /// <summary>
    /// The move is learned when the Pokémon is hatched from an egg.
    /// </summary>
    Egg,

    /// <summary>
    /// The move is learned by using a tutor in the game.
    /// </summary>
    Tutor,

    /// <summary>
    /// The move is learned by using a TM or HM.
    /// </summary>
    Machine,

    /// <summary>
    /// The move is learned when the Pokémon changes form.
    /// </summary>
    FormChange
}

/// <summary>
/// A learned move is the data attached to a Pokemon for a move it has learned. It has information
/// such as the remaining amount of users, how it has been learned, etc.
/// </summary>
public interface ILearnedMove
{
    /// <summary>
    /// The immutable move information of the move.
    /// </summary>
    IMoveData MoveData { get; }

    /// <summary>
    /// The maximal power points for this move.
    /// </summary>
    byte MaxPp { get; }

    /// <summary>
    /// The way the move has been learned.
    /// </summary>
    MoveLearnMethod LearnMethod { get; }

    /// <summary>
    /// Try and reduce the PP by a certain amount. If the amount is higher than the current uses,
    /// return false. Otherwise, reduce the PP, and return true.
    /// </summary>
    bool TryUse(byte amount = 1);

    /// <summary>
    /// Set the remaining PP to the max amount of PP.
    /// </summary>
    void RestoreAllUses();

    /// <summary>
    /// Restore the remaining PP by a certain amount. Will prevent it from going above max PP.
    /// </summary>
    void RestoreUses(byte amount);
}

/// <inheritdoc />
public class LearnedMoveImpl : ILearnedMove
{
    private byte _maxPpModification = 0;
    
    public LearnedMoveImpl(IMoveData moveData, MoveLearnMethod learnMethod)
    {
        MoveData = moveData;
        LearnMethod = learnMethod;
        CurrentPp = MaxPp;
    }

    /// <inheritdoc />
    public IMoveData MoveData { get; }

    /// <inheritdoc />
    public byte MaxPp => (byte)(MoveData.BaseUsages + _maxPpModification);

    /// <inheritdoc />
    public MoveLearnMethod LearnMethod { get; }
    
    public byte CurrentPp { get; private set; }
    
    public bool TryUse(byte amount = 1)
    {
        if (CurrentPp < amount)
            return false;
        
        CurrentPp -= amount;
        return true;
    }

    public void RestoreAllUses() => CurrentPp = MaxPp;

    public void RestoreUses(byte amount) => CurrentPp = (byte)Math.Min(CurrentPp + amount, MaxPp);
}