namespace Theriapolis.Core.Data;

/// <summary>
/// Pre-loaded content lookup tables. Constructing one calls every loader
/// exactly once and indexes results by id, so subsequent
/// <c>resolver.Clades["canidae"]</c> lookups are O(1).
///
/// Used by character creation, save/load (id → def resolution), and Phase 5 M5
/// NPC instantiation. Shared across screens that need any combination of
/// these tables.
/// </summary>
public sealed class ContentResolver
{
    public IReadOnlyDictionary<string, CladeDef>      Clades      { get; }
    public IReadOnlyDictionary<string, SpeciesDef>    Species     { get; }
    public IReadOnlyDictionary<string, ClassDef>      Classes     { get; }
    public IReadOnlyDictionary<string, SubclassDef>   Subclasses  { get; }
    public IReadOnlyDictionary<string, BackgroundDef> Backgrounds { get; }
    public IReadOnlyDictionary<string, ItemDef>       Items       { get; }
    public IReadOnlyDictionary<string, LootTableDef>  LootTables  { get; }
    public NpcTemplateContent                         Npcs        { get; }

    /// <summary>Phase 6 M0 — building templates + settlement layouts.</summary>
    public SettlementContent                          Settlements { get; }

    /// <summary>Phase 6 M1 — pre-meeting bias profiles per <c>reputation.md §I-1</c>.</summary>
    public IReadOnlyDictionary<string, BiasProfileDef> BiasProfiles { get; }

    /// <summary>Phase 6 M2 — faction definitions including opposition matrix entries.</summary>
    public IReadOnlyDictionary<string, FactionDef>    Factions    { get; }

    /// <summary>Phase 6 M1 — generic + named friendly/neutral resident templates.</summary>
    public IReadOnlyDictionary<string, ResidentTemplateDef> Residents { get; }

    /// <summary>
    /// Phase 6 M1 — fast lookup of named residents by anchor-prefixed role
    /// tag (e.g. "millhaven.innkeeper" → ResidentTemplateDef). Generic
    /// templates live in <see cref="Residents"/>; this index only holds
    /// the entries with <c>named: true</c>.
    /// </summary>
    public IReadOnlyDictionary<string, ResidentTemplateDef> ResidentsByRoleTag { get; }

    /// <summary>Phase 6 M3 — dialogue trees indexed by id.</summary>
    public IReadOnlyDictionary<string, DialogueDef> Dialogues { get; }

    /// <summary>Phase 6 M4 — quest trees indexed by id.</summary>
    public IReadOnlyDictionary<string, QuestDef> Quests { get; }

    /// <summary>Phase 7 M0 — room templates indexed by id (every dungeon type).</summary>
    public IReadOnlyDictionary<string, RoomTemplateDef> RoomTemplates { get; }

    /// <summary>
    /// Phase 7 M0 — room templates indexed by dungeon type (e.g. <c>imperium</c>
    /// → IList of all imperium-typed templates). Used by the layout matcher
    /// to filter candidates without a linear scan.
    /// </summary>
    public IReadOnlyDictionary<string, IReadOnlyList<RoomTemplateDef>> RoomTemplatesByType { get; }

    /// <summary>Phase 7 M0 — dungeon layouts indexed by id.</summary>
    public IReadOnlyDictionary<string, DungeonLayoutDef> DungeonLayouts { get; }

    /// <summary>
    /// Phase 7 M0 — anchor-locked layouts indexed by anchor id (e.g.
    /// <c>OldHowlMine</c> → the pinned 3-room layout). Procedural pipeline
    /// never picks anchor-locked layouts; the anchor resolver consults this
    /// dict directly.
    /// </summary>
    public IReadOnlyDictionary<string, DungeonLayoutDef> DungeonLayoutsByAnchor { get; }

    public ContentResolver(ContentLoader loader)
    {
        var clades = loader.LoadClades();
        Clades      = clades.ToDictionary(c => c.Id, StringComparer.OrdinalIgnoreCase);
        var speciesArr = loader.LoadSpecies(clades);
        Species     = speciesArr.ToDictionary(s => s.Id, StringComparer.OrdinalIgnoreCase);
        var classes = loader.LoadClasses();
        Classes     = classes.ToDictionary(c => c.Id, StringComparer.OrdinalIgnoreCase);
        Subclasses  = loader.LoadSubclasses(classes).ToDictionary(s => s.Id, StringComparer.OrdinalIgnoreCase);
        Backgrounds = loader.LoadBackgrounds().ToDictionary(b => b.Id, StringComparer.OrdinalIgnoreCase);
        var items   = loader.LoadItems();
        Items       = items.ToDictionary(i => i.Id, StringComparer.OrdinalIgnoreCase);
        LootTables  = loader.LoadLootTables(items).ToDictionary(t => t.Id, StringComparer.OrdinalIgnoreCase);

        // Phase 6 M5 — factions loaded early so NpcTemplates can validate
        // their faction field references against the canonical list.
        var factionsArr = loader.LoadFactions();
        Factions    = factionsArr.ToDictionary(f => f.Id, StringComparer.OrdinalIgnoreCase);
        Npcs        = loader.LoadNpcTemplates(items, factionsArr);

        // Phase 6 M0 — building/layout content.
        var buildings = loader.LoadBuildingTemplates();
        var layouts   = loader.LoadSettlementLayouts(buildings);
        var byId      = buildings.ToDictionary(b => b.Id, StringComparer.OrdinalIgnoreCase);
        var preset    = layouts.Where(l => l.Kind == "preset")
                               .ToDictionary(l => l.Anchor, StringComparer.OrdinalIgnoreCase);
        var proc      = layouts.Where(l => l.Kind == "procedural")
                               .ToDictionary(l => l.Tier);
        Settlements = new SettlementContent(byId, preset, proc);

        // Phase 6 M1 — bias profiles + resident templates.
        // (factionsArr already loaded above for NpcTemplates validation.)
        var biasArr  = loader.LoadBiasProfiles(clades, factionsArr);
        BiasProfiles = biasArr.ToDictionary(b => b.Id, StringComparer.OrdinalIgnoreCase);
        var residentArr = loader.LoadResidentTemplates(biasArr, clades, speciesArr, factionsArr);
        Residents = residentArr.ToDictionary(r => r.Id, StringComparer.OrdinalIgnoreCase);
        ResidentsByRoleTag = residentArr
            .Where(r => r.Named)
            .ToDictionary(r => r.RoleTag, StringComparer.OrdinalIgnoreCase);

        // Phase 6 M3 — dialogue trees.
        Dialogues = loader.LoadDialogues(items)
            .ToDictionary(d => d.Id, StringComparer.OrdinalIgnoreCase);

        // Phase 6 M4 — quest trees.
        Quests = loader.LoadQuests(items)
            .ToDictionary(q => q.Id, StringComparer.OrdinalIgnoreCase);

        // Phase 7 M0 — room templates + dungeon layouts.
        var roomArr = loader.LoadRoomTemplates();
        RoomTemplates = roomArr.ToDictionary(r => r.Id, StringComparer.OrdinalIgnoreCase);
        RoomTemplatesByType = roomArr
            .GroupBy(r => r.Type, StringComparer.OrdinalIgnoreCase)
            .ToDictionary(
                g => g.Key,
                g => (IReadOnlyList<RoomTemplateDef>)g.ToArray(),
                StringComparer.OrdinalIgnoreCase);

        var layoutArr = loader.LoadDungeonLayouts(roomArr, LootTables.Values.ToArray());
        DungeonLayouts = layoutArr.ToDictionary(l => l.Id, StringComparer.OrdinalIgnoreCase);
        DungeonLayoutsByAnchor = layoutArr
            .Where(l => !string.IsNullOrEmpty(l.Anchor))
            .ToDictionary(l => l.Anchor, StringComparer.OrdinalIgnoreCase);
    }
}
