/**
 * SET 66 — test-RHA at freeze: sick-red cases (the case's own defect) are
 * repaired or honestly dropped BEFORE the contract freezes; the RHA phase
 * never edits frozen suites for freeze-detectable defects.
 */
import { describe, expect, it } from 'vitest';
import type { FeatureSpec, LlmClient, RepairInput } from '../src/core/types';
import { runTier1Job } from '../src/tier1/runner';
import { makeEvalSuiteRunner } from '../src/tier1/testExec';

const RIGHT = 'export function add(a: number, b: number): number { return a + b; }';
const GOOD_A = 'expect(add(2, 3)).toBe(5);';
const GOOD_B = 'expect(add(7, 0)).toBe(7);';
// Sick: parses, passes fill conformance (references the allowed symbol), but
// is red at born-red for the WRONG reason — add.create is not a function.
const SICK_B = 'expect((add as unknown as { create: (n: number) => number }).create(7)).toBe(7);';

function makeSpec(): FeatureSpec {
  return {
    title: 'Adder', prompt: 'adder',
    features: [{
      id: 'F1', name: 'add', description: 'adds two numbers', parentId: null,
      deps: [], files: ['src/adder.ts'], testFile: 'tests/f1-add.test.ts',
      edgeCases: ['zero'], envVars: [],
      exports: [{ file: 'src/adder.ts', symbol: 'add' }],
      stubs: [{ path: 'src/adder.ts', content: `export function add(a: number, b: number): number { throw new Error('stub: not implemented'); }` }],
    }],
  } as unknown as FeatureSpec;
}

function makeLlm(rescueBody: string | null): LlmClient {
  return {
    async encodeFeatures() { return makeSpec(); },
    async generateTests() { return { content: '', parts: { imports: [], cases: [] } }; },
    async generateImplementation() { return [{ path: 'src/adder.ts', content: RIGHT }]; },
    async repair(_i: RepairInput) { return [{ path: 'src/adder.ts', content: RIGHT }]; },
    async fixTestCases(
      _s: unknown, _f: unknown, req: { name: string }[], _imp: unknown, _cur: unknown,
      opts?: { purpose?: string },
    ) {
      if (opts?.purpose?.startsWith('test-rha:')) {
        // Freeze-gate redraw for the sick case.
        return { cases: [{ name: req[0]!.name, kind: 'edge' as const, body: rescueBody ?? '' }] };
      }
      // SET 71 per-node draws: respond per requested case name.
      const name = req[0]!.name;
      return {
        cases: [{
          name,
          kind: (name === 'zero' ? 'edge' : 'behavior') as 'edge' | 'behavior',
          body: name === 'zero' ? SICK_B : GOOD_A,
        }],
      };
    },
  } as unknown as LlmClient;
}

describe('SET 66 — test-RHA at freeze', () => {
  it('sick-red case is redrawn at the freeze gate; contract freezes honest and heals in build', async () => {
    const res = await runTier1Job({ prompt: 'adder', llm: makeLlm(GOOD_B), runSuite: makeEvalSuiteRunner() });
    const msgs = res.log.map(e => e.message);
    expect(msgs.some(m => /^test-rha: \d+ sick-red/.test(m))).toBe(true);
    // SET 92 — per-attempt disposition lines replace the opaque "redrawn" line.
    expect(msgs.some(m => /test-rha: draft accepted \(try \d+\/\d+/.test(m))).toBe(true);
    expect(msgs.some(m => /test-rha: case "zero" cleared/.test(m))).toBe(true);
    expect(res.metrics.sickRedCases).toBeGreaterThanOrEqual(1);
    expect(res.metrics.testRhaDraws).toBeGreaterThanOrEqual(1);
    // The frozen contract carries the healthy body, not the sick one.
    const suite = res.frozenTests[0]?.content ?? '';
    expect(suite).toContain(GOOD_B);
    expect(suite).not.toContain('.create(7)');
    // And the RHA phase never had to edit the contract.
    expect(res.metrics.irSurgeriesInRha).toBe(0);
    expect(res.problems.length).toBe(0);
  });

  it('unrepairable sick-red is dropped at the gate — never frozen, never fought in RHA', async () => {
    const res = await runTier1Job({ prompt: 'adder', llm: makeLlm(null), runSuite: makeEvalSuiteRunner() });
    const msgs = res.log.map(e => e.message);
    expect(msgs.some(m => /test-rha: case "zero" dropped at freeze-gate/.test(m))).toBe(true);
    expect(res.problems.some(p => /dropped at freeze-gate — sick-red unrepairable/.test(p))).toBe(true);
    const suite = res.frozenTests[0]?.content ?? '';
    expect(suite).toContain(GOOD_A);
    expect(suite).not.toContain('.create(7)');
    expect(res.metrics.irSurgeriesInRha).toBe(0);
  });
});
