import Fastify from "fastify";
import cors from "@fastify/cors";
import swagger from "@fastify/swagger";
import swaggerUI from "@fastify/swagger-ui";
import sensible from "@fastify/sensible";
import { env } from "./env.js";
import { ensureDatabaseReady } from "./db-init.js";
import { startModelCatalogRefreshLoop, warmModelCatalog } from "./llm/model-catalog.js";
import { registerRoutes } from "./routes.js";

const app = Fastify({
  bodyLimit: 32 * 1024 * 1024,
  disableRequestLogging: true,
  logger: {
    transport: {
      target: "pino-pretty",
      options: { colorize: true, translateTime: "SYS:standard" },
    },
  },
});

await ensureDatabaseReady(app.log);
await warmModelCatalog(app.log);
const stopModelCatalogRefreshLoop = startModelCatalogRefreshLoop(app.log);

await app.register(cors, {
  origin: true,
  credentials: true,
  methods: ["GET", "HEAD", "POST", "DELETE", "OPTIONS"],
});

await app.register(swagger, {
  openapi: {
    info: {
      title: "LLM Multiplexer Backend",
      version: "0.1.0",
    },
  },
});

await app.register(swaggerUI, { routePrefix: "/docs" });
await app.register(sensible);

app.addHook("onRequest", async (req) => {
  if (req.url.startsWith("/health")) return;
  req.log.info({ method: req.method, url: req.url }, "request received");
});

app.addHook("onResponse", async (req, reply) => {
  if (req.url.startsWith("/health")) return;
  const responseTimeMs = typeof reply.elapsedTime === "number" ? Number(reply.elapsedTime.toFixed(1)) : undefined;
  req.log.info(
    {
      method: req.method,
      url: req.url,
      statusCode: reply.statusCode,
      responseTimeMs,
    },
    "request completed"
  );
});

app.setErrorHandler((err, req, reply) => {
  const e = err as any;
  const statusCode = e.statusCode ?? 500;
  if (!req.url.startsWith("/health")) {
    req.log.error(
      {
        method: req.method,
        url: req.url,
        statusCode,
        err: e,
      },
      "request failed"
    );
  }
  reply.status(statusCode).send({
    error: true,
    message: e.message ?? String(e),
    statusCode,
  });
});

app.addHook("onClose", async () => {
  stopModelCatalogRefreshLoop();
});

await registerRoutes(app);

await app.listen({ port: env.PORT, host: env.HOST });
app.log.info(`listening on http://${env.HOST}:${env.PORT}`);
