import fs from "node:fs";
import os from "node:os";
import path from "node:path";
import { describe, it, expect, beforeEach, afterEach } from "vitest";
import { runSpecFixtureSyncCheck } from "./spec-fixtures";

describe("runSpecFixtureSyncCheck", () => {
  let tmpDir: string;

  beforeEach(() => {
    tmpDir = fs.mkdtempSync(path.join(os.tmpdir(), "sync-check-spec-fixture-"));
  });

  afterEach(() => {
    fs.rmSync(tmpDir, { recursive: true, force: true });
  });

  function setupSpecFixture(specs: string[], fixtures: string[]) {
    const specDir = path.join(tmpDir, "my-app", "frontend", "e2e", "tests");
    const fixtureDir = path.join(tmpDir, "my-app", "frontend", "e2e", "fixtures");
    fs.mkdirSync(specDir, { recursive: true });
    fs.mkdirSync(fixtureDir, { recursive: true });
    for (const name of specs) {
      fs.writeFileSync(path.join(specDir, `${name}.spec.ts`), 'test("foo", async () => {});');
    }
    for (const name of fixtures) {
      fs.writeFileSync(path.join(fixtureDir, `${name}.ts`), "export {};");
    }
  }

  it("returns no errors when each spec has a matching fixture", async () => {
    setupSpecFixture(
      ["item-lifecycle", "user-management"],
      ["user", "item-lifecycle", "user-management"],
    );

    const { errors } = await runSpecFixtureSyncCheck("my-app", tmpDir);
    expect(errors).toHaveLength(0);
  });

  it("reports missing-spec-fixture when spec has no matching fixture", async () => {
    setupSpecFixture(["item-lifecycle"], ["user"]);

    const { errors } = await runSpecFixtureSyncCheck("my-app", tmpDir);
    expect(errors).toContainEqual(
      expect.objectContaining({
        type: "missing-spec-fixture",
        category: "e2e-fixture",
        expectedBasename: "item-lifecycle.ts",
      }),
    );
  });

  it("returns no errors when no spec files exist", async () => {
    fs.mkdirSync(path.join(tmpDir, "my-app"), { recursive: true });
    const { errors } = await runSpecFixtureSyncCheck("my-app", tmpDir);
    expect(errors).toHaveLength(0);
  });
});
