defmodule MicrowavepropWeb.ApiCatalogController do
  @moduledoc """
  RFC 9727 API catalog + companion OpenAPI spec for automated API discovery.

  `/api/contacts/map` is currently the only public JSON endpoint. The
  catalog lists it with link relations for `service-desc` (OpenAPI) and
  `status` (health check). If more endpoints are added, extend
  `linkset_entries/1` and the OpenAPI `paths` map.
  """
  use MicrowavepropWeb, :controller

  @openapi_type "application/vnd.oai.openapi+json;version=3.0"

  @spec catalog(Plug.Conn.t(), map()) :: Plug.Conn.t()
  def catalog(conn, _params) do
    body = Jason.encode!(%{linkset: linkset_entries(conn)})

    conn
    |> put_resp_content_type("application/linkset+json")
    |> put_resp_header("cache-control", "public, max-age=3600")
    |> send_resp(200, body)
  end

  @spec openapi(Plug.Conn.t(), map()) :: Plug.Conn.t()
  def openapi(conn, _params) do
    body = Jason.encode!(openapi_spec(conn))

    conn
    |> put_resp_content_type("application/json")
    |> put_resp_header("cache-control", "public, max-age=3600")
    |> send_resp(200, body)
  end

  defp linkset_entries(conn) do
    [
      %{
        anchor: url(conn, ~p"/api/contacts/map"),
        "service-desc": [%{href: url(conn, ~p"/openapi.json"), type: @openapi_type}],
        status: [%{href: url(conn, ~p"/health")}]
      }
    ]
  end

  defp openapi_spec(conn) do
    %{
      openapi: "3.0.3",
      info: %{
        title: "Microwaveprop Public API",
        description: "Public JSON endpoints for the NTMS microwave propagation prediction service.",
        version: "1.0.0"
      },
      servers: [%{url: url(conn, ~p"/")}],
      paths: %{
        "/api/contacts/map" => %{
          get: %{
            summary: "All recorded amateur-radio contacts as compact tuples",
            description:
              "Returns every contact in the calibration dataset as an array of fixed-shape tuples. " <>
                "Response is pre-gzipped when the client sends Accept-Encoding: gzip. " <>
                "Tuple shape: [lat1, lon1, lat2, lon2, band_mhz, callsign1, callsign2, mode, distance_km, qso_timestamp, id].",
            responses: %{
              "200" => %{
                description: "Array of contact tuples",
                content: %{
                  "application/json" => %{
                    schema: %{
                      type: "array",
                      items: %{
                        type: "array",
                        minItems: 11,
                        maxItems: 11
                      }
                    }
                  }
                }
              }
            }
          }
        }
      }
    }
  end
end
