import { describe, expect, it, vi } from "vitest";
import { StandardResourceCatalog } from "../src/v3/resource-catalog/standardResourceCatalog.js";

describe("StandardResourceCatalog — skills", () => {
  it("registers and lists a skill manifest", () => {
    const catalog = new StandardResourceCatalog();
    catalog.setCurrentFileContext("trigger/chat.ts", "chat");

    catalog.registerSkillMetadata({ id: "pdf-processing", sourcePath: "./skills/pdf-processing" });

    const manifests = catalog.listSkillManifests();
    expect(manifests).toHaveLength(1);
    expect(manifests[0]).toMatchObject({
      id: "pdf-processing",
      sourcePath: "./skills/pdf-processing",
      filePath: "trigger/chat.ts",
      entryPoint: "chat",
    });
  });

  it("getSkillManifest returns the registered skill", () => {
    const catalog = new StandardResourceCatalog();
    catalog.setCurrentFileContext("trigger/chat.ts", "chat");
    catalog.registerSkillMetadata({ id: "a", sourcePath: "./skills/a" });

    expect(catalog.getSkillManifest("a")?.sourcePath).toBe("./skills/a");
    expect(catalog.getSkillManifest("missing")).toBeUndefined();
  });

  it("skips registration without a file context", () => {
    const catalog = new StandardResourceCatalog();

    catalog.registerSkillMetadata({ id: "pdf", sourcePath: "./skills/pdf" });

    expect(catalog.listSkillManifests()).toHaveLength(0);
  });

  it("warns and ignores when the same id is registered with a different path", () => {
    const catalog = new StandardResourceCatalog();
    catalog.setCurrentFileContext("trigger/chat.ts", "chat");

    const warn = vi.spyOn(console, "warn").mockImplementation(() => {});

    catalog.registerSkillMetadata({ id: "pdf", sourcePath: "./skills/pdf" });
    catalog.registerSkillMetadata({ id: "pdf", sourcePath: "./skills/other-pdf" });

    const manifests = catalog.listSkillManifests();
    expect(manifests).toHaveLength(1);
    expect(manifests[0]?.sourcePath).toBe("./skills/pdf");
    expect(warn).toHaveBeenCalledWith(expect.stringContaining("defined twice"));

    warn.mockRestore();
  });

  it("re-registering the same id + path is idempotent", () => {
    const catalog = new StandardResourceCatalog();
    catalog.setCurrentFileContext("trigger/chat.ts", "chat");

    catalog.registerSkillMetadata({ id: "pdf", sourcePath: "./skills/pdf" });
    catalog.registerSkillMetadata({ id: "pdf", sourcePath: "./skills/pdf" });

    expect(catalog.listSkillManifests()).toHaveLength(1);
  });

  it("registers multiple distinct skills", () => {
    const catalog = new StandardResourceCatalog();
    catalog.setCurrentFileContext("trigger/chat.ts", "chat");

    catalog.registerSkillMetadata({ id: "pdf", sourcePath: "./skills/pdf" });
    catalog.registerSkillMetadata({ id: "researcher", sourcePath: "./skills/researcher" });

    expect(
      catalog
        .listSkillManifests()
        .map((s) => s.id)
        .sort()
    ).toEqual(["pdf", "researcher"]);
  });
});
