/**
 * `Cache-Control`, fail-closed.
 *
 * A global `onRequest` hook stamps `private, no-store` on every reply before any
 * route runs, and a route that wants a CDN or a browser to keep a copy has to
 * say so out loud with `publicCache()`. The order matters: doing this in
 * `onSend` "only if the header is missing" would leave error paths, 404s and
 * anything thrown before the handler with no policy at all, and the one body
 * that must never be cached is the one that came out of a mistake.
 *
 * CONTRACT.md §5.
 */

import type { FastifyInstance, FastifyReply, FastifyRequest } from "fastify";

export function registerCachePolicy(app: FastifyInstance): void {
  app.addHook("onRequest", async (_req, reply) => {
    reply.header("cache-control", "private, no-store");
  });
}

/**
 * Opt this reply in to shared caching.
 *
 * The credential check is not paranoia for its own sake. A route can be
 * *usually* public and still be reached with a session attached, and a shared
 * cache that stored that response would serve one viewer's body to the next. If
 * the request carried anything that could personalise the answer, the fail-closed
 * default stands.
 */
export function publicCache(req: FastifyRequest, reply: FastifyReply, seconds: number): void {
  if (req.headers.authorization !== undefined || req.headers.cookie !== undefined) return;
  const maxAge = Math.max(0, Math.floor(seconds));
  reply.header("cache-control", `public, max-age=${maxAge}`);
  reply.header("vary", "Origin");
}
