import { scrypt, randomBytes, randomUUID, timingSafeEqual } from "crypto";
import { promisify } from "util";
import { query } from "@/lib/db-postgres";

const scryptAsync = promisify(scrypt) as (
  password: string,
  salt: string,
  keylen: number,
) => Promise<Buffer>;

/**
 * Hash a password with scrypt (Node stdlib — no native deps, Alpine-safe).
 * Format: `scrypt$<saltHex>$<keyHex>`.
 */
export async function hashPassword(password: string): Promise<string> {
  const salt = randomBytes(16).toString("hex");
  const derived = await scryptAsync(password, salt, 64);
  return `scrypt$${salt}$${derived.toString("hex")}`;
}

export async function verifyPassword(
  password: string,
  stored: string,
): Promise<boolean> {
  const parts = stored.split("$");
  if (parts.length !== 3 || parts[0] !== "scrypt") return false;
  const [, salt, keyHex] = parts;
  const keyBuf = Buffer.from(keyHex, "hex");
  const derived = await scryptAsync(password, salt, 64);
  return keyBuf.length === derived.length && timingSafeEqual(keyBuf, derived);
}

// ── Session cookie ───────────────────────────────────────────────────────────
// Must match the cookie NextAuth issues for OAuth (see lib/auth/authOptions.ts)
// so getServerSession reads sessions created here exactly the same way.
const nextAuthUrl = (process.env.NEXTAUTH_URL ?? "").trim();
const isLocalNextAuth =
  nextAuthUrl.startsWith("http://localhost") ||
  nextAuthUrl.startsWith("http://127.0.0.1") ||
  (process.env.NODE_ENV === "development" && !nextAuthUrl);

export const SESSION_COOKIE_NAME = isLocalNextAuth
  ? "next-auth.session-token"
  : "__Secure-next-auth.session-token";

const SESSION_MAX_AGE_MS = 30 * 24 * 60 * 60 * 1000; // 30 days

export function sessionCookieOptions(expires: Date) {
  return {
    httpOnly: true,
    sameSite: "lax" as const,
    path: "/",
    secure: !isLocalNextAuth,
    expires,
    ...(isLocalNextAuth ? {} : { domain: ".vibnai.com" }),
  };
}

/**
 * Create a database-backed NextAuth session row for a user and return the token
 * to set as the session cookie. This is the same `sessions` table the Prisma
 * adapter uses for OAuth, so the resulting session works everywhere
 * (`authSession()`, `useSession()`, sign-out, etc.).
 */
export async function createDbSession(
  userId: string,
): Promise<{ token: string; expires: Date }> {
  const token = randomBytes(32).toString("hex");
  const expires = new Date(Date.now() + SESSION_MAX_AGE_MS);
  await query(
    `INSERT INTO sessions (id, session_token, user_id, expires)
     VALUES ($1, $2, $3, $4)`,
    [randomUUID(), token, userId, expires],
  );
  return { token, expires };
}
