import { cookies } from "next/headers";

const COOKIE_NAME = "admin_session";
const SEP = ".";

function getSecret(): string {
  const secret = process.env.ADMIN_SESSION_SECRET;
  if (!secret) throw new Error("ADMIN_SESSION_SECRET env var is not set");
  return secret;
}

async function sign(payload: string): Promise<string> {
  const encoder = new TextEncoder();
  const key = await crypto.subtle.importKey(
    "raw",
    encoder.encode(getSecret()),
    { name: "HMAC", hash: "SHA-256" },
    false,
    ["sign"],
  );
  const sig = await crypto.subtle.sign("HMAC", key, encoder.encode(payload));
  return btoa(String.fromCharCode(...new Uint8Array(sig)));
}

export interface AdminSession {
  username: string;
  role: "SUPER_ADMIN" | "ADMIN";
}

export async function createAdminSession(data: AdminSession): Promise<string> {
  const payload = btoa(JSON.stringify(data));
  return payload + SEP + (await sign(payload));
}

export async function verifyAdminSession(token: string): Promise<AdminSession | null> {
  const sepIdx = token.lastIndexOf(SEP);
  if (sepIdx === -1) return null;
  const payload = token.slice(0, sepIdx);
  const sig = token.slice(sepIdx + 1);
  const expectedSig = await sign(payload);
  if (sig.length !== expectedSig.length) return null;
  try {
    if (!constantTimeEqual(sig, expectedSig)) return null;
  } catch {
    return null;
  }
  try {
    return JSON.parse(atob(payload));
  } catch {
    return null;
  }
}

function constantTimeEqual(a: string, b: string): boolean {
  if (a.length !== b.length) return false;
  let result = 0;
  for (let i = 0; i < a.length; i++) {
    result |= a.charCodeAt(i) ^ b.charCodeAt(i);
  }
  return result === 0;
}

export const COOKIE_NAME_ADMIN = COOKIE_NAME;

export function cookieOptions(value: string) {
  return {
    name: COOKIE_NAME,
    value,
    httpOnly: true,
    secure: process.env.NODE_ENV === "production",
    sameSite: "lax" as const,
    path: "/",
  };
}

export async function getAdminSession(): Promise<AdminSession | null> {
  const store = await cookies();
  const token = store.get(COOKIE_NAME)?.value;
  if (!token) return null;
  return verifyAdminSession(token);
}
