import type { SystemId } from '@/lib/rules';
import type { RulesetClass } from '@/lib/ruleset/normalize';
import type {
  Monster,
  Spell,
  MagicItem,
  Weapon5e,
  Armor5e,
  Feat5e,
  Condition5e,
  CompendiumEntry,
} from './types';

/**
 * Lazy, cached loaders for the SRD datasets. Dynamic `import()` keeps the
 * multi-hundred-KB JSON out of the main bundle — it loads only when the user
 * opens the compendium (fixing the old app's eager MB-scale imports).
 */
let monstersCache: Monster[] | null = null;
let spellsCache: Spell[] | null = null;
let itemsCache: MagicItem[] | null = null;

export async function loadMonsters(): Promise<Monster[]> {
  if (!monstersCache) {
    const mod = await import('@/data/srd/monsters-srd.json');
    monstersCache = mod.default as unknown as Monster[];
  }
  return monstersCache;
}

export async function loadSpells(): Promise<Spell[]> {
  if (!spellsCache) {
    const mod = await import('@/data/srd/spells-srd.json');
    spellsCache = mod.default as unknown as Spell[];
  }
  return spellsCache;
}

export async function loadItems(): Promise<MagicItem[]> {
  if (!itemsCache) {
    const mod = await import('@/data/srd/magicitems-srd.json');
    itemsCache = mod.default as unknown as MagicItem[];
  }
  return itemsCache;
}

// ---- Additional 5e categories (bundled — these files are small) ----
const cache = new Map<string, unknown[]>();

export async function loadWeapons5e(): Promise<Weapon5e[]> {
  if (!cache.has('w5e')) {
    const mod = await import('@/data/srd/weapons-full.json');
    cache.set('w5e', mod.default as unknown as Weapon5e[]);
  }
  return cache.get('w5e') as Weapon5e[];
}

export async function loadArmor5e(): Promise<Armor5e[]> {
  if (!cache.has('a5e')) {
    const mod = await import('@/data/srd/equipment.json');
    cache.set('a5e', (mod.default as { armor: Armor5e[] }).armor);
  }
  return cache.get('a5e') as Armor5e[];
}

export async function loadFeats5e(): Promise<Feat5e[]> {
  if (!cache.has('f5e')) {
    const mod = await import('@/data/srd/mpmb-feats.json');
    const obj = mod.default as Record<string, Feat5e>;
    cache.set('f5e', Object.values(obj).sort((a, b) => a.name.localeCompare(b.name)));
  }
  return cache.get('f5e') as Feat5e[];
}

export async function loadConditions5e(): Promise<Condition5e[]> {
  if (!cache.has('c5e')) {
    const mod = await import('@/data/srd/conditions.json');
    cache.set('c5e', mod.default as unknown as Condition5e[]);
  }
  return cache.get('c5e') as Condition5e[];
}

// ---- Structured ruleset classes (Open5e + Foundry pf2e; feed builder + compendium) ----
export async function loadClasses(system: SystemId): Promise<RulesetClass[]> {
  const key = `classes:${system}`;
  if (!cache.has(key)) {
    if (system === '5e') {
      const mod = await import('@/data/srd/classes.json');
      cache.set(key, mod.default as unknown as RulesetClass[]);
    } else {
      const res = await fetch(`${import.meta.env.BASE_URL}data/pf2e/classes.json`);
      cache.set(key, (res.ok ? await res.json() : []) as RulesetClass[]);
    }
  }
  return cache.get(key) as RulesetClass[];
}

export async function loadRaces5e(): Promise<{ slug: string; name: string; desc: string; asi: string; speed: string; vision: string; traits: string }[]> {
  if (!cache.has('races5e')) {
    const mod = await import('@/data/srd/races.json');
    cache.set('races5e', mod.default as unknown[]);
  }
  return cache.get('races5e') as { slug: string; name: string; desc: string; asi: string; speed: string; vision: string; traits: string }[];
}

export async function loadBackgrounds5e(): Promise<{ slug: string; name: string; desc: string; skills: string; feature: string }[]> {
  if (!cache.has('bg5e')) {
    const mod = await import('@/data/srd/backgrounds.json');
    cache.set('bg5e', mod.default as unknown[]);
  }
  return cache.get('bg5e') as { slug: string; name: string; desc: string; skills: string; feature: string }[];
}

// ---- PF2e categories (static assets fetched at runtime; large files) ----
const pf2eCache = new Map<string, CompendiumEntry[]>();

export async function loadPf2e(file: string): Promise<CompendiumEntry[]> {
  if (!pf2eCache.has(file)) {
    const res = await fetch(`${import.meta.env.BASE_URL}data/pf2e/${file}.json`);
    if (!res.ok) throw new Error(`Failed to load PF2e ${file} (${res.status})`);
    pf2eCache.set(file, (await res.json()) as CompendiumEntry[]);
  }
  return pf2eCache.get(file)!;
}

/** Build a combat-ready stat block summary from a monster. */
export function monsterToCombatant(m: Monster): {
  name: string;
  ac: number;
  hp: number;
} {
  return {
    name: m.name,
    ac: m.armor_class ?? 10,
    hp: m.hit_points ?? 1,
  };
}

export function crLabel(m: Monster): string {
  if (m.challenge_rating) return m.challenge_rating;
  if (m.cr === undefined) return '—';
  if (m.cr === 0.125) return '1/8';
  if (m.cr === 0.25) return '1/4';
  if (m.cr === 0.5) return '1/2';
  return String(m.cr);
}
