import { describe, expect, it } from 'vitest';
import type { FeatureSpec, LlmClient } 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; }';

function spec(): 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"); }' }],
    }],
  } as unknown as FeatureSpec;
}

class WorldAwareLlm {
  calls = 0;
  private recordWatch(): string {
    this.calls++;
    return 'IDIOM: addition\nUNION: inspect the current contract.';
  }

  async encodeFeatures() { return spec(); }
  async generateTests() { return { content: '', parts: { imports: [], cases: [] } }; }
  async fixTestCases(_spec: unknown, _feature: unknown, requested: { name: string }[]) {
    const name = requested[0]!.name;
    return {
      cases: [{
        name,
        kind: (name === 'zero' ? 'edge' : 'behavior') as 'edge' | 'behavior',
        body: name === 'zero' ? 'expect(add(7, 0)).toBe(7);' : 'expect(add(2, 3)).toBe(5);',
      }],
    };
  }
  async generateImplementation() { return [{ path: 'src/adder.ts', content: RIGHT }]; }
  async repair() { return [{ path: 'src/adder.ts', content: RIGHT }]; }
  async watchEpoch() { return this.recordWatch(); }
}

describe('SET 94d — watcher world advancement', () => {
  it('uses a receiver-dependent class double and skips failed-world re-synthesis', async () => {
    const llm = new WorldAwareLlm();
    const result = await runTier1Job({
      prompt: 'adder',
      llm: llm as unknown as LlmClient,
      runSuite: makeEvalSuiteRunner(),
    });

    expect(result.metrics.watcherWorldStaleSkips).toBeGreaterThan(0);
    expect(llm.calls).toBeLessThan(result.metrics.watcherSyntheses);
    expect(result.log.some(e => /skipped — no world advancement since node/.test(e.message))).toBe(true);
  });
});
