/**
 * SET 64c — flawed-exhibit page: enclosing-node excerpts, symbol-span
 * fallback, provable absence, anti-anchoring header, 300-char cap.
 */
import { describe, expect, it } from 'vitest';
import {
  buildFlawedExhibit,
  EXHIBIT_CAP,
  EXHIBIT_HEADER,
  extractLineHint,
  extractLineSpan,
  extractSymbolSpan,
} from '../src/tier1/exhibit';
import { classifyFailure } from '../src/tier1/substrate';

const IMPL = [
  'export function add(a: number, b: number): number {',
  '  return a - b;',
  '}',
  '',
  'export const VERSION = 1;',
].join('\n');

describe('SET 64c — flawed exhibit', () => {
  it('symbol span: brace-matched node, header framed, hashed', () => {
    const ex = buildFlawedExhibit({
      cls: classifyFailure('sums', 'expected 3, received -1'),
      files: [{ path: 'src/add.ts', content: IMPL }],
      symbol: 'add',
      fallbackFile: 'src/add.ts',
    });
    expect(ex).not.toBeNull();
    expect(ex!.text).toContain(EXHIBIT_HEADER);
    expect(ex!.text).toContain('return a - b;');
    expect(ex!.text).not.toContain('VERSION');
    expect(ex!.source).toBe('symbol-span');
    expect(ex!.hash).toMatch(/^[0-9a-f]{8}-/);
  });

  it('provable absence is itself evidence', () => {
    const ex = buildFlawedExhibit({
      cls: null,
      files: [{ path: 'src/add.ts', content: 'export const other = 1;' }],
      symbol: 'add',
      fallbackFile: 'src/add.ts',
    });
    expect(ex!.source).toBe('symbol-absent');
    expect(ex!.text).toMatch(/provably absent/);
  });

  it('position path: line hint → enclosing function span', () => {
    expect(extractLineHint('crash at src/add.ts:2 boom', 'src/add.ts')).toBe(2);
    const span = extractLineSpan(IMPL, 2);
    expect(span).toContain('export function add');
    expect(span).toContain('return a - b;');
  });

  it('cap: giant nodes clip at the budget', () => {
    const giant = `export function big() {\n${'  const x = 1;\n'.repeat(200)}}`;
    const span = extractSymbolSpan(giant, 'big');
    expect(span!.length).toBeLessThanOrEqual(EXHIBIT_CAP + 1);
    expect(span!.endsWith('…')).toBe(true);
  });

  it('no position, no symbol → null (nothing to cite)', () => {
    expect(buildFlawedExhibit({ cls: null, files: [], symbol: null })).toBeNull();
  });
});
