const crypto = require("crypto");
const cors = require("cors");
const { sendError } = require("../utils/http");

const WRITE_KEY_REGEX = /^[A-Za-z0-9_-]{16,128}$/;
let warnedAboutOpenWriteAccess = false;

function parseAllowedOrigins(value) {
  const legacy = process.env.FRONTEND_ORIGIN || "";
  const source = value || legacy;

  if (!source) {
    return ["http://localhost:3000", "http://127.0.0.1:3000"];
  }

  return source
    .split(",")
    .map((item) => item.trim())
    .filter(Boolean);
}

function createCorsMiddleware() {
  const allowedOrigins = new Set(parseAllowedOrigins(process.env.CORS_ALLOWED_ORIGINS));

  return cors({
    origin(origin, callback) {
      // Allow same-origin/browser requests with no Origin header.
      if (!origin) {
        callback(null, true);
        return;
      }

      if (allowedOrigins.has(origin)) {
        callback(null, true);
        return;
      }

      callback(new Error("CORS origin blocked"));
    },
    credentials: false,
    methods: ["GET", "POST", "PUT", "DELETE", "OPTIONS"],
    allowedHeaders: ["Content-Type", "X-API-Key"],
    maxAge: 600,
  });
}

function securityHeaders(req, res, next) {
  const trustProxy = String(process.env.TRUST_PROXY || "false").toLowerCase() === "true";
  res.setHeader(
    "Content-Security-Policy",
    [
      "default-src 'self'",
      "script-src 'self'",
      "style-src 'self' 'unsafe-inline' https://fonts.googleapis.com",
      "img-src 'self' data: https://render.crafty.gg",
      "font-src 'self' https://fonts.gstatic.com",
      "connect-src 'self'",
      "object-src 'none'",
      "base-uri 'self'",
      "form-action 'self'",
      "frame-ancestors 'none'",
      "upgrade-insecure-requests",
    ].join("; ")
  );

  res.setHeader("X-Content-Type-Options", "nosniff");
  res.setHeader("X-Frame-Options", "DENY");
  res.setHeader("Referrer-Policy", "strict-origin-when-cross-origin");
  res.setHeader("Permissions-Policy", "camera=(), microphone=(), geolocation=()");
  res.setHeader("Cross-Origin-Resource-Policy", "same-origin");
  res.setHeader("Cross-Origin-Opener-Policy", "same-origin");

  if (req.secure || (trustProxy && String(req.get("x-forwarded-proto") || "").toLowerCase() === "https")) {
    res.setHeader("Strict-Transport-Security", "max-age=31536000; includeSubDomains");
  }

  next();
}

function enforceHttps(req, res, next) {
  const enforce = String(process.env.ENFORCE_HTTPS || "false").toLowerCase() === "true";
  const trustProxy = String(process.env.TRUST_PROXY || "false").toLowerCase() === "true";

  if (!enforce) {
    next();
    return;
  }

  const isSecure =
    req.secure || (trustProxy && String(req.get("x-forwarded-proto") || "").toLowerCase() === "https");
  if (isSecure) {
    next();
    return;
  }

  const host = req.get("host");
  if (!host) {
    return sendError(res, 400, "HTTPS_REQUIRED", "HTTPS is required.");
  }

  return res.redirect(301, `https://${host}${req.originalUrl}`);
}

function getWriteKeys() {
  const raw = process.env.API_WRITE_KEYS || process.env.API_WRITE_KEY || "";
  const keys = raw
    .split(",")
    .map((key) => key.trim())
    .filter(Boolean)
    .filter((key) => WRITE_KEY_REGEX.test(key));

  return keys;
}

function safeEqual(a, b) {
  const left = Buffer.from(a);
  const right = Buffer.from(b);

  if (left.length !== right.length) {
    return false;
  }

  return crypto.timingSafeEqual(left, right);
}

function requireWriteApiKey(req, res, next) {
  const writeKeys = getWriteKeys();

  if (writeKeys.length === 0) {
    if (!warnedAboutOpenWriteAccess) {
      warnedAboutOpenWriteAccess = true;
      console.warn("Write API key protection is disabled. Set API_WRITE_KEYS to enforce write authentication.");
    }
    next();
    return;
  }

  const apiKey = String(req.get("x-api-key") || "").trim();
  if (!WRITE_KEY_REGEX.test(apiKey)) {
    return sendError(res, 401, "AUTH_REQUIRED", "Missing or invalid API key.");
  }

  const matched = writeKeys.some((key) => safeEqual(key, apiKey));
  if (!matched) {
    return sendError(res, 401, "AUTH_REQUIRED", "Missing or invalid API key.");
  }

  next();
}

module.exports = {
  createCorsMiddleware,
  securityHeaders,
  enforceHttps,
  requireWriteApiKey,
};
