using Microsoft.Xna.Framework.Graphics;
using MrGameEng.Genetics;
using MrGameEng.Graphics;

namespace LittleSim.Content;

/// <summary>
/// Готовая (resolved) таблица животных для сцены: по каждому <see cref="AnimalDef"/> — загруженный
/// регион атласа и набор генов вида (<see cref="GenomeTemplate"/>) для генерации особей. Строится
/// один раз при загрузке сцены (нужны атлас и устройство), как <see cref="PlantSet"/>. Системы и
/// фабрика индексируются в неё без словарей. Фаза A1 — один спрайт на вид; стадии/пол придут позже.
/// </summary>
public sealed class AnimalSet
{
    /// <summary>Вид животного: его деф, спрайт и набор генов для генерации особи.</summary>
    public sealed class Species
    {
        /// <summary>Исходный деф животного.</summary>
        public required AnimalDef Def { get; init; }

        /// <summary>Спрайт вида (фаза A1 — единый; стадии/пол позже).</summary>
        public required Texture2DRegion Region { get; init; }

        /// <summary>Набор генов вида: базовые значения для генерации особи.</summary>
        public required GenomeTemplate Template { get; init; }
    }

    private readonly Species[] _species;
    private readonly Dictionary<AnimalDef, int> _index = new();

    /// <summary>Общий реестр генов (по id) для скрещивания и вычисления признаков животных.</summary>
    public IReadOnlyDictionary<string, GeneDef> GeneRegistry { get; }

    /// <summary>Строит таблицу из всех (не-abstract) <see cref="AnimalDef"/> мода.</summary>
    public AnimalSet(GameContent content, ModAtlases atlases, GraphicsDevice device)
    {
        var genes = content
            .Defs.All<GeneDef>()
            .ToDictionary(g => g.DefName, g => g, StringComparer.Ordinal);
        GeneRegistry = genes;

        var defs = content.Defs.All<AnimalDef>().ToArray();
        _species = new Species[defs.Length];
        for (var i = 0; i < defs.Length; i++)
        {
            var def = defs[i];
            _species[i] = new Species
            {
                Def = def,
                Region = atlases.GetRegion(device, def.Texture),
                Template = BuildTemplate(def.Genome, genes),
            };
            _index[def] = i;
        }
    }

    /// <summary>Число видов в таблице.</summary>
    public int Count => _species.Length;

    /// <summary>Вид по индексу.</summary>
    public Species this[int index] => _species[index];

    /// <summary>Индекс вида по дефу.</summary>
    public int IndexOf(AnimalDef def) => _index[def];

    // Переводит базовый геном вида (числа из animals.json) в набор генов: каждое число — центр
    // аллелей соответствующего общего GeneDef. Зеркало PlantSet.BuildTemplate.
    private static GenomeTemplate BuildTemplate(
        AnimalGenomeDef g,
        IReadOnlyDictionary<string, GeneDef> genes
    )
    {
        GeneDef Gene(string id) =>
            genes.TryGetValue(id, out var def)
                ? def
                : throw new KeyNotFoundException(
                    $"Gene def '{id}' not found — is Mods/Core/Defs/genes.json loaded?"
                );

        GenomeTemplate.Entry Numeric(string id, float baseValue) =>
            new(Gene(id), baseValue, g.Spread);

        return new GenomeTemplate(
            [
                Numeric("GeneMaxBodySize", g.BodySize),
                Numeric("GeneMetabolism", g.Metabolism),
                Numeric("GeneMoveSpeed", g.MoveSpeed),
                Numeric("GeneBloodVolume", g.BloodVolume),
                Numeric("GeneVision", g.Vision),
                new GenomeTemplate.Entry(Gene("GeneBrainSize"), g.BrainSize, 0.03f),
                Numeric("GeneInsulation", g.Insulation),
                new GenomeTemplate.Entry(Gene("GeneFurColor"), g.FurColor, 0.06f),
                Numeric("GeneLifespan", g.Lifespan),
            ]
        );
    }
}
