import { describe, expect, it } from "vitest";
import { moduleNameToPrefix, generateErrors } from "./generate-errors";
import type { ParsedCommandDoc } from "./parse-command-doc";

describe("moduleNameToPrefix", () => {
  it("converts module name to UPPER_SNAKE_CASE prefix", () => {
    expect(moduleNameToPrefix("item-management")).toBe("ITEM_MANAGEMENT");
    expect(moduleNameToPrefix("primitives")).toBe("PRIMITIVES");
    expect(moduleNameToPrefix("user-management")).toBe("USER_MANAGEMENT");
    expect(moduleNameToPrefix("product-management")).toBe("PRODUCT_MANAGEMENT");
  });
});

describe("generateErrors", () => {
  it("generates error classes with module-prefixed codes", () => {
    const docs: ParsedCommandDoc[] = [
      {
        commandName: "createItem",
        permissionScope: "item",
        errors: [
          { code: "DUPLICATE_SKU", description: "An item with the same SKU already exists" },
          { code: "UNIT_NOT_FOUND", description: "Referenced unit does not exist or is inactive" },
        ],
        externalDependencies: [],
      },
      {
        commandName: "activateItem",
        permissionScope: "item",
        errors: [
          { code: "ITEM_NOT_FOUND", description: "Item does not exist" },
          { code: "INVALID_STATE_TRANSITION", description: "Item is not in a valid state" },
        ],
        externalDependencies: [],
      },
    ];

    const result = generateErrors("item-management", docs);

    expect(result).toContain("// @generated — do not edit");
    expect(result).toContain('import { createDomainError } from "@tailor-platform/erp-kit/core";');
    expect(result).toContain("export const DuplicateSkuError = createDomainError(");
    expect(result).toContain('"DuplicateSkuError", "ITEM_MANAGEMENT_DUPLICATE_SKU"');
    expect(result).toContain("export const UnitNotFoundError = createDomainError(");
    expect(result).toContain('"UnitNotFoundError", "ITEM_MANAGEMENT_UNIT_NOT_FOUND"');
    expect(result).toContain("export const ItemNotFoundError = createDomainError(");
    expect(result).toContain("export const InvalidStateTransitionError = createDomainError(");
  });

  it("deduplicates error codes across commands", () => {
    const docs: ParsedCommandDoc[] = [
      {
        commandName: "createItem",
        permissionScope: "item",
        errors: [{ code: "ITEM_NOT_FOUND", description: "Item does not exist" }],
        externalDependencies: [],
      },
      {
        commandName: "updateItem",
        permissionScope: "item",
        errors: [{ code: "ITEM_NOT_FOUND", description: "Item does not exist" }],
        externalDependencies: [],
      },
    ];

    const result = generateErrors("item-management", docs);

    const matches = result.match(/ItemNotFoundError/g);
    // Class name appears exactly twice: export declaration + first arg to createDomainError
    expect(matches).toHaveLength(2);
  });

  it("throws when same code has different descriptions across commands", () => {
    const docs: ParsedCommandDoc[] = [
      {
        commandName: "activateCompany",
        permissionScope: "company",
        errors: [{ code: "INVALID_STATE", description: "Company is not in DRAFT status" }],
        externalDependencies: [],
      },
      {
        commandName: "deactivateCompany",
        permissionScope: "company",
        errors: [{ code: "INVALID_STATE", description: "Company is not in ACTIVE status" }],
        externalDependencies: [],
      },
    ];

    expect(() => generateErrors("organization", docs)).toThrow(/INVALID_STATE/);
    expect(() => generateErrors("organization", docs)).toThrow(/activateCompany/);
    expect(() => generateErrors("organization", docs)).toThrow(/deactivateCompany/);
  });

  it("returns empty string when no errors", () => {
    const docs: ParsedCommandDoc[] = [
      { commandName: "noop", permissionScope: "misc", errors: [], externalDependencies: [] },
    ];

    const result = generateErrors("item-management", docs);

    expect(result).toBe("");
  });
});
