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

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

  beforeEach(() => {
    tmpDir = fs.mkdtempSync(path.join(os.tmpdir(), "erp-kit-app-test-"));
  });

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

  it("generates resolver stubs and tests from docs", () => {
    // Set up docs
    const docsDir = path.join(tmpDir, "docs", "resolver");
    fs.mkdirSync(docsDir, { recursive: true });

    fs.writeFileSync(
      path.join(docsDir, "createItem.md"),
      `# createItem

## Overview

Creates a new item.

## Modules Commands Used

- \`item-management.createItem\` — Creates a new item record

## Exception Handling

| Error Code | Description |
| --- | --- |
| DUPLICATE_SKU | SKU already exists |
`,
    );

    fs.writeFileSync(
      path.join(docsDir, "getMyProfile.md"),
      `# getMyProfile

## Overview

Gets profile.

## Modules Commands Used

- \`user-management.getMyProfile\` — Fetches profile
`,
    );

    const { exitCode } = runAppGenerateCode(tmpDir);
    expect(exitCode).toBe(0);

    const resolverDir = path.join(tmpDir, "backend", "src", "resolver");
    expect(fs.existsSync(resolverDir)).toBe(true);

    const files = fs.readdirSync(resolverDir).sort();
    expect(files).toContain("createItem.ts");
    expect(files).toContain("getMyProfile.ts");
    expect(files).not.toContain("createItem.generated.ts");

    // Stub has createResolver
    const stub = fs.readFileSync(path.join(resolverDir, "createItem.ts"), "utf-8");
    expect(stub).toContain("createResolver");
    expect(stub).toContain('name: "createItem"');
    expect(stub).toContain('getDB("main-db")');
  });

  it("does not overwrite existing stubs on re-run", () => {
    const docsDir = path.join(tmpDir, "docs", "resolver");
    fs.mkdirSync(docsDir, { recursive: true });
    fs.writeFileSync(
      path.join(docsDir, "createItem.md"),
      `# createItem

## Overview
Creates an item.

## Modules Commands Used
- \`item-management.createItem\` — Creates item
`,
    );

    runAppGenerateCode(tmpDir);

    // Modify the stub
    const resolverDir = path.join(tmpDir, "backend", "src", "resolver");
    const stubPath = path.join(resolverDir, "createItem.ts");
    fs.writeFileSync(stubPath, "// custom implementation");

    // Re-run
    runAppGenerateCode(tmpDir);

    // Stub should not be overwritten
    expect(fs.readFileSync(stubPath, "utf-8")).toBe("// custom implementation");
  });

  it("returns 0 with no docs/resolver directory", () => {
    const { exitCode } = runAppGenerateCode(tmpDir);
    expect(exitCode).toBe(0);
  });

  it("returns 0 with empty docs/resolver directory", () => {
    fs.mkdirSync(path.join(tmpDir, "docs", "resolver"), { recursive: true });
    const { exitCode } = runAppGenerateCode(tmpDir);
    expect(exitCode).toBe(0);
  });
});
