/**
 * SET 61 — exact-name delegation handlers for is-not-a-function|<m>.
 * Fixture-verified end-to-end: the mechanical fix is applied and the REAL
 * suite runner must go green; ambiguity must refuse, never guess.
 */
import { describe, expect, it } from 'vitest';
import type { FeatureSpec, GeneratedFile } from '../src/core/types';
import { attemptMechanicalFix, classifyFailure } from '../src/tier1/substrate';
import { buildTestProgram, makeEvalSuiteRunner } from '../src/tier1/testExec';

const SPEC = { title: 'x', prompt: 'x', features: [] } as unknown as FeatureSpec;

function applyFix(artifact: GeneratedFile[], fix: { path: string; content: string }): GeneratedFile[] {
  return artifact.map(f => (f.path === fix.path ? { ...f, content: fix.content } : f));
}

describe('SET 61 — member conformance shims', () => {
  it('H1: instance method expected, module function present (same file) → healed, suite green', async () => {
    const impl: GeneratedFile = {
      path: 'src/article_store.ts',
      content: [
        'export class ArticleStore {',
        '  articles: string[] = [];',
        '}',
        'export function create(title: string): { title: string; slug: string } {',
        "  return { title, slug: title.toLowerCase().replace(/\\s+/g, '-') };",
        '}',
      ].join('\n'),
    };
    const suite: GeneratedFile = {
      path: 'tests/article_store.test.ts',
      content: [
        "import { describe, it, expect } from 'vitest';",
        "import { ArticleStore } from '../src/article_store';",
        "describe('store', () => {",
        "  it('creates with slug', () => {",
        '    const store = new ArticleStore();',
        "    expect(store.create('Hello World').slug).toBe('hello-world');",
        '  });',
        '});',
      ].join('\n'),
    };
    const failure = classifyFailure('creates with slug', 'TypeError: store.create is not a function');
    expect(failure.kind).toBe('is-not-a-function');
    const attempt = attemptMechanicalFix(failure, [impl], suite, SPEC);
    expect(attempt.status).toBe('fixed');
    const healed = applyFix([impl], attempt.fix!);
    const r = await makeEvalSuiteRunner()(healed, { path: suite.path, content: suite.content });
    expect(r.crashed ?? null).toBeNull();
    expect(r.failures.length).toBe(0);
  });

  it('H3: bare call expected, single class donor with zero-arg ctor → healed, suite green', async () => {
    const impl: GeneratedFile = {
      path: 'src/text_kit.ts',
      content: [
        'export class TextKit {',
        '  slugify(s: string): string {',
        "    return s.toLowerCase().replace(/\\s+/g, '-');",
        '  }',
        '}',
      ].join('\n'),
    };
    const suite: GeneratedFile = {
      path: 'tests/text_kit.test.ts',
      content: [
        "import { describe, it, expect } from 'vitest';",
        "import { slugify } from '../src/text_kit';",
        "describe('slugify', () => {",
        "  it('kebabs', () => { expect(slugify('Hello World')).toBe('hello-world'); });",
        '});',
      ].join('\n'),
    };
    const failure = classifyFailure('kebabs', 'TypeError: (0 , slugify) is not a function');
    expect(failure.kind).toBe('is-not-a-function');
    const attempt = attemptMechanicalFix(failure, [impl], suite, SPEC);
    expect(attempt.status).toBe('fixed');
    const healed = applyFix([impl], attempt.fix!);
    const r = await makeEvalSuiteRunner()(healed, { path: suite.path, content: suite.content });
    expect(r.crashed ?? null).toBeNull();
    expect(r.failures.length).toBe(0);
  });

  it('ambiguity: two class donors for a bare call → refused, never guesses', () => {
    const a: GeneratedFile = {
      path: 'src/a.ts',
      content: 'export class A {\n  render(s: string): string { return s; }\n}',
    };
    const b: GeneratedFile = {
      path: 'src/b.ts',
      content: 'export class B {\n  render(s: string): string { return s + s; }\n}',
    };
    const suite: GeneratedFile = {
      path: 'tests/r.test.ts',
      content: "import { render } from '../src/a';\nit('r', () => { expect(render('x')).toBe('x'); });",
    };
    const failure = classifyFailure('r', 'TypeError: (0 , render) is not a function');
    const attempt = attemptMechanicalFix(failure, [a, b], suite, SPEC);
    expect(attempt.status).toBe('refused');
    expect(attempt.reason).toMatch(/ambiguous/);
  });
});
