import crypto from "node:crypto";
import { cookies } from "next/headers";
import { redirect } from "next/navigation";

const COOKIE_NAME = "pyramidcom_admin";
const SESSION_DURATION_SECONDS = 12 * 60 * 60;

export type AdminSession = {
  email: string;
  displayName: string;
  expiresAt: number;
};

export async function isAdminRequest() {
  return Boolean(await getAdminSession());
}

export async function getAdminSession(): Promise<AdminSession | null> {
  if (process.env.NODE_ENV === "development" && process.env.ALLOW_DEV_ADMIN !== "false") {
    return { email: "jh@pyramidcom.fr", displayName: "Administrateur", expiresAt: Date.now() + SESSION_DURATION_SECONDS * 1000 };
  }
  const token = (await cookies()).get(COOKIE_NAME)?.value;
  return token ? verifySessionToken(token) : null;
}

export async function requireAdminSession() {
  const session = await getAdminSession();
  if (!session) redirect("/connexion");
  return session;
}

export async function createAdminSession(email: string, displayName: string) {
  const expiresAt = Date.now() + SESSION_DURATION_SECONDS * 1000;
  const payload = encode(JSON.stringify({ email, displayName, expiresAt }));
  (await cookies()).set(COOKIE_NAME, `${payload}.${sign(payload)}`, {
    httpOnly: true,
    secure: process.env.NODE_ENV === "production",
    sameSite: "lax",
    path: "/",
    maxAge: SESSION_DURATION_SECONDS,
  });
}

export async function clearAdminSession() {
  (await cookies()).set(COOKIE_NAME, "", {
    httpOnly: true,
    secure: process.env.NODE_ENV === "production",
    sameSite: "lax",
    path: "/",
    maxAge: 0,
  });
}

function verifySessionToken(token: string): AdminSession | null {
  const separator = token.lastIndexOf(".");
  if (separator < 1) return null;
  const payload = token.slice(0, separator);
  if (!safeEqual(token.slice(separator + 1), sign(payload))) return null;
  try {
    const value = JSON.parse(decode(payload)) as Partial<AdminSession>;
    if (typeof value.email !== "string" || typeof value.displayName !== "string" ||
        typeof value.expiresAt !== "number" || value.expiresAt <= Date.now()) return null;
    return value as AdminSession;
  } catch {
    return null;
  }
}

function sign(value: string) {
  const secret = process.env.SESSION_SECRET;
  if (!secret || secret.length < 32) {
    if (process.env.NODE_ENV === "production") throw new Error("SESSION_SECRET must contain at least 32 characters.");
    return crypto.createHmac("sha256", "pyramidcom-local-development-only").update(value).digest("base64url");
  }
  return crypto.createHmac("sha256", secret).update(value).digest("base64url");
}

function safeEqual(left: string, right: string) {
  const a = Buffer.from(left);
  const b = Buffer.from(right);
  return a.length === b.length && crypto.timingSafeEqual(a, b);
}

function encode(value: string) {
  return Buffer.from(value, "utf8").toString("base64url");
}

function decode(value: string) {
  return Buffer.from(value, "base64url").toString("utf8");
}
