import {
  createHash,
  randomBytes,
  scryptSync,
  timingSafeEqual,
} from "node:crypto";
import { prisma } from "./prisma";

const SESSION_COOKIE = "cdrdpyj_admin";
const SESSION_TTL_MS = 8 * 60 * 60 * 1000;

export interface AuthSession {
  adminId: string;
  email: string;
  nombre: string;
  rol: string;
}

export function sessionCookieName(): string {
  return SESSION_COOKIE;
}

export function hashPassword(password: string): string {
  const salt = randomBytes(16).toString("hex");
  const hash = scryptSync(password, salt, 64).toString("hex");
  return `${salt}:${hash}`;
}

export function verifyPassword(password: string, stored: string): boolean {
  const [salt, hash] = stored.split(":");
  if (!salt || !hash) return false;
  const test = scryptSync(password, salt, 64);
  const ref = Buffer.from(hash, "hex");
  return test.length === ref.length && timingSafeEqual(test, ref);
}

function sha256(value: string): string {
  return createHash("sha256").update(value).digest("hex");
}

function timingSafeEqualStr(a: string, b: string): boolean {
  const ab = Buffer.from(a);
  const bb = Buffer.from(b);
  return ab.length === bb.length && timingSafeEqual(ab, bb);
}

export function sessionCookieFor(token: string): string {
  const secure = process.env.NODE_ENV === "production" ? "; Secure" : "";
  return `${SESSION_COOKIE}=${token}; HttpOnly; Path=/; SameSite=Lax; Max-Age=${Math.floor(
    SESSION_TTL_MS / 1000
  )}${secure}`;
}

export function clearSessionCookie(): string {
  const secure = process.env.NODE_ENV === "production" ? "; Secure" : "";
  return `${SESSION_COOKIE}=; HttpOnly; Path=/; SameSite=Lax; Max-Age=0${secure}`;
}

function readSessionToken(request: Request): string | null {
  const cookie = request.headers.get("cookie");
  if (!cookie) return null;
  const entry = cookie
    .split(";")
    .map((c) => c.trim())
    .find((c) => c.startsWith(`${SESSION_COOKIE}=`));
  if (!entry) return null;
  return entry.slice(SESSION_COOKIE.length + 1) || null;
}

export async function createSession(adminId: string): Promise<string> {
  const token = randomBytes(32).toString("base64url");
  await prisma.session.create({
    data: {
      token_hash: sha256(token),
      admin_id: adminId,
      expires_at: new Date(Date.now() + SESSION_TTL_MS),
    },
  });
  return token;
}

export async function getSession(request: Request): Promise<AuthSession | null> {
  const token = readSessionToken(request);
  if (!token) return null;

  const session = await prisma.session.findUnique({
    where: { token_hash: sha256(token) },
    include: { admin: true },
  });

  if (
    !session ||
    session.expires_at.getTime() <= Date.now() ||
    !session.admin.activo
  ) {
    return null;
  }

  return {
    adminId: session.admin.id,
    email: session.admin.email,
    nombre: session.admin.nombre,
    rol: session.admin.rol,
  };
}

export async function revokeSession(request: Request): Promise<void> {
  const token = readSessionToken(request);
  if (!token) return;
  try {
    await prisma.session.delete({ where: { token_hash: sha256(token) } });
  } catch {
    // sesión inexistente, no hacer nada
  }
}

export async function isApiAuthorized(request: Request): Promise<boolean> {
  if (await getSession(request)) return true;

  const apiKey = process.env.ADMIN_API_KEY;
  if (!apiKey) return false;

  const key =
    request.headers.get("x-api-key") ??
    request.headers.get("authorization")?.replace(/^Bearer\s+/i, "");
  if (!key) return false;

  return timingSafeEqualStr(key, apiKey);
}
