const SESSION_COOKIE = "coaching_session";

function parseCookieHeader(header) {
  const cookies = {};

  for (const part of String(header || "").split(";")) {
    const separator = part.indexOf("=");
    if (separator === -1) continue;
    const name = part.slice(0, separator).trim();
    const value = part.slice(separator + 1).trim();
    if (name) cookies[name] = decodeURIComponent(value);
  }

  return cookies;
}

function sessionTokenFromRequest(req) {
  return parseCookieHeader(req.headers?.cookie)[SESSION_COOKIE] || null;
}

function cookieOptions() {
  return {
    httpOnly: true,
    secure: process.env.NODE_ENV === "production" || process.env.NODE_ENV === "dev_stage",
    sameSite: "lax",
    path: "/",
  };
}

function setSessionCookie(req, res, token) {
  res.cookie(SESSION_COOKIE, token, { ...cookieOptions(), maxAge: 30 * 60 * 1000 });
}

function clearSessionCookie(req, res) {
  res.clearCookie(SESSION_COOKIE, cookieOptions());
}

function requestOrigin(req) {
  const origin = req.get("origin");
  if (origin) return origin;
  const referer = req.get("referer");
  return referer ? new URL(referer).origin : null;
}

function expectedOrigin(req) {
  const protocol = req.get("x-forwarded-proto") || req.protocol;
  const host = req.get("x-forwarded-host") || req.get("host");
  return `${protocol}://${host}`;
}

function protectCookieMutations(req, res, next) {
  if (["GET", "HEAD", "OPTIONS"].includes(req.method)) {
    next();
    return;
  }

  if (req.get("authorization") || !sessionTokenFromRequest(req)) {
    next();
    return;
  }

  let origin;
  try {
    origin = requestOrigin(req);
  } catch {
    res.status(403).send({ error: "csrf_origin_invalid" });
    return;
  }

  if (!origin || origin !== expectedOrigin(req)) {
    res.status(403).send({ error: "csrf_origin_invalid" });
    return;
  }

  next();
}

module.exports = { SESSION_COOKIE, parseCookieHeader, sessionTokenFromRequest, setSessionCookie, clearSessionCookie, protectCookieMutations };
