using System.Diagnostics.CodeAnalysis;
using System.Text.Json;
using System.Text.Json.Nodes;
using System.Text.Json.Serialization;

// ReSharper disable UnusedAutoPropertyAccessor.Global
// ReSharper disable PropertyCanBeMadeInitOnly.Global

namespace PkmnLib.Dynamic.Libraries.DataLoaders.Models;

/// <summary>
/// Represents a serialized species.
/// </summary>
public class SerializedSpecies
{
    /// <inheritdoc cref="PkmnLib.Static.Utils.INamedValue.Name"/>
    public string Species { get; set; } = null!;

    /// <inheritdoc cref="PkmnLib.Static.Species.ISpecies.Id"/>
    public ushort Id { get; set; }

    /// <inheritdoc cref="PkmnLib.Static.Species.ISpecies.GenderRate"/>
    public float GenderRatio { get; set; }

    /// <inheritdoc cref="PkmnLib.Static.Species.ISpecies.GrowthRate"/>
    public string GrowthRate { get; set; } = null!;

    /// <inheritdoc cref="PkmnLib.Static.Species.ISpecies.BaseHappiness"/>
    public byte BaseHappiness { get; set; }

    /// <inheritdoc cref="PkmnLib.Static.Species.ISpecies.CaptureRate"/>
    public byte CatchRate { get; set; }

    /// <summary>
    /// The color of the Pokémon, used for Pokédex sorting.
    /// </summary>
    public string Color { get; set; } = null!;

    /// <summary>
    /// Whether the Pokémon has a different form per gender
    /// </summary>
    public bool GenderDifference { get; set; }

    /// <inheritdoc cref="PkmnLib.Static.Species.ISpecies.EggGroups"/>
    public string[] EggGroups { get; set; } = null!;

    /// <summary>
    /// The number of steps required to hatch the Pokémon's egg, in cycles (1 cycle = 255 steps).
    /// </summary>
    public int EggCycles { get; set; }

    /// <inheritdoc cref="PkmnLib.Static.Species.ISpecies.Flags"/>
    public string[] Flags { get; set; } = [];

    /// <inheritdoc cref="PkmnLib.Static.Species.ISpecies.Forms"/>
    public Dictionary<string, SerializedForm> Formes { get; set; } = null!;

    /// <inheritdoc cref="PkmnLib.Static.Species.ISpecies.EvolutionData"/>
    public SerializedEvolution[] Evolutions { get; set; } = [];

    /// <summary>
    /// Additional data that is not part of the standard species data.
    /// </summary>
    [JsonExtensionData]
    public Dictionary<string, JsonElement>? ExtensionData { get; set; }
}

/// <summary>
/// Represents a serialized form of a Pokémon species.
/// </summary>
public class SerializedForm
{
    /// <inheritdoc cref="PkmnLib.Static.Species.IForm.Abilities"/>
    public string[] Abilities { get; set; } = null!;

    /// <inheritdoc cref="PkmnLib.Static.Species.IForm.HiddenAbilities"/>
    public string[] HiddenAbilities { get; set; } = [];

    /// <inheritdoc cref="PkmnLib.Static.Species.IForm.BaseStats"/>
    public SerializedStats BaseStats { get; set; } = null!;

    /// <summary>
    /// The Pokémon's EV yield. This is the number of EVs gained when defeating a Pokémon of this species.
    /// </summary>
    public SerializedStats EVReward { get; set; } = null!;

    /// <inheritdoc cref="PkmnLib.Static.Species.IForm.Types"/>
    public string[] Types { get; set; } = null!;

    /// <inheritdoc cref="PkmnLib.Static.Species.IForm.Height"/>
    public float Height { get; set; }

    /// <inheritdoc cref="PkmnLib.Static.Species.IForm.Weight"/>
    public float Weight { get; set; }

    /// <inheritdoc cref="PkmnLib.Static.Species.IForm.BaseExperience"/>
    public uint BaseExp { get; set; }

    /// <summary>
    /// Whether the form is a Mega Evolution.
    /// </summary>
    public bool IsMega { get; set; }

    /// <inheritdoc cref="PkmnLib.Static.Species.IForm.Moves"/>
    public SerializedMoves Moves { get; set; } = null!;

    /// <inheritdoc cref="PkmnLib.Static.Species.IForm.Flags"/>
    public string[] Flags { get; set; } = [];

    /// <summary>
    /// Check if the form is a battle-only form, meaning it should return to its original form after the battle ends.
    /// </summary>
    public bool IsBattleOnly { get; set; }

    public string? InheritFrom { get; set; }

    /// <summary>
    /// Additional data that is not part of the standard form data.
    /// </summary>
    [JsonExtensionData]
    public Dictionary<string, JsonElement>? ExtensionData { get; set; }

    [SuppressMessage("ReSharper", "ConditionIsAlwaysTrueOrFalseAccordingToNullableAPIContract"),
     SuppressMessage("ReSharper", "NullCoalescingConditionIsAlwaysNotNullAccordingToAPIContract")]
    internal void MakeInheritFrom(SerializedForm other)
    {
        Abilities ??= other.Abilities.ToArray();
        HiddenAbilities ??= other.HiddenAbilities.ToArray();
        BaseStats ??= other.BaseStats.Copy();
        EVReward ??= other.EVReward.Copy();
        Types ??= other.Types.ToArray();
        if (Height == 0)
            Height = other.Height;
        if (Weight == 0)
            Weight = other.Weight;
        if (BaseExp == 0)
            BaseExp = other.BaseExp;
        Moves ??= new SerializedMoves();
        if (Moves.LevelMoves == null || Moves.LevelMoves.Length == 0)
            Moves.LevelMoves = other.Moves.LevelMoves?.ToArray();
        if (Moves.EggMoves == null || Moves.EggMoves.Length == 0)
            Moves.EggMoves = other.Moves.EggMoves?.ToArray();
        if (Moves.TutorMoves == null || Moves.TutorMoves.Length == 0)
            Moves.TutorMoves = other.Moves.TutorMoves?.ToArray();
        if (Moves.Machine == null || Moves.Machine.Length == 0)
            Moves.Machine = other.Moves.Machine?.ToArray();
        Flags ??= other.Flags.ToArray();
    }
}

/// <summary>
/// Represents a serialized evolution of a Pokémon species.
/// </summary>
public class SerializedEvolution
{
    /// <inheritdoc cref="PkmnLib.Static.Species.IEvolution.ToSpecies"/>
    public string Species { get; set; } = null!;

    /// <summary>
    /// The method of evolution.
    /// </summary>
    public string Method { get; set; } = null!;

    /// <summary>
    /// Additional data for the evolution method.
    /// </summary>
    public JsonNode Data { get; set; } = null!;
}

/// <summary>
/// Represents the base stats of a Pokémon species.
/// </summary>
public record SerializedStats
{
    /// <inheritdoc cref="PkmnLib.Static.ImmutableStatisticSet{T}.Hp"/>
    public ushort Hp { get; set; }

    /// <inheritdoc cref="PkmnLib.Static.ImmutableStatisticSet{T}.Attack"/>
    public ushort Attack { get; set; }

    /// <inheritdoc cref="PkmnLib.Static.ImmutableStatisticSet{T}.Defense"/>
    public ushort Defense { get; set; }

    /// <inheritdoc cref="PkmnLib.Static.ImmutableStatisticSet{T}.SpecialAttack"/>
    public ushort SpecialAttack { get; set; }

    /// <inheritdoc cref="PkmnLib.Static.ImmutableStatisticSet{T}.SpecialDefense"/>
    public ushort SpecialDefense { get; set; }

    /// <inheritdoc cref="PkmnLib.Static.ImmutableStatisticSet{T}.Speed"/>
    public ushort Speed { get; set; }

    public SerializedStats Copy() =>
        new()
        {
            Hp = Hp,
            Attack = Attack,
            Defense = Defense,
            SpecialAttack = SpecialAttack,
            SpecialDefense = SpecialDefense,
            Speed = Speed,
        };
}

/// <summary>
/// Represents a serialized level move.
/// </summary>
public class SerializedLevelMove
{
    /// <summary>
    /// The name of the move.
    /// </summary>
    public string Name { get; set; } = null!;

    /// <summary>
    /// The level at which the move is learned.
    /// </summary>
    public uint Level { get; set; }
}

/// <summary>
/// Represents a serialized set of moves a Pokémon can learn.
/// </summary>
public class SerializedMoves
{
    /// <summary>
    /// The moves the Pokémon can learn by leveling up.
    /// </summary>
    public SerializedLevelMove[]? LevelMoves { get; set; }

    /// <summary>
    /// The moves the Pokémon can learn by breeding.
    /// </summary>
    public string[]? EggMoves { get; set; }

    /// <summary>
    /// The moves the Pokémon can learn by tutoring.
    /// </summary>
    public string[]? TutorMoves { get; set; }

    /// <summary>
    /// The moves the Pokémon can learn by TM.
    /// </summary>
    public string[]? Machine { get; set; }
}