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

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

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

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

  function setupStoryFixture(storyName: string, storyContent: string, testContent: string) {
    const flow = "item-lifecycle";
    const storyDir = path.join(tmpDir, "my-app", "docs", "business-flow", flow, "story");
    const testDir = path.join(tmpDir, "my-app", "backend", "src", "tests", "story", flow);
    fs.mkdirSync(storyDir, { recursive: true });
    fs.mkdirSync(testDir, { recursive: true });
    fs.writeFileSync(path.join(storyDir, `${storyName}.md`), storyContent);
    fs.writeFileSync(path.join(testDir, `${storyName}.test.ts`), testContent);
  }

  it("reports missing-test-case when story doc has case not in test", async () => {
    setupStoryFixture(
      "admin--create-item",
      "# Create Item\n\n## Test Cases\n\n- creates item\n- validates input\n",
      'describe("admin--create-item", () => { it("creates item", async () => {}); });',
    );

    const { errors } = await runAppTestCaseSyncCheck("my-app", tmpDir);
    expect(errors).toContainEqual(
      expect.objectContaining({
        type: "missing-test-case",
        category: "story-test-case",
        expectedBasename: "validates input",
      }),
    );
  });

  it("reports extra-test-case when test has case not in story doc", async () => {
    setupStoryFixture(
      "admin--create-item",
      "# Create Item\n\n## Test Cases\n\n- creates item\n",
      'describe("admin--create-item", () => { it("creates item", async () => {}); it("extra case", async () => {}); });',
    );

    const { errors } = await runAppTestCaseSyncCheck("my-app", tmpDir);
    expect(errors).toContainEqual(
      expect.objectContaining({
        type: "extra-test-case",
        category: "story-test-case",
        expectedBasename: "extra case",
      }),
    );
  });

  it("returns no errors when story doc and test match", async () => {
    setupStoryFixture(
      "admin--create-item",
      "# Create Item\n\n## Test Cases\n\n- creates item\n- validates input\n",
      'describe("admin--create-item", () => { it("creates item", async () => {}); it("validates input", async () => {}); });',
    );

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

  it("reports missing-test-file when story test file does not exist", async () => {
    const flow = "item-lifecycle";
    const storyDir = path.join(tmpDir, "my-app", "docs", "business-flow", flow, "story");
    fs.mkdirSync(storyDir, { recursive: true });
    // No test file created
    fs.writeFileSync(
      path.join(storyDir, "admin--create-item.md"),
      "# Create Item\n\n## Test Cases\n\n- creates item\n- validates input\n",
    );

    const { errors } = await runAppTestCaseSyncCheck("my-app", tmpDir);
    expect(errors).toContainEqual(
      expect.objectContaining({
        type: "missing-test-file",
        category: "story-test-case",
        expectedBasename: "admin--create-item.test.ts",
      }),
    );
  });

  it("skips when story doc has no Test Cases section", async () => {
    setupStoryFixture(
      "admin--view-items",
      "# View Items\n\n## Scenario Patterns\n\n- Browse items\n",
      'describe("admin--view-items", () => { it("some test", async () => {}); });',
    );

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