/**
 * `GET /api/v1/health`.
 *
 * The route the CI job asserts on, so it has one job: answer 200 on a box that
 * was handed nothing. It touches no upstream, reads no file and takes no lock —
 * a health check that can be made to fail by a third party's outage is a health
 * check that will page somebody at four in the morning about somebody else's
 * server.
 *
 * `degraded` is what makes it more than a liveness probe: every demotion the
 * config made is printed here, so "why is the weather always clear" has an
 * answer that does not require log access.
 *
 * `regions` joins it for the same reason. Weather and flights now refuse a place
 * this box does not serve, so a client that guesses `?city=` and a 400 it cannot
 * explain is the failure this field prevents: ask health once, learn what may be
 * asked for, and an operator diagnosing "why is there no SoCal weather" reads
 * the answer instead of the env file. Publishing the allowlist gives nothing
 * away — knowing what is served is not the same as widening it, and the ids are
 * the names of the cities the map already draws.
 */

import type { FastifyInstance } from "fastify";
import type { Region } from "../regions.ts";
import type { HealthBody } from "../../../src/server/wire.ts";
import type { Services } from "../services.ts";

/**
 * `HealthBody` plus the served regions.
 *
 * The field belongs in `src/server/wire.ts` beside the body it extends, and it
 * is stated here only because that file is the browser side of this change and
 * lands with it. Fold `regions: Region[]` into `HealthBody` and this alias goes
 * away; nothing else has to move, because the shape is already exactly what the
 * route serves.
 */
type HealthBodyWithRegions = HealthBody & { regions: Region[] };

export function registerHealth(app: FastifyInstance, services: Services): void {
  const { config, startedAt } = services;

  app.get("/api/v1/health", async () => {
    const body: HealthBodyWithRegions = {
      ok: true,
      service: "tera-api",
      version: config.version,
      uptimeSeconds: Math.round((Date.now() - startedAt) / 1000),
      sources: {
        weather: config.weather.source,
        flights: config.flights.source,
        satellites: config.satellites.source,
        markers: config.markers.source,
      },
      auth: {
        mode: config.auth.mode,
        entryUrl: config.auth.mode === "sso" && config.auth.entryUrl !== ""
          ? config.auth.entryUrl
          : null,
      },
      // In the config's order, so the first entry is the region a request with
      // no query gets. A client reading this can pick its default the same way
      // the server does.
      regions: config.regions,
      degraded: config.degraded,
    };
    return body;
  });
}
