// server/utils/jwt.ts

/**
 * JWT Token Validation using jose library
 *
 * Validates Cidaas ID tokens (OIDC JWT) to ensure:
 * - Signature is valid (using Cidaas public keys from JWKS)
 * - Token has not expired
 * - Issuer matches expected Cidaas instance
 * - Audience matches our client ID
 */

import { jwtVerify, createRemoteJWKSet, type JWTPayload } from 'jose'

// Cache JWKS (Cidaas public keys) to avoid fetching on every request
let jwksCache: ReturnType<typeof createRemoteJWKSet> | null = null

/**
 * Get or create JWKS cache
 *
 * JWKS (JSON Web Key Set) contains public keys used to verify JWT signatures.
 * We cache this to improve performance.
 */
function getJWKS() {
  if (!jwksCache) {
    const config = useRuntimeConfig()
    jwksCache = createRemoteJWKSet(new URL(config.cidaas.jwksUrl))
  }
  return jwksCache
}

/**
 * Extended JWT payload with OIDC claims
 */
export interface CidaasJWTPayload extends JWTPayload {
  sub: string // User ID (experimenta_id)
  email?: string
  email_verified?: boolean
  given_name?: string
  family_name?: string
  name?: string
}

/**
 * Verify Cidaas ID token
 *
 * @param idToken - JWT ID token from Cidaas
 * @returns Decoded and verified JWT payload
 * @throws Error if verification fails
 */
export async function verifyIdToken(idToken: string): Promise<CidaasJWTPayload> {
  const config = useRuntimeConfig()
  const JWKS = getJWKS()

  try {
    const { payload } = await jwtVerify(idToken, JWKS, {
      issuer: config.cidaas.issuer, // Must match Cidaas issuer
      audience: config.cidaas.clientId, // Must match our client ID
    })

    return payload as CidaasJWTPayload
  } catch (error) {
    console.error('JWT verification failed:', error)

    // Provide specific error messages
    if (error instanceof Error) {
      if (error.message.includes('expired')) {
        throw createError({
          statusCode: 401,
          statusMessage: 'Token has expired',
        })
      }

      if (error.message.includes('signature')) {
        throw createError({
          statusCode: 401,
          statusMessage: 'Invalid token signature',
        })
      }
    }

    throw createError({
      statusCode: 401,
      statusMessage: 'Invalid ID token',
    })
  }
}

/**
 * Decode JWT without verification (for debugging only!)
 *
 * ⚠️ WARNING: Only use for debugging. Never trust unverified tokens!
 *
 * @param token - JWT token
 * @returns Decoded payload (unverified!)
 */
export function decodeJWT(token: string): JWTPayload | null {
  try {
    const parts = token.split('.')
    if (parts.length !== 3) {
      return null
    }

    const payload = parts[1]
    const decoded = JSON.parse(Buffer.from(payload, 'base64url').toString('utf-8'))

    return decoded
  } catch (error) {
    console.error('JWT decode failed:', error)
    return null
  }
}
