using PkmnLib.Static.Utils;

namespace PkmnLib.Static.Species;

/// <summary>
/// Data about how and into which Pokémon a species can evolve.
/// </summary>
public interface IEvolution
{
    /// <summary>
    /// The species that the Pokémon evolves into.
    /// </summary>
    StringKey ToSpecies { get; }
}

/// <summary>
/// Evolves when a certain level is reached.
/// </summary>
public record LevelEvolution : IEvolution
{
    /// <summary>
    /// The level at which the Pokémon evolves.
    /// </summary>
    public required uint Level { get; init; }

    /// <inheritdoc />
    public required StringKey ToSpecies { get; init; }
}

/// <summary>
/// Evolves when a certain level is reached, and the Pokémon is a specific gender
/// </summary>
public record LevelGenderEvolution : IEvolution
{
    /// <summary>
    /// The level at which the Pokémon evolves.
    /// </summary>
    public required uint Level { get; init; }

    /// <summary>
    /// The gender the Pokémon needs to have to evolve
    /// </summary>
    public required Gender Gender { get; init; }

    /// <inheritdoc />
    public required StringKey ToSpecies { get; init; }
}

/// <summary>
/// Evolves when an item is used on the Pokémon.
/// </summary>
public record ItemUseEvolution : IEvolution
{
    /// <summary>
    /// The item that needs to be used.
    /// </summary>
    public required StringKey Item { get; init; }

    /// <inheritdoc />
    public required StringKey ToSpecies { get; init; }
}

/// <summary>
/// Evolves when an item is used on the Pokémon, and the Pokémon is a specific gender
/// </summary>
public record ItemGenderEvolution : IEvolution
{
    /// <summary>
    /// The item that needs to be used.
    /// </summary>
    public required StringKey Item { get; init; }

    /// <summary>
    /// The gender the Pokémon needs to have to evolve
    /// </summary>
    public Gender Gender { get; init; }

    /// <inheritdoc />
    public required StringKey ToSpecies { get; init; }
}

/// <summary>
/// Evolves when an item is held by the Pokémon, and the Pokémon levels up.
/// </summary>
public record HoldItemEvolution : IEvolution
{
    /// <summary>
    /// The item that needs to be held.
    /// </summary>
    public required StringKey Item { get; init; }

    /// <inheritdoc />
    public required StringKey ToSpecies { get; init; }
}

/// <summary>
/// Evolves when an item is held by the Pokémon, and the Pokémon levels up, and it's day.
/// </summary>
public record DayHoldItemEvolution : IEvolution
{
    /// <summary>
    /// The item that needs to be held.
    /// </summary>
    public required StringKey Item { get; init; }

    /// <inheritdoc />
    public required StringKey ToSpecies { get; init; }
}

/// <summary>
/// Evolves when an item is held by the Pokémon, and the Pokémon levels up, and it's night.
/// </summary>
public record NightHoldItemEvolution : IEvolution
{
    /// <summary>
    /// The item that needs to be held.
    /// </summary>
    public required StringKey Item { get; init; }

    /// <inheritdoc />
    public required StringKey ToSpecies { get; init; }
}

/// <summary>
/// Evolves when the Pokémon knows a certain move, and the Pokémon levels up.
/// </summary>
public record HasMoveEvolution : IEvolution
{
    /// <summary>
    /// The name of the move that needs to be known.
    /// </summary>
    public required StringKey MoveName { get; init; }

    /// <inheritdoc />
    public required StringKey ToSpecies { get; init; }
}

/// <summary>
/// Evolves when above a certain happiness level, and the Pokémon levels up.
/// </summary>
public record HappinessEvolution : IEvolution
{
    /// <summary>
    /// The happiness level that needs to be reached.
    /// </summary>
    public required byte Happiness { get; init; }

    /// <inheritdoc />
    public required StringKey ToSpecies { get; init; }
}

/// <summary>
/// Evolves when above a certain happiness level, and the Pokémon levels up, and it's day.
/// </summary>
public record HappinessDayEvolution : IEvolution
{
    /// <summary>
    /// The happiness level that needs to be reached.
    /// </summary>
    public required byte Happiness { get; init; }

    /// <inheritdoc />
    public required StringKey ToSpecies { get; init; }
}

/// <summary>
/// Evolves when above a certain happiness level, and the Pokémon levels up, and it's night.
/// </summary>
public record HappinessNightEvolution : IEvolution
{
    /// <summary>
    /// The happiness level that needs to be reached.
    /// </summary>
    public required byte Happiness { get; init; }

    /// <inheritdoc />
    public required StringKey ToSpecies { get; init; }
}

/// <summary>
/// Evolves when traded.
/// </summary>
public record TradeEvolution : IEvolution
{
    /// <inheritdoc />
    public required StringKey ToSpecies { get; init; }
}

/// <summary>
/// Evolves when traded with a certain species.
/// </summary>
public record TradeSpeciesEvolution : IEvolution
{
    /// <summary>
    /// The species that needs to be traded with.
    /// </summary>
    public required StringKey WithSpecies { get; init; }

    /// <inheritdoc />
    public required StringKey ToSpecies { get; init; }
}

/// <summary>
/// Evolves when traded while it's holding a certain item.
/// </summary>
public record TradeItemEvolution : IEvolution
{
    /// <summary>
    /// The item that needs to be held.
    /// </summary>
    public required StringKey Item { get; init; }

    /// <inheritdoc />
    public required StringKey ToSpecies { get; init; }
}

/// <summary>
/// Custom evolution method, implemented by the user.
/// </summary>
public record CustomEvolution : IEvolution
{
    /// <summary>
    /// The name of the custom evolution method. This should refer to the name of the script that will be executed.
    /// </summary>
    public required StringKey Name { get; init; }

    /// <summary>
    /// The parameters of the custom evolution method.
    /// </summary>
    public required IReadOnlyDictionary<StringKey, object> Parameters { get; init; }

    /// <inheritdoc />
    public required StringKey ToSpecies { get; init; }
}