using MrGameEng.Atlases;
using MrGameEng.Core;
using MrGameEng.Genetics;
using MrGameEng.Mods;

namespace LittleSim.Content;

/// <summary>
/// Загруженный контент модов: список модов, дефы, локализация и кэш атласов.
/// Создаётся в Program до открытия окна (чистый CPU) и регистрируется сервисом —
/// сцены берут его из <c>Context.Services</c>.
/// </summary>
public sealed class GameContent
{
    private GameContent(
        IReadOnlyList<Mod> mods,
        DefDatabase defs,
        LanguageManager languages,
        TerrainSet terrains,
        string atlasCacheDirectory
    )
    {
        Mods = mods;
        Defs = defs;
        Languages = languages;
        Terrains = terrains;
        AtlasCacheDirectory = atlasCacheDirectory;
    }

    /// <summary>Активные моды в порядке загрузки.</summary>
    public IReadOnlyList<Mod> Mods { get; }

    /// <summary>База дефов (Terrain/Plant/Pawn).</summary>
    public DefDatabase Defs { get; }

    /// <summary>Локализация интерфейса.</summary>
    public LanguageManager Languages { get; }

    /// <summary>Дефы рельефа, готовые к классификации по высоте.</summary>
    public TerrainSet Terrains { get; }

    /// <summary>Директория собранных атласов (кормит <see cref="ModAtlases"/>).</summary>
    public string AtlasCacheDirectory { get; }

    /// <summary>
    /// Находит папку Mods (вверх по дереву от исполняемого файла), загружает моды, дефы и
    /// языки и инкрементально собирает атласы из смерженного дерева текстур всех модов.
    /// </summary>
    public static GameContent Load()
    {
        var modsRoot =
            ModLoader.FindModsRoot(AppContext.BaseDirectory)
            ?? throw new DirectoryNotFoundException(
                "Папка Mods не найдена ни рядом с игрой, ни выше по дереву каталогов."
            );
        var mods = ModLoader.Load(modsRoot);

        var defs = new DefDatabase();
        defs.RegisterType<TerrainDef>("Terrain");
        defs.RegisterType<GeneDef>("Gene");
        defs.RegisterType<PlantDef>("Plant");
        defs.RegisterType<PawnDef>("Pawn");
        defs.RegisterType<WorldPresetDef>("WorldPreset");
        defs.Load(mods);

        var languages = new LanguageManager(defaultLanguage: "ru");
        languages.Load(mods);

        // Текстуры поздних модов переопределяют ранние по относительному пути;
        // сборка инкрементальная — без изменений старт мгновенный.
        var atlasCacheDirectory = Path.Combine(
            Path.GetDirectoryName(modsRoot)!,
            "Cache",
            "Atlases"
        );
        var textures = ModContentTree.Build(mods, "Textures", ".png", ".jpg", ".jpeg", ".bmp");
        var result = AtlasBuilder.Build(
            new AtlasBuildOptions
            {
                OutputDirectory = atlasCacheDirectory,
                GroupDepth = ModAtlases.GroupDepth,
            },
            textures.Files.Select(f => (f.FullPath, f.RelativePath))
        );
        var built = result.Groups.Count(g => !g.Skipped);
        Log.Info(
            $"Atlases: {built} built, {result.Groups.Count - built} up to date ({result.Groups.Count} total)"
        );

        return new GameContent(
            mods,
            defs,
            languages,
            new TerrainSet(defs.All<TerrainDef>()),
            atlasCacheDirectory
        );
    }
}
