/**
 * SET 37c — Mock-API mechanical class: harness provides full mock surface
 * (jest→vi alias AND bare spyOn/fn) plus deterministic suite rewrite fallback.
 */
import { describe, expect, it } from 'vitest';
import type { GeneratedFile } from '../src/core/types';
import {
  makeEvalSuiteRunner,
  rewriteJestToVi,
  rewriteMockApiSurface,
} from '../src/tier1/testExec';

describe('SET 37c harness mock surface', () => {
  it('suite using bare spyOn/fn without import does not ReferenceError', async () => {
    const files: GeneratedFile[] = [
      {
        path: 'src/svc.ts',
        content: [
          'export const svc = {',
          '  add(a: number, b: number) { return a + b; },',
          '};',
        ].join('\n'),
      },
    ];
    const test: GeneratedFile = {
      path: 'tests/f1.test.ts',
      content: [
        "import { describe, it, expect } from 'vitest';",
        "import { svc } from '../src/svc';",
        "describe('mock', () => {",
        "  it('bare fn', () => {",
        '    const mock = fn(() => 7);',
        '    expect(mock()).toBe(7);',
        '  });',
        "  it('bare spyOn', () => {",
        "    const spy = spyOn(svc, 'add');",
        '    spy.mockReturnValue(99);',
        '    expect(svc.add(1, 2)).toBe(99);',
        '    spy.mockRestore();',
        '  });',
        '});',
      ].join('\n'),
    };
    const runner = makeEvalSuiteRunner();
    const r = await runner(files, test);
    expect(r.crashed).toBeUndefined();
    expect(r.failures).toHaveLength(0);
    expect(r.total).toBe(2);
  });

  it('jest.fn / jest.spyOn still work via harness alias', async () => {
    const files: GeneratedFile[] = [
      { path: 'src/ok.ts', content: 'export function ok(): number { return 1; }\n' },
    ];
    const test: GeneratedFile = {
      path: 'tests/f1.test.ts',
      content: [
        "import { describe, it, expect } from 'vitest';",
        "import { ok } from '../src/ok';",
        "describe('t', () => {",
        "  it('jest', () => {",
        '    const f = jest.fn(() => ok());',
        '    expect(f()).toBe(1);',
        '  });',
        '});',
      ].join('\n'),
    };
    const r = await makeEvalSuiteRunner()(files, test);
    expect(r.crashed).toBeUndefined();
    expect(r.failures).toHaveLength(0);
  });

  it('rewriteMockApiSurface rewrites jest and bare spyOn/fn', () => {
    const src = [
      "import { describe, it, expect, jest } from 'vitest';",
      'const a = jest.fn();',
      'const b = spyOn(obj, "m");',
      'const c = fn();',
    ].join('\n');
    const next = rewriteMockApiSurface(src);
    expect(next).toBeTruthy();
    expect(next!).toContain('vi.fn');
    expect(next!).toContain('vi.spyOn');
    expect(next!).not.toMatch(/\bjest\./);
    // jest-only rewrite remains substrate-safe
    const jestOnly = rewriteJestToVi("import { jest } from 'vitest';\njest.fn();\n");
    expect(jestOnly).toContain('vi.fn');
    expect(jestOnly).not.toContain('jest.fn');
  });

  it('imported spyOn/fn from vitest resolve via harness require surface', async () => {
    const files: GeneratedFile[] = [
      { path: 'src/ok.ts', content: 'export const ok = { n: () => 1 };\n' },
    ];
    const test: GeneratedFile = {
      path: 'tests/f1.test.ts',
      content: [
        "import { describe, it, expect, spyOn, fn } from 'vitest';",
        "import { ok } from '../src/ok';",
        "describe('t', () => {",
        "  it('imported', () => {",
        '    const f = fn(() => 2);',
        '    expect(f()).toBe(2);',
        "    const s = spyOn(ok, 'n').mockReturnValue(3);",
        '    expect(ok.n()).toBe(3);',
        '    s.mockRestore();',
        '  });',
        '});',
      ].join('\n'),
    };
    const r = await makeEvalSuiteRunner()(files, test);
    expect(r.crashed).toBeUndefined();
    expect(r.failures).toHaveLength(0);
  });
});
