using System.Text.Json.Serialization;
using Microsoft.Xna.Framework;
using MrGameEng.Mods;

namespace LittleSim.Content;

/// <summary>Запись скаттера: с вероятностью <see cref="Chance"/> на клетку ставится одно растение из <see cref="Options"/>.</summary>
public sealed class ScatterEntry
{
    /// <summary>Вероятность на клетку (0..1); записи бросаются независимо.</summary>
    public float Chance { get; init; }

    /// <summary>Имена <see cref="PlantDef"/>, из которых выбирается равновероятно.</summary>
    public List<string> Options { get; init; } = [];
}

/// <summary>Тип клетки рельефа (Defs/terrain.json): порог высоты, цвет, поверхность, скаттер растений.</summary>
public sealed class TerrainDef : Def
{
    /// <summary>Верхняя граница высоты (клетка относится к первому дефу, чей порог выше её высоты).</summary>
    public float MaxHeight { get; init; }

    /// <summary>Цвет клетки [r, g, b] для сцен с тонированными квадратами и тайлов без поверхности.</summary>
    [JsonPropertyName("color")]
    public List<int> Rgb { get; init; } = [];

    /// <summary>Суша: здесь появляются жители, животные и растения.</summary>
    public bool IsLand { get; init; }

    /// <summary>Загораживает свет (горы) — базовый окклюдер для лайтмапа/теней.</summary>
    public bool BlocksLight { get; init; }

    /// <summary>Ключ текстуры поверхности для тайловой сцены; null — тонированный тайл.</summary>
    public string? Surface { get; init; }

    /// <summary>Растительность, рассыпаемая по клеткам этого террейна.</summary>
    public List<ScatterEntry> Scatter { get; init; } = [];

    /// <summary>
    /// Плодородность почвы — множитель скорости роста растений на этом террейне (1 — норма,
    /// больше — быстрее). Богатая лесная почва растит быстрее песка/камня.
    /// </summary>
    public float Fertility { get; init; } = 1f;

    /// <summary>Цвет тонировки из <see cref="Rgb"/>.</summary>
    public Color Tint => Rgb is [var r, var g, var b, ..] ? new(r, g, b) : Color.Magenta;
}

/// <summary>
/// Одна стадия роста растения (вложенный объект <see cref="PlantDef.Stages"/>): свой спрайт и
/// размер, и сколько игровых дней растение проводит на этой стадии до перехода к следующей.
/// Растёт на месте — последняя стадия терминальная (её <see cref="GrowDays"/> игнорируется).
/// </summary>
public sealed class PlantGrowthStage
{
    /// <summary>Ключ текстуры стадии; null — берётся базовая <see cref="PlantDef.Texture"/>.</summary>
    public string? Texture { get; init; }

    /// <summary>Размер спрайта в клетках на этой стадии; 0 — берётся базовый <see cref="PlantDef.SizeCells"/>.</summary>
    public float SizeCells { get; init; }

    /// <summary>Сколько игровых дней расти на этой стадии до перехода к следующей.</summary>
    public float GrowDays { get; init; }

    /// <summary>Ключ локализации названия стадии (опционально, для будущих тултипов).</summary>
    public string? Label { get; init; }
}

/// <summary>
/// Базовый геном вида (вложенный объект <see cref="PlantDef.Genome"/>): оптимумы и толерантности по
/// факторам среды + базовая бодрость роста. Особь при спавне получает аллели рядом с этими базами
/// (разброс — <see cref="Spread"/>); фенотип = среднее аллелей.
/// </summary>
public sealed class GenomeDef
{
    /// <summary>Оптимальная освещённость (0..1) и её толерантность.</summary>
    public float OptimalLight { get; init; } = 0.7f;

    /// <summary>Ширина толерантности по свету.</summary>
    public float LightTolerance { get; init; } = 0.4f;

    /// <summary>Оптимальная температура (°C) и её толерантность.</summary>
    public float OptimalTemperature { get; init; } = 18f;

    /// <summary>Ширина толерантности по температуре (°C).</summary>
    public float TemperatureTolerance { get; init; } = 12f;

    /// <summary>Оптимальная плодородность почвы и её толерантность.</summary>
    public float OptimalFertility { get; init; } = 1f;

    /// <summary>Ширина толерантности по плодородности.</summary>
    public float FertilityTolerance { get; init; } = 0.8f;

    /// <summary>Базовая бодрость роста (множитель скорости в идеальных условиях).</summary>
    public float Vigor { get; init; } = 1f;

    /// <summary>Продолжительность жизни (игровых дней) до смерти от старости.</summary>
    public float Lifespan { get; init; } = 80f;

    /// <summary>Дальность расселения семян (в клетках).</summary>
    public float DispersalRange { get; init; } = 2f;

    /// <summary>Средний интервал между попытками дать семя (игровых дней).</summary>
    public float ReproduceInterval { get; init; } = 8f;

    /// <summary>Способность к самоопылению (0..1): шанс дать семя без партнёра.</summary>
    public float SelfPollination { get; init; } = 0.4f;

    /// <summary>Темп мутаций (0..1): вероятность сдвига аллеля у потомка.</summary>
    public float MutationRate { get; init; } = 0.05f;

    /// <summary>Доля рецессивного аллеля морфы в стартовой популяции (0..1).</summary>
    public float VariantChance { get; init; } = 0.15f;

    /// <summary>Доля разброса аллелей вокруг базы при генерации особи.</summary>
    public float Spread { get; init; } = 0.08f;
}

/// <summary>Растение (Defs/plants.json): текстура, размер, опциональный ствол-препятствие, стадии роста, геном.</summary>
public sealed class PlantDef : Def
{
    /// <summary>Ключ текстуры (путь региона в атласах); база для стадий без своей текстуры.</summary>
    public string Texture { get; init; } = "";

    /// <summary>Базовый размер спрайта в клетках; база для стадий без своего размера.</summary>
    public float SizeCells { get; init; } = 1f;

    /// <summary>Радиус коллайдера ствола в клетках; 0 — без коллайдера (трава, кусты).</summary>
    public float TrunkRadiusCells { get; init; }

    /// <summary>Стадии роста по порядку; пусто — одна терминальная стадия из базовой текстуры.</summary>
    public List<PlantGrowthStage> Stages { get; init; } = [];

    /// <summary>Базовый геном вида: оптимумы/толерантности по среде и бодрость роста.</summary>
    public GenomeDef Genome { get; init; } = new();
}

/// <summary>
/// Пресет размера мира (Defs/worldpresets.json): габариты сетки и население. Меню «Новый
/// мир» строит список размеров из этих дефов — новая механика приходит данными мода, а не
/// хардкодом. <see cref="Def.Label"/> — ключ локализации (preset.*).
/// </summary>
public sealed class WorldPresetDef : Def
{
    /// <summary>Ширина мира в клетках.</summary>
    public int Width { get; init; }

    /// <summary>Высота мира в клетках.</summary>
    public int Height { get; init; }

    /// <summary>Число жителей при генерации.</summary>
    public int Population { get; init; }

    /// <summary>Порядок в списке UI (по возрастанию).</summary>
    public int Order { get; init; }
}

/// <summary>Существо (Defs/pawns.json): текстура, размер и вид (житель/животное).</summary>
public sealed class PawnDef : Def
{
    /// <summary>Вид существа: жители ("being") живут в мировой сцене, животные ("animal") — в террейне.</summary>
    public const string KindBeing = "being";

    /// <summary>Вид животного.</summary>
    public const string KindAnimal = "animal";

    /// <summary>Ключ текстуры (путь региона в атласах).</summary>
    public string Texture { get; init; } = "";

    /// <summary>Размер спрайта в клетках.</summary>
    public float SizeCells { get; init; } = 1f;

    /// <summary>Вид: <see cref="KindBeing"/> или <see cref="KindAnimal"/>.</summary>
    public string Kind { get; init; } = "";
}
