import crypto from 'crypto'
import { generateRegistrationOptions } from '@simplewebauthn/server'
import { readUsers } from '../../../../utils/auth.js'
import { getWebAuthnConfig } from '../../../../utils/webauthn-config.js'
import { hashRecoveryToken } from '../../../../utils/passkey-recovery.js'
import { setPreRegistration } from '../../../../utils/webauthn-challenges.js'
import { assertRateLimit, getClientIp } from '../../../../utils/rate-limit.js'
import { writeAuditLog } from '../../../../utils/audit-log.js'

function findUserByTokenHash(users, tokenHash) {
  const now = Date.now()
  for (const u of users) {
    const list = Array.isArray(u.passkeyRecoveryTokens) ? u.passkeyRecoveryTokens : []
    const match = list.find(t =>
      t &&
      t.tokenHash === tokenHash &&
      !t.usedAt &&
      t.expiresAt &&
      new Date(t.expiresAt).getTime() > now
    )
    if (match) return { user: u, tokenEntry: match }
  }
  return { user: null, tokenEntry: null }
}

export default defineEventHandler(async (event) => {
  const query = getQuery(event)
  const token = String(query?.token || '')
  if (!token) {
    throw createError({ statusCode: 400, statusMessage: 'Token fehlt' })
  }

  const ip = getClientIp(event)
  assertRateLimit(event, {
    name: 'auth:passkey-recovery:options:ip',
    keyParts: [ip],
    windowMs: 10 * 60 * 1000,
    maxAttempts: 60,
    lockoutMs: 10 * 60 * 1000
  })

  const tokenHash = hashRecoveryToken(token)
  assertRateLimit(event, {
    name: 'auth:passkey-recovery:options:token',
    keyParts: [tokenHash],
    windowMs: 10 * 60 * 1000,
    maxAttempts: 10,
    lockoutMs: 30 * 60 * 1000
  })

  const users = await readUsers()
  const { user } = findUserByTokenHash(users, tokenHash)
  if (!user) {
    await writeAuditLog('auth.passkey.recovery.options.failed', { ip, reason: 'invalid_token' })
    throw createError({ statusCode: 400, statusMessage: 'Ungültiger oder abgelaufener Token' })
  }

  const { rpId, rpName } = getWebAuthnConfig()
  const excludeCredentials = (Array.isArray(user.passkeys) ? user.passkeys : [])
    .filter(pk => pk && pk.credentialId)
    .map(pk => ({ id: pk.credentialId, type: 'public-key', transports: pk.transports || undefined }))

  const options = await generateRegistrationOptions({
    rpName,
    rpID: rpId,
    userID: new TextEncoder().encode(String(user.id)),
    userName: user.email,
    userDisplayName: user.name || user.email,
    attestationType: 'none',
    authenticatorSelection: {
      residentKey: 'preferred',
      userVerification: 'preferred'
    },
    excludeCredentials
  })

  // Opaques recoveryId für Complete-Request
  const recoveryId = crypto.randomBytes(16).toString('hex')
  setPreRegistration(recoveryId, {
    challenge: options.challenge,
    tokenHash,
    userId: user.id
  })

  await writeAuditLog('auth.passkey.recovery.options.issued', { ip, userId: user.id })

  return { success: true, recoveryId, options }
})

