import { describe, it, expect, vi, beforeEach } from "vitest";
import { runDocModule } from "./module";

describe("runDocModule", () => {
  beforeEach(() => {
    vi.restoreAllMocks();
  });

  it("outputs README and available docs for a known module", () => {
    const logs: string[] = [];
    vi.spyOn(console, "log").mockImplementation((...args: unknown[]) => {
      logs.push(args.map(String).join(" "));
    });

    const exitCode = runDocModule("organization");
    expect(exitCode).toBe(0);

    const output = logs.join("\n");
    expect(output).toContain("## Overview");
    expect(output).toContain("## Available Documentation");
    expect(output).toContain("CreateCompany");
    expect(output).toContain("GetCompany");
    expect(output).toContain("Company");
  });

  it("outputs raw doc content for a specific command", () => {
    const logs: string[] = [];
    vi.spyOn(console, "log").mockImplementation((...args: unknown[]) => {
      logs.push(args.map(String).join(" "));
    });

    const exitCode = runDocModule("organization", "command", "CreateCompany");
    expect(exitCode).toBe(0);

    const output = logs.join("\n");
    expect(output).toContain("# CreateCompany");
    expect(output).toContain("## Overview");
    expect(output).toContain("## Business Rules");
    expect(output).toContain("## Error Scenarios");
  });

  it("returns error for unknown module", () => {
    const errors: string[] = [];
    vi.spyOn(console, "error").mockImplementation((...args: unknown[]) => {
      errors.push(args.map(String).join(" "));
    });

    const exitCode = runDocModule("nonexistent");
    expect(exitCode).toBe(1);

    const output = errors.join("\n");
    expect(output).toContain("Module not found: nonexistent");
    expect(output).toContain("Available modules:");
  });

  it("returns error for unknown doc type", () => {
    const errors: string[] = [];
    vi.spyOn(console, "error").mockImplementation((...args: unknown[]) => {
      errors.push(args.map(String).join(" "));
    });

    const exitCode = runDocModule("organization", "invalid", "Foo");
    expect(exitCode).toBe(1);

    const output = errors.join("\n");
    expect(output).toContain("Unknown doc type: invalid");
    expect(output).toContain("Available types:");
  });

  it("outputs valid JSON for module detail with --format json", () => {
    const logs: string[] = [];
    vi.spyOn(console, "log").mockImplementation((...args: unknown[]) => {
      logs.push(args.map(String).join(" "));
    });

    const exitCode = runDocModule("organization", undefined, undefined, "json");
    expect(exitCode).toBe(0);

    const parsed = JSON.parse(logs.join("\n")) as Record<string, unknown>;
    expect(parsed).toHaveProperty("module", "organization");
    expect(parsed).toHaveProperty("readme");
    expect(parsed).toHaveProperty("docs");
    expect(typeof parsed.readme).toBe("string");
    const docs = parsed.docs as Record<string, string[]>;
    expect(docs.command.length).toBeGreaterThan(0);
  });

  it("outputs valid JSON for specific command with --format json", () => {
    const logs: string[] = [];
    vi.spyOn(console, "log").mockImplementation((...args: unknown[]) => {
      logs.push(args.map(String).join(" "));
    });

    const exitCode = runDocModule("organization", "command", "CreateCompany", "json");
    expect(exitCode).toBe(0);

    const parsed = JSON.parse(logs.join("\n")) as Record<string, unknown>;
    expect(parsed).toHaveProperty("module", "organization");
    expect(parsed).toHaveProperty("type", "command");
    expect(parsed).toHaveProperty("name", "CreateCompany");
    expect(parsed).toHaveProperty("content");
    expect(typeof parsed.content).toBe("string");
    expect(parsed.content as string).toContain("# CreateCompany");
  });

  it("returns error for unknown doc name", () => {
    const errors: string[] = [];
    vi.spyOn(console, "error").mockImplementation((...args: unknown[]) => {
      errors.push(args.map(String).join(" "));
    });

    const exitCode = runDocModule("organization", "command", "Nonexistent");
    expect(exitCode).toBe(1);

    const output = errors.join("\n");
    expect(output).toContain("Doc not found: organization/command/Nonexistent");
    expect(output).toContain("Available commands:");
  });
});
