// ─────────────────────────────────────────────────────────────────────────────
// JWT signing & verification (jose library)
//
// Stateless session tokens signed with HS256. The secret is read once from the
// environment and cached for the lifetime of the process.
// ─────────────────────────────────────────────────────────────────────────────

import { jwtVerify, SignJWT } from "jose"

let encoded: Uint8Array

// ── Secret management ────────────────────────────────────────────────────────

/**
 * Return the JWT signing key as a `Uint8Array`.
 *
 * Reads `JWT_SECRET` from the environment on first call and caches the encoded
 * result so subsequent calls are effectively free.
 */
export function getJWTSecret(): Uint8Array {
  if (!encoded) {
    const raw = process.env.JWT_SECRET
    if (!raw) {
      throw new Error(
        "JWT_SECRET environment variable is required. " +
          "Generate one: openssl rand -hex 32",
      )
    }
    encoded = new TextEncoder().encode(raw)
  }
  return encoded
}

// ── Verification ─────────────────────────────────────────────────────────────

/**
 * Verify a JWT and extract its payload.
 *
 * Returns `null` instead of throwing when the token is expired, malformed, or
 * signed with a different key.
 *
 * @param token - Raw JWT string (from cookie / header).
 * @returns     Decoded `{ userId, role }` or `null`.
 */
export async function verifyToken(token: string) {
  try {
    const { payload } = await jwtVerify(token, getJWTSecret())
    return payload as { userId: string; role: string }
  } catch {
    return null
  }
}

// ── Signing ──────────────────────────────────────────────────────────────────

/**
 * Create a signed JWT for the given user.
 *
 * Token includes:
 *   • `userId` and `role` as custom claims
 *   • `iat` (issued-at) timestamp
 *   • `exp` set to 24 hours from now
 *
 * @param payload - Object containing `userId` and `role`.
 * @returns       The signed JWT string.
 */
export async function signToken(payload: { userId: string; role: string }) {
  return new SignJWT(payload)
    .setProtectedHeader({ alg: "HS256" })
    .setExpirationTime("24h")
    .setIssuedAt()
    .sign(getJWTSecret())
}
