import fs from "node:fs";
import os from "node:os";
import path from "node:path";
import { describe, it, expect, afterEach } from "vitest";
import { scaffoldModule, scaffoldModuleBoilerplate } from "./init";

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

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

  it("creates expected directories and files", () => {
    tmpDir = fs.mkdtempSync(path.join(os.tmpdir(), "scaffold-test-"));
    const moduleDir = path.join(tmpDir, "test-module");
    fs.mkdirSync(moduleDir, { recursive: true });

    scaffoldModuleBoilerplate(moduleDir, "test-module");

    for (const dir of ["db", "command", "executor", "generated", "lib", "query", "testing"]) {
      expect(fs.existsSync(path.join(moduleDir, dir))).toBe(true);
    }

    for (const dir of ["db", "command", "executor", "query"]) {
      expect(fs.existsSync(path.join(moduleDir, dir, ".gitkeep"))).toBe(true);
    }

    const expectedFiles = [
      "module.ts",
      "index.ts",
      "lib/permissions.generated.ts",
      "tailor.config.ts",
      "package.json",
      "oxlint.config.ts",
      "tsconfig.json",
      "lib/types.ts",
      "testing/fixtures.ts",
      "generated/kysely-tailordb.ts",
    ];
    for (const file of expectedFiles) {
      expect(fs.existsSync(path.join(moduleDir, file))).toBe(true);
    }

    const permissions = fs.readFileSync(
      path.join(moduleDir, "lib/permissions.generated.ts"),
      "utf-8",
    );
    expect(permissions).toContain("definePermissions(");

    const config = fs.readFileSync(path.join(moduleDir, "tailor.config.ts"), "utf-8");
    expect(config).toContain('name: "test-module"');

    const pkg = fs.readFileSync(path.join(moduleDir, "package.json"), "utf-8");
    expect(pkg).toContain('"name": "test-module"');
    expect(pkg).not.toContain("workspace:*");

    const moduleFile = fs.readFileSync(path.join(moduleDir, "module.ts"), "utf-8");
    expect(moduleFile).toContain("defineModule");
    expect(moduleFile).toContain("commands");
    expect(moduleFile).toContain("queries");
  });
});

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

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

  it("creates module directory with scaffolded boilerplate", () => {
    tmpDir = fs.mkdtempSync(path.join(os.tmpdir(), "init-module-test-"));
    const exitCode = scaffoldModule("my-module", tmpDir);
    expect(exitCode).toBe(0);

    const moduleDir = path.join(tmpDir, "my-module");
    expect(fs.existsSync(moduleDir)).toBe(true);
    expect(fs.existsSync(path.join(moduleDir, "package.json"))).toBe(true);
    expect(fs.existsSync(path.join(moduleDir, "tailor.config.ts"))).toBe(true);
    expect(fs.existsSync(path.join(moduleDir, "index.ts"))).toBe(true);
  });

  it("succeeds if module directory already exists", () => {
    tmpDir = fs.mkdtempSync(path.join(os.tmpdir(), "init-module-test-"));
    const moduleDir = path.join(tmpDir, "my-module");
    fs.mkdirSync(moduleDir, { recursive: true });

    const exitCode = scaffoldModule("my-module", tmpDir);
    expect(exitCode).toBe(0);
  });
});
