using PkmnLib.Dynamic.ScriptHandling;
using PkmnLib.Static;
using PkmnLib.Static.Moves;

namespace PkmnLib.Dynamic.Models;

public interface IHitData
{
    /// <summary>
    /// Whether the hit is critical.
    /// </summary>
    bool IsCritical { get; }

    /// <summary>
    /// The base power of the hit.
    /// </summary>
    byte BasePower { get; }

    /// <summary>
    /// The effectiveness of the hit.
    /// </summary>
    float Effectiveness { get; }

    /// <summary>
    /// The damage done by the hit.
    /// </summary>
    uint Damage { get; }

    /// <summary>
    /// The type of the hit.
    /// </summary>
    TypeIdentifier Type { get; }

    /// <summary>
    /// Whether the hit has failed.
    /// </summary>
    bool HasFailed { get; }

    /// <summary>
    /// Fails the hit.
    /// </summary>
    void Fail();

    bool Equals(HitData? other);
    bool Equals(object? other);
    int GetHashCode();
    string ToString();
}

/// <inheritdoc />
public record HitData : IHitData
{
    /// <inheritdoc />
    public bool IsCritical { get; internal set; }

    /// <inheritdoc />
    public byte BasePower { get; internal set; }

    /// <inheritdoc />
    public float Effectiveness { get; internal set; }

    /// <inheritdoc />
    public uint Damage { get; internal set; }

    /// <inheritdoc />
    public TypeIdentifier Type { get; internal set; }

    /// <inheritdoc />
    public bool HasFailed { get; private set; }

    /// <inheritdoc />
    public void Fail() => HasFailed = true;
}

/// <summary>
/// An executing move is the data of the move for while it is executing.
/// </summary>
public interface IExecutingMove : IScriptSource
{
    /// <summary>
    /// The number of targets this move has.
    /// </summary>
    int TargetCount { get; }

    /// <summary>
    /// The number of hits this move has per target.
    /// </summary>
    byte NumberOfHits { get; }

    /// <summary>
    /// The user of the move.
    /// </summary>
    IPokemon User { get; }

    /// <summary>
    /// The move the user has actually chosen to do.
    /// </summary>
    ILearnedMove ChosenMove { get; }

    /// <summary>
    /// The move that the user is actually going to do. This can be different from the chosen move, for example
    /// when metronome is used, in which case the chosen move will be metronome, and the movedata will be the
    /// move that metronome has chosen.
    /// </summary>
    IMoveData UseMove { get; }

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

    /// <summary>
    /// Gets a hit data for a target, with a specific index.
    /// </summary>
    HitData GetHitData(IPokemon target, byte hit);

    /// <summary>
    /// Checks whether a Pokémon is a target for this move.
    /// </summary>
    bool IsPokemonTarget(IPokemon target);

    /// <summary>
    /// Gets the index of the hits in this move where the hits for a specific target start.
    /// </summary>
    int GetTargetIndex(IPokemon target);

    /// <summary>
    /// Gets a hit based on its raw index.
    /// </summary>
    HitData GetDataFromRawIndex(int index);
}