import fs from "node:fs";
import os from "node:os";
import path from "node:path";
import { describe, it, expect, beforeEach, afterEach } from "vitest";
import { parseActorNamesFromFixture, runActorSyncCheck } from "./actors";

describe("parseActorNamesFromFixture", () => {
  it("extracts actor names from type union", () => {
    const content = `export type Actor = "admin" | "general-user";`;
    expect(parseActorNamesFromFixture(content)).toEqual(["admin", "general-user"]);
  });

  it("extracts single actor", () => {
    const content = `export type Actor = "admin";`;
    expect(parseActorNamesFromFixture(content)).toEqual(["admin"]);
  });

  it("returns empty array when no Actor type", () => {
    expect(parseActorNamesFromFixture("const x = 1;")).toEqual([]);
  });
});

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

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

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

  function setupActorFixture(fixtureContent: string, actorDocs: string[]) {
    const fixtureDir = path.join(tmpDir, "my-app", "frontend", "e2e", "fixtures");
    const actorDocDir = path.join(tmpDir, "my-app", "docs", "actor");
    fs.mkdirSync(fixtureDir, { recursive: true });
    fs.mkdirSync(actorDocDir, { recursive: true });
    fs.writeFileSync(path.join(fixtureDir, "user.ts"), fixtureContent);
    for (const doc of actorDocs) {
      fs.writeFileSync(path.join(actorDocDir, `${doc}.md`), `# ${doc}\n`);
    }
  }

  it("returns no errors when actors match", async () => {
    setupActorFixture(`export type Actor = "admin" | "general-user";`, ["admin", "general-user"]);

    const result = await runActorSyncCheck("my-app", tmpDir);
    expect(result.errors).toHaveLength(0);
    // 1 fixture file + 2 actor docs
    expect(result.filesChecked).toBe(3);
  });

  it("reports missing-actor-doc when fixture has actor without doc", async () => {
    setupActorFixture(`export type Actor = "admin" | "general-user";`, ["admin"]);

    const { errors } = await runActorSyncCheck("my-app", tmpDir);
    expect(errors).toContainEqual(
      expect.objectContaining({
        type: "missing-actor-doc",
        category: "actor",
        expectedBasename: "general-user.md",
      }),
    );
  });

  it("reports missing-actor-fixture when doc has actor without fixture", async () => {
    setupActorFixture(`export type Actor = "admin";`, ["admin", "general-user"]);

    const { errors } = await runActorSyncCheck("my-app", tmpDir);
    expect(errors).toContainEqual(
      expect.objectContaining({
        type: "missing-actor-fixture",
        category: "actor",
        expectedBasename: "general-user",
      }),
    );
  });

  it("returns no errors when fixture file does not exist", async () => {
    const actorDocDir = path.join(tmpDir, "my-app", "docs", "actor");
    fs.mkdirSync(actorDocDir, { recursive: true });
    fs.writeFileSync(path.join(actorDocDir, "admin.md"), "# admin\n");

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