import express, { type Express } from "express";
import cors from "cors";
import cookieParser from "cookie-parser";
import pinoHttp from "pino-http";
import router from "./routes";
import { logger } from "./lib/logger";

const app: Express = express();
const requestWindows = new Map<string, { count: number; resetAt: number }>();

app.use(
  pinoHttp({
    logger,
    serializers: {
      req(req) {
        return {
          id: req.id,
          method: req.method,
          url: req.url?.split("?")[0],
        };
      },
      res(res) {
        return {
          statusCode: res.statusCode,
        };
      },
    },
  }),
);
app.disable("x-powered-by");
app.use((_req, res, next) => {
  res.setHeader("X-Content-Type-Options", "nosniff");
  res.setHeader("X-Frame-Options", "DENY");
  res.setHeader("Referrer-Policy", "no-referrer");
  res.setHeader("Permissions-Policy", "camera=(), microphone=(), geolocation=()");
  res.setHeader("Content-Security-Policy", "default-src 'none'; frame-ancestors 'none'");
  next();
});
const allowedOrigins = new Set(
  (process.env.ALLOWED_ORIGINS ?? "").split(",").map(value => value.trim()).filter(Boolean),
);
app.use((req, res, next) => {
  const origin = req.get("origin");
  const sameOrigin = origin === `${req.protocol}://${req.get("host")}`;
  if (origin && !sameOrigin && !allowedOrigins.has(origin)) {
    res.status(403).json({ error: "Origin no permitido" });
    return;
  }
  next();
});
app.use(cors({
  credentials: true,
  origin: true,
}));
app.use(cookieParser());
app.use(express.json({ limit: "256kb" }));
app.use(express.urlencoded({ extended: true, limit: "64kb" }));
app.use((req, res, next) => {
  if (req.path === "/healthz") { next(); return; }
  const now = Date.now();
  const key = req.ip ?? "unknown";
  const current = requestWindows.get(key);
  if (!current || current.resetAt <= now) {
    requestWindows.set(key, { count: 1, resetAt: now + 60_000 });
    next();
    return;
  }
  if (current.count >= 120) {
    res.setHeader("Retry-After", "60");
    res.status(429).json({ error: "Límite de solicitudes excedido" });
    return;
  }
  current.count += 1;
  next();
});

app.use("/api", router);

export default app;
