/**
 * Corpus client: fetch the published passive corpus (rha.software/corpus/v1/)
 * and verify every file against the manifest's sha256 before use. Works in
 * browser and Node (WebCrypto + fetch are global in both).
 */
import type { LessonRecord } from '../core/lessons';

export const DEFAULT_CORPUS_BASE = 'https://rha.software/corpus/v1';

export interface CorpusManifest {
  corpusVersion: 1;
  appVersion: string;
  generatedAt: string;
  files: { name: string; sha256: string; bytes: number }[];
}

export interface Corpus {
  manifest: CorpusManifest;
  /** System prompts keyed by pipeline stage. */
  prompts: Record<string, string>;
  /** Canonical algorithm bounds: defaults + validation ranges. */
  gates: { defaults: Record<string, unknown>; ranges: Record<string, { min: number; max: number }> };
  lessons: LessonRecord[];
}

async function sha256Hex(text: string): Promise<string> {
  const digest = await crypto.subtle.digest('SHA-256', new TextEncoder().encode(text));
  return [...new Uint8Array(digest)].map(b => b.toString(16).padStart(2, '0')).join('');
}

export async function fetchCorpus(
  base = DEFAULT_CORPUS_BASE,
  fetchImpl: typeof fetch = fetch,
): Promise<Corpus> {
  const root = base.replace(/\/$/, '');
  const get = async (name: string): Promise<string> => {
    const res = await fetchImpl(`${root}/${name}`);
    if (!res.ok) throw new Error(`corpus fetch ${name}: HTTP ${res.status}`);
    return res.text();
  };

  const manifest = JSON.parse(await get('manifest.json')) as CorpusManifest;
  if (manifest.corpusVersion !== 1) {
    throw new Error(`unsupported corpusVersion ${manifest.corpusVersion} (runner speaks v1)`);
  }

  const verified: Record<string, string> = {};
  for (const f of manifest.files) {
    const text = await get(f.name);
    const hash = await sha256Hex(text);
    if (hash !== f.sha256) {
      throw new Error(`corpus integrity failure: ${f.name} sha256 ${hash} != manifest ${f.sha256}`);
    }
    verified[f.name] = text;
  }

  const prompts = JSON.parse(verified['prompts.json'] ?? '{}').stages ?? {};
  const gates = JSON.parse(verified['gates.json'] ?? '{}');
  const lessons = JSON.parse(verified['lessons.json'] ?? '{}').lessons ?? [];
  return { manifest, prompts, gates, lessons };
}
