import crypto from "node:crypto";

export type SessionData = {
  user?: {
    id: number;
    login: string;
    name?: string;
    email?: string;
  };
  csrf?: string;
};

const COOKIE_NAME = "gp_session";

function b64url(input: Buffer | string) {
  return Buffer.from(input)
    .toString("base64")
    .replace(/=/g, "")
    .replace(/\+/g, "-")
    .replace(/\//g, "_");
}

function sign(payload: string, secret: string) {
  return crypto.createHmac("sha256", secret).update(payload).digest("base64url");
}

export function createSessionCookie(data: SessionData, secret = process.env.SESSION_SECRET || "") {
  const payload = b64url(JSON.stringify(data));
  const sig = sign(payload, secret);
  return `${payload}.${sig}`;
}

export function parseSessionCookie(cookieValue: string | undefined, secret = process.env.SESSION_SECRET || ""): SessionData | undefined {
  if (!cookieValue) return undefined;
  const [payload, sig] = cookieValue.split(".");
  if (!payload || !sig) return undefined;
  const expected = sign(payload, secret);
  if (!crypto.timingSafeEqual(Buffer.from(sig), Buffer.from(expected))) return undefined;
  try {
    const json = Buffer.from(payload.replace(/-/g, "+").replace(/_/g, "/"), "base64").toString("utf-8");
    return JSON.parse(json);
  } catch {
    return undefined;
  }
}

export function clearCookieHeader(name = COOKIE_NAME) {
  return `${name}=; Path=/; HttpOnly; Secure; SameSite=Lax; Max-Age=0`;
}

export function sessionCookieHeader(value: string, name = COOKIE_NAME) {
  // 7 days
  const maxAge = 60 * 60 * 24 * 7;
  return `${name}=${value}; Path=/; HttpOnly; Secure; SameSite=Lax; Max-Age=${maxAge}`;
}

export function getSessionFromRequest(req: Request, secret = process.env.SESSION_SECRET || ""): SessionData | undefined {
  const cookie = req.headers.get("cookie") || "";
  const match = cookie.match(/(?:^|; )gp_session=([^;]+)/);
  if (!match) return undefined;
  return parseSessionCookie(match[1], secret);
}

export function randomToken(bytes = 32) {
  return crypto.randomBytes(bytes).toString("hex");
}

export const COOKIE_NAME_STATE = "oauth_state";

export function setTempCookie(name: string, value: string) {
  // short lived: 10 minutes
  const maxAge = 60 * 10;
  return `${name}=${value}; Path=/; HttpOnly; Secure; SameSite=Lax; Max-Age=${maxAge}`;
}
