import assert from "node:assert/strict";
import { describe, it } from "node:test";

import {
  findMissingOperations,
  normalizePath,
} from "../openapi-contract.mjs";

describe("OpenAPI contract comparison", () => {
  it("accepts matching paths and methods", () => {
    const missing = findMissingOperations(
      {
        chatHistory: { method: "get", path: "/api/chat/history" },
        unlockAlbum: {
          method: "post",
          path: "/api/private-zone/albums/{albumId}/unlock",
        },
      },
      {
        paths: {
          "/api/chat/history": { get: {} },
          "/api/private-zone/albums/{album_id}/unlock/": { post: {} },
        },
      },
    );

    assert.deepEqual(missing, []);
  });

  it("reports missing paths and methods with operation ids", () => {
    const missing = findMissingOperations(
      {
        chatHistory: { method: "get", path: "/api/chat/history" },
        chatSend: { method: "post", path: "/api/chat/send" },
      },
      { paths: { "/api/chat/history": { post: {} } } },
    );

    assert.deepEqual(missing, [
      {
        operationId: "chatHistory",
        method: "get",
        path: "/api/chat/history",
        reason: "method is missing",
      },
      {
        operationId: "chatSend",
        method: "post",
        path: "/api/chat/send",
        reason: "path is missing",
      },
    ]);
  });

  it("normalizes trailing slashes and path parameter names", () => {
    assert.equal(
      normalizePath("/api/albums/{album_id}/unlock/"),
      "/api/albums/{}/unlock",
    );
  });

  it("rejects documents without OpenAPI paths", () => {
    assert.throws(
      () => findMissingOperations({}, {}),
      /does not contain a paths object/u,
    );
  });
});
