import { DEFAULT_THEME_ID, THEME_REGISTRY_META } from '../lib/theme.js';
import { findUnwiredOverrides, type ModTheme } from '../lib/theme-contract.js';
import DefaultShell from './default/DefaultShell.astro';
import DefaultPostBody from './default/DefaultPostBody.astro';
import DefaultIndexBody from './default/DefaultIndexBody.astro';
import DefaultSearchBody from './default/DefaultSearchBody.astro';
import DefaultNotFoundBody from './default/DefaultNotFoundBody.astro';
import EditorialShell from './editorial/EditorialShell.astro';
import EditorialPostBody from './editorial/EditorialPostBody.astro';
import EditorialIndexBody from './editorial/EditorialIndexBody.astro';
import EditorialSearchBody from './editorial/EditorialSearchBody.astro';
import EditorialNotFoundBody from './editorial/EditorialNotFoundBody.astro';
import MagazineShell from './magazine/MagazineShell.astro';
import MagazinePostBody from './magazine/MagazinePostBody.astro';
import MagazineIndexBody from './magazine/MagazineIndexBody.astro';
import MagazineSearchBody from './magazine/MagazineSearchBody.astro';
import MagazineNotFoundBody from './magazine/MagazineNotFoundBody.astro';
import BlogShell from './blog/BlogShell.astro';
import BlogPostBody from './blog/BlogPostBody.astro';
import BlogIndexBody from './blog/BlogIndexBody.astro';
import BlogSearchBody from './blog/BlogSearchBody.astro';
import BlogNotFoundBody from './blog/BlogNotFoundBody.astro';

export {
  DefaultPostBody,
  DefaultIndexBody,
  DefaultSearchBody,
  DefaultNotFoundBody,
};

const THEMES: Record<string, ModTheme> = {
  default: {
    id: 'default',
    name: 'Default',
    Shell: DefaultShell,
    overrides: {
      index: DefaultIndexBody,
      search: DefaultSearchBody,
      'not-found': DefaultNotFoundBody,
    },
  },
  editorial: {
    id: 'editorial',
    name: 'Editorial',
    Shell: EditorialShell,
    overrides: {
      post: EditorialPostBody,
      index: EditorialIndexBody,
      search: EditorialSearchBody,
      'not-found': EditorialNotFoundBody,
    },
  },
  magazine: {
    id: 'magazine',
    name: 'Magazine',
    Shell: MagazineShell,
    overrides: {
      post: MagazinePostBody,
      index: MagazineIndexBody,
      search: MagazineSearchBody,
      'not-found': MagazineNotFoundBody,
    },
  },
  blog: {
    id: 'blog',
    name: 'Blog',
    Shell: BlogShell,
    overrides: {
      post: BlogPostBody,
      index: BlogIndexBody,
      search: BlogSearchBody,
      'not-found': BlogNotFoundBody,
    },
  },
};

// --- Fail-closed construction guard (spec §4 purity boundary) ---------------
// (a) registry/meta parity: keys === THEME_REGISTRY_META ids.
const metaIds = new Set(THEME_REGISTRY_META.map((t) => t.id));
const keyIds = new Set(Object.keys(THEMES));
if (metaIds.size !== keyIds.size || [...metaIds].some((id) => !keyIds.has(id))) {
  throw new Error(
    `theme registry/meta mismatch: meta=[${[...metaIds].sort()}] registry=[${[...keyIds].sort()}]`,
  );
}
// (b) override honesty: no theme may advertise an override on an unwired screen.
for (const theme of Object.values(THEMES)) {
  const unwired = findUnwiredOverrides(theme);
  if (unwired.length > 0) {
    throw new Error(
      `theme "${theme.id}" overrides unwired screen(s) [${unwired}] — wire the screen to resolveScreen and add it to WIRED_SCREENS, or remove the override`,
    );
  }
}

export const MOD_CMS_THEMES: Record<string, ModTheme> = THEMES;

/** Total theme lookup — unknown ids fall back to DEFAULT_THEME_ID (registry guard proves it exists). */
export function resolveModTheme(themeId: string): ModTheme {
  const theme = MOD_CMS_THEMES[themeId] ?? MOD_CMS_THEMES[DEFAULT_THEME_ID];
  if (!theme) {
    throw new Error(
      `theme registry invariant violated: missing default theme "${DEFAULT_THEME_ID}"`,
    );
  }
  return theme;
}
