/**
 * `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` is a field of `HealthBody` for the same reason, and it is a field
 * of `HealthBody` rather than of a local alias widening it next to this route:
 * a body's shape stated anywhere but the wire contract is a shape the browser
 * cannot read. Weather and flights now refuse a place this box does not serve,
 * so a client that guesses `?city=` and earns 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 { HealthBody } from "../../../src/server/wire.ts";
import type { Services } from "../services.ts";

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

  app.get("/api/v1/health", async () => {
    const body: HealthBody = {
      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,
        devices: config.devices.source,
        fires: config.fires.source,
        // The two sky feeds. Optional on `HealthBody`, so a client reading an
        // older box's answer sees `undefined` and correctly concludes it serves
        // neither; published here so "why is there no rain on this board" is
        // answered by the box rather than by its env file. Read straight off the
        // config for the same reason every line above it is: this route touches
        // no service and cannot be made to fail by somebody else's outage.
        radar: config.radar.source,
        birds: config.birds.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;
  });
}
