import fs from "node:fs";
import os from "node:os";
import path from "node:path";
import { describe, it, expect, beforeEach, afterEach } from "vitest";
import { runModuleTestCaseSyncCheck } from "./module-test-cases";

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

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

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

  it("reports missing-test-case when doc has case not in test", async () => {
    const docDir = path.join(tmpDir, "modules", "foo", "docs", "command");
    const testDir = path.join(tmpDir, "modules", "foo", "command");
    fs.mkdirSync(docDir, { recursive: true });
    fs.mkdirSync(testDir, { recursive: true });

    fs.writeFileSync(
      path.join(docDir, "CreateOrder.md"),
      "# CreateOrder\n\n## Test Cases\n\n- creates order\n- validates input\n",
    );
    fs.writeFileSync(path.join(testDir, "createOrder.ts"), "export {}");
    fs.writeFileSync(
      path.join(testDir, "createOrder.test.ts"),
      'describe("createOrder", () => { it("creates order", async () => {}); });',
    );

    const { errors } = await runModuleTestCaseSyncCheck("modules", tmpDir);
    expect(errors).toContainEqual(
      expect.objectContaining({
        type: "missing-test-case",
        category: "command-test-case",
        expectedBasename: "validates input",
      }),
    );
  });

  it("reports extra-test-case when test has case not in doc", async () => {
    const docDir = path.join(tmpDir, "modules", "foo", "docs", "command");
    const testDir = path.join(tmpDir, "modules", "foo", "command");
    fs.mkdirSync(docDir, { recursive: true });
    fs.mkdirSync(testDir, { recursive: true });

    fs.writeFileSync(
      path.join(docDir, "CreateOrder.md"),
      "# CreateOrder\n\n## Test Cases\n\n- creates order\n",
    );
    fs.writeFileSync(path.join(testDir, "createOrder.ts"), "export {}");
    fs.writeFileSync(
      path.join(testDir, "createOrder.test.ts"),
      'describe("createOrder", () => { it("creates order", async () => {}); it("extra case", async () => {}); });',
    );

    const { errors } = await runModuleTestCaseSyncCheck("modules", tmpDir);
    expect(errors).toContainEqual(
      expect.objectContaining({
        type: "extra-test-case",
        category: "command-test-case",
        expectedBasename: "extra case",
      }),
    );
  });

  it("returns 0 when doc test cases match test it() descriptions", async () => {
    const docDir = path.join(tmpDir, "modules", "foo", "docs", "command");
    const testDir = path.join(tmpDir, "modules", "foo", "command");
    fs.mkdirSync(docDir, { recursive: true });
    fs.mkdirSync(testDir, { recursive: true });

    fs.writeFileSync(
      path.join(docDir, "CreateOrder.md"),
      "# CreateOrder\n\n## Test Cases\n\n- creates order\n- validates input\n",
    );
    fs.writeFileSync(path.join(testDir, "createOrder.ts"), "export {}");
    fs.writeFileSync(
      path.join(testDir, "createOrder.test.ts"),
      'describe("createOrder", () => { it("creates order", async () => {}); it("validates input", async () => {}); });',
    );

    const { errors } = await runModuleTestCaseSyncCheck("modules", tmpDir);
    const tcErrors = errors.filter(
      (e) => e.type === "missing-test-case" || e.type === "extra-test-case",
    );
    expect(tcErrors).toHaveLength(0);
  });

  it("reports missing-test-file when test file does not exist", async () => {
    const docDir = path.join(tmpDir, "modules", "foo", "docs", "command");
    const testDir = path.join(tmpDir, "modules", "foo", "command");
    fs.mkdirSync(docDir, { recursive: true });
    fs.mkdirSync(testDir, { recursive: true });

    fs.writeFileSync(
      path.join(docDir, "CreateOrder.md"),
      "# CreateOrder\n\n## Test Cases\n\n- creates order\n- validates input\n",
    );
    fs.writeFileSync(path.join(testDir, "createOrder.ts"), "export {}");
    // No createOrder.test.ts file

    const { errors } = await runModuleTestCaseSyncCheck("modules", tmpDir);
    expect(errors).toContainEqual(
      expect.objectContaining({
        type: "missing-test-file",
        category: "command-test-case",
        expectedBasename: "createOrder.test.ts",
      }),
    );
  });

  it("skips test-case check when doc has no Test Cases section", async () => {
    const docDir = path.join(tmpDir, "modules", "foo", "docs", "command");
    const testDir = path.join(tmpDir, "modules", "foo", "command");
    fs.mkdirSync(docDir, { recursive: true });
    fs.mkdirSync(testDir, { recursive: true });

    fs.writeFileSync(
      path.join(docDir, "CreateOrder.md"),
      "# CreateOrder\n\n## Overview\n\nSome text.\n",
    );
    fs.writeFileSync(path.join(testDir, "createOrder.ts"), "export {}");
    fs.writeFileSync(
      path.join(testDir, "createOrder.test.ts"),
      'describe("createOrder", () => { it("creates order", async () => {}); });',
    );

    const { errors } = await runModuleTestCaseSyncCheck("modules", tmpDir);
    const tcErrors = errors.filter(
      (e) => e.type === "missing-test-case" || e.type === "extra-test-case",
    );
    expect(tcErrors).toHaveLength(0);
  });
});
