import { timingSafeEqual } from "node:crypto";
import type { FastifyInstance, FastifyReply, FastifyRequest } from "fastify";
import BRAND from "../../../../brand.config.json" with { type: "json" };
import { errors } from "../lib/errors.js";

const CACHE_KEY = "ops:summary:cache";
const CACHE_TS_KEY = "ops:summary:computed_at";

function requireOpsToken(app: FastifyInstance) {
  return async (req: FastifyRequest, reply: FastifyReply): Promise<void> => {
    if (app.config.NODE_ENV === "production" && req.protocol !== "https") {
      return reply
        .status(403)
        .send({ error: { code: "HTTPS_REQUIRED", message: "Ops-endpointen kräver HTTPS." } });
    }

    const header = req.headers.authorization ?? "";
    const match = /^Bearer\s+(.+)$/.exec(header);
    const provided = match?.[1] ?? "";
    const expected = app.config.OPS_TOKEN ?? "";

    if (!expected || expected.length < 20 || provided.length !== expected.length) {
      throw errors.unauthorized();
    }

    const ok = timingSafeEqual(Buffer.from(provided), Buffer.from(expected));
    if (!ok) throw errors.unauthorized();
  };
}

/**
 * Operations summary endpoint: read-only, token-protected, served from cache.
 * Heavy computation is done by the REFRESH_OPS_SUMMARY_CACHE worker job.
 */
export async function opsRoutes(app: FastifyInstance) {
  const preHandler = [requireOpsToken(app)];

  app.get("/ops/v1/health", { preHandler }, async () => ({
    ok: true,
    app: "cibello",
  }));

  app.get("/ops/v1/summary", { preHandler }, async (_req, reply) => {
    const [json, ts] = await app.redis.mget(CACHE_KEY, CACHE_TS_KEY);
    if (!json) {
      return reply.status(503).send({
        error: {
          code: "CACHE_MISS",
          message: "Sammanfattningen är inte färdigberäknad än. Vänta på nästa canary-/cache-jobb.",
        },
      });
    }

    let summary: Record<string, unknown>;
    try {
      summary = JSON.parse(json) as Record<string, unknown>;
    } catch {
      return reply
        .status(500)
        .send({ error: { code: "CACHE_INVALID", message: "Cachen innehåller ogiltig JSON." } });
    }

    const enriched = structuredClone(summary);

    if (
      enriched.wall &&
      typeof enriched.wall === "object" &&
      Array.isArray((enriched.wall as Record<string, unknown>).boards)
    ) {
      for (const board of (enriched.wall as { boards: Array<{ title?: string }> }).boards) {
        if (board.title === "{brand}") board.title = BRAND.name;
      }
    }

    return reply.send({
      ...enriched,
      cached_at: ts ?? summary.as_of,
    });
  });
}
