import { expectDiagnostics } from "@typespec/compiler/testing";
import { deepStrictEqual } from "assert";
import { it } from "vitest";
import { supportedVersions, worksFor } from "./works-for.js";

worksFor(supportedVersions, ({ diagnoseOpenApiFor, openApiFor }) => {
  async function expectStatusCodes(code: string, statusCodes: string[]) {
    const res = await openApiFor(code);
    deepStrictEqual(Object.keys(res.paths["/"].get.responses), statusCodes);
  }
  it("map single status code", async () => {
    await expectStatusCodes(
      `
      op read(): {@statusCode _: 200, content: string};
      `,
      ["200"],
    );
  });

  it("map multiple status code", async () => {
    await expectStatusCodes(
      `
      op read(): {@statusCode _: 200 | 201 | 204, content: string};
      `,
      ["200", "201", "204"],
    );
  });

  it("map simple status code range", async () => {
    await expectStatusCodes(
      `
      op read(): {@minValue(400) @maxValue(499) @statusCode _: int32, content: string};
      `,
      ["4XX"],
    );
  });

  it("map status code range going over multiple hundreds", async () => {
    await expectStatusCodes(
      `
      op read(): {@minValue(400) @maxValue(599) @statusCode _: int32, content: string};
      `,
      ["4XX", "5XX"],
    );
  });

  it("emit diagnostic if status code range is not supported", async () => {
    const diagnostics = await diagnoseOpenApiFor(
      `
      op read(): {@minValue(455) @maxValue(495) @statusCode _: int32, content: string};
      `,
    );
    expectDiagnostics(diagnostics, [
      {
        code: "@typespec/openapi3/unsupported-status-code-range",
        message:
          "Status code range '455 to '495' is not supported. OpenAPI 3.0 can only represent range 1XX, 2XX, 3XX, 4XX and 5XX. Example: `@minValue(400) @maxValue(499)` for 4XX.",
      },
    ]);
  });

  it("extracts status codes from models in a named union", async () => {
    await expectStatusCodes(
      `
      model A {
        @statusCode _: 418;
      }

      model B {
        @statusCode _: 200;
      }

      union R {
        A: A;
        B: B;
      };

      op read(): R;
      `,
      ["200", "418"],
    );
  });

  it("deduplicates status codes when multiple models in union have same code", async () => {
    await expectStatusCodes(
      `
      model A {
        @statusCode _: 418;
      }

      model B {
        @statusCode _: 418;
      }

      model C {
        @statusCode _: 200;
      }

      union R {
        A: A;
        B: B;
        C: C;
      };

      op read(): R;
      `,
      ["200", "418"],
    );
  });
});
