/**
 * Persistent repair lessons — the substrate is read, not just written.
 * Lessons OUTLIVE a run via data/lessons.jsonl (gitignored under data/).
 */
import fs from 'node:fs';
import path from 'node:path';
import { fileURLToPath } from 'node:url';

export interface LessonRecord {
  classKey: string;
  /** Plain-text idiom, e.g. "TS2305: suite imports member X absent from src/foo.ts". */
  idiom: string;
  /** Applied resolution description / mechanical hint. */
  resolution: string;
  /** Optional: exported member name for missing-member lessons. */
  member?: string;
  /** Optional: routed stub path. */
  target?: string;
  /** Optional: inferred signature snippet for additive widen. */
  signature?: string;
  ts: string;
}

const ROOT = path.resolve(path.dirname(fileURLToPath(import.meta.url)), '..', '..');
const LESSONS_PATH = path.join(ROOT, 'data', 'lessons.jsonl');

let cache: LessonRecord[] | null = null;

export function lessonsPath(): string {
  return LESSONS_PATH;
}

export function loadLessons(file = LESSONS_PATH): LessonRecord[] {
  try {
    if (!fs.existsSync(file)) {
      cache = [];
      return cache;
    }
    const lines = fs.readFileSync(file, 'utf8').split('\n').filter(Boolean);
    cache = lines.map(l => JSON.parse(l) as LessonRecord);
    return cache;
  } catch {
    cache = [];
    return cache;
  }
}

export function getLessons(): LessonRecord[] {
  if (cache == null) loadLessons();
  return cache ?? [];
}

export function resetLessonsCache(): void {
  cache = null;
}

/** Append one lesson to jsonl + in-memory cache. Dedupes exact classKey+member+target. */
export function appendLesson(rec: LessonRecord, file = LESSONS_PATH): void {
  const all = getLessons();
  const dup = all.find(
    x => x.classKey === rec.classKey
      && (x.member ?? '') === (rec.member ?? '')
      && (x.target ?? '') === (rec.target ?? ''),
  );
  if (dup) return;
  fs.mkdirSync(path.dirname(file), { recursive: true });
  fs.appendFileSync(file, JSON.stringify(rec) + '\n');
  all.push(rec);
  cache = all;
}

export function findLessons(classKey: string): LessonRecord[] {
  return getLessons().filter(l => l.classKey === classKey || classKey.startsWith(l.classKey.split('|')[0]));
}

/** Format matching lessons for repair prompts ("checked idioms"). */
export function checkedIdiomsText(classKeys: string[]): string {
  const seen = new Set<string>();
  const lines: string[] = [];
  for (const ck of classKeys) {
    for (const l of findLessons(ck)) {
      const id = `${l.classKey}|${l.member ?? ''}|${l.target ?? ''}`;
      if (seen.has(id)) continue;
      seen.add(id);
      lines.push(`- ${l.idiom} → ${l.resolution}`);
    }
  }
  if (!lines.length) return '';
  return `Checked idioms (apply mechanically when they match — do not rediscover):\n${lines.join('\n')}`;
}

export function makeClassKey(bugClass: string, target: string, member?: string | null): string {
  return member ? `${bugClass}|${target}|${member}` : `${bugClass}|${target}`;
}
