import fs from "node:fs";
import os from "node:os";
import path from "node:path";
import { afterEach, beforeEach, describe, expect, it } from "vitest";
import { findMissingComponentTests } from "./component-tests";

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

  beforeEach(() => {
    tmpDir = fs.mkdtempSync(path.join(os.tmpdir(), "verify-component-"));
  });

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

  function writeComponent(relPath: string, content = "export const C = () => null;\n") {
    const full = path.join(tmpDir, "my-app", "frontend", "src", "components", relPath);
    fs.mkdirSync(path.dirname(full), { recursive: true });
    fs.writeFileSync(full, content);
  }

  it("returns nothing when every component has a co-located test", async () => {
    writeComponent("composed/empty-state.tsx");
    writeComponent("composed/empty-state.test.tsx");

    expect(await findMissingComponentTests("my-app", tmpDir)).toHaveLength(0);
  });

  it("reports a component with no co-located test", async () => {
    writeComponent("composed/error-fallback.tsx");

    const missing = await findMissingComponentTests("my-app", tmpDir);
    expect(missing).toContainEqual(
      expect.objectContaining({ expectedTest: "error-fallback.test.tsx" }),
    );
  });

  it("ignores shadcn ui primitives under components/ui", async () => {
    writeComponent("ui/spinner.tsx");

    expect(await findMissingComponentTests("my-app", tmpDir)).toHaveLength(0);
  });

  it("respects the /* no-test: */ opt-out marker", async () => {
    writeComponent(
      "composed/divider.tsx",
      "/* no-test: presentational */\nexport const Divider = () => null;\n",
    );

    expect(await findMissingComponentTests("my-app", tmpDir)).toHaveLength(0);
  });

  it("does not treat a test file as a component needing its own test", async () => {
    writeComponent("composed/loading.tsx");
    writeComponent("composed/loading.test.tsx");

    expect(await findMissingComponentTests("my-app", tmpDir)).toHaveLength(0);
  });

  it("returns nothing when there are no components", async () => {
    fs.mkdirSync(path.join(tmpDir, "my-app"), { recursive: true });
    expect(await findMissingComponentTests("my-app", tmpDir)).toHaveLength(0);
  });
});
