import { verifyRegistrationResponse } from '@simplewebauthn/server'
import { readUsers, writeUsers } from '../../../../utils/auth.js'
import { consumePreRegistration } from '../../../../utils/webauthn-challenges.js'
import { getWebAuthnConfig } from '../../../../utils/webauthn-config.js'
import { toBase64Url } from '../../../../utils/webauthn-encoding.js'
import { assertRateLimit, getClientIp } from '../../../../utils/rate-limit.js'
import { writeAuditLog } from '../../../../utils/audit-log.js'

function findUserAndToken(users, userId, tokenHash) {
  const now = Date.now()
  const idx = users.findIndex(u => String(u.id) === String(userId))
  if (idx === -1) return { idx: -1, tokenEntry: null }
  const user = users[idx]
  const list = Array.isArray(user.passkeyRecoveryTokens) ? user.passkeyRecoveryTokens : []
  const tokenEntry = list.find(t =>
    t &&
    t.tokenHash === tokenHash &&
    !t.usedAt &&
    t.expiresAt &&
    new Date(t.expiresAt).getTime() > now
  )
  return { idx, tokenEntry }
}

export default defineEventHandler(async (event) => {
  const ip = getClientIp(event)
  const body = await readBody(event)
  const recoveryId = String(body?.recoveryId || '')
  const response = body?.credential
  const passkeyName = body?.name ? String(body.name).slice(0, 80) : 'Passkey'

  if (!recoveryId || !response) {
    throw createError({ statusCode: 400, statusMessage: 'Ungültige Anfrage' })
  }

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

  const pre = consumePreRegistration(recoveryId)
  if (!pre) {
    throw createError({ statusCode: 400, statusMessage: 'Recovery-Session abgelaufen. Bitte erneut versuchen.' })
  }

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

  const users = await readUsers()
  const { idx, tokenEntry } = findUserAndToken(users, userId, tokenHash)
  if (idx === -1 || !tokenEntry) {
    await writeAuditLog('auth.passkey.recovery.complete.failed', { ip, reason: 'invalid_token', userId })
    throw createError({ statusCode: 400, statusMessage: 'Ungültiger oder abgelaufener Token' })
  }

  const { origin, rpId, requireUV } = getWebAuthnConfig()

  const verification = await verifyRegistrationResponse({
    response,
    expectedChallenge: challenge,
    expectedOrigin: origin,
    expectedRPID: rpId,
    requireUserVerification: requireUV
  })

  const { verified, registrationInfo } = verification
  if (!verified || !registrationInfo) {
    await writeAuditLog('auth.passkey.recovery.complete.failed', { ip, reason: 'verification_failed', userId })
    throw createError({ statusCode: 400, statusMessage: 'Passkey-Registrierung fehlgeschlagen' })
  }

  const {
    credentialID,
    credentialPublicKey,
    counter,
    credentialDeviceType,
    credentialBackedUp
  } = registrationInfo

  const credentialId = toBase64Url(credentialID)
  const publicKey = toBase64Url(credentialPublicKey)

  const user = users[idx]
  if (!Array.isArray(user.passkeys)) user.passkeys = []

  // Duplikate verhindern
  if (!user.passkeys.some(pk => pk.credentialId === credentialId)) {
    user.passkeys.push({
      id: `${Date.now()}`,
      credentialId,
      publicKey,
      counter: Number(counter) || 0,
      transports: Array.isArray(response.transports) ? response.transports : undefined,
      deviceType: credentialDeviceType,
      backedUp: !!credentialBackedUp,
      createdAt: new Date().toISOString(),
      lastUsedAt: null,
      name: passkeyName
    })
  }

  // Token als benutzt markieren (one-time)
  tokenEntry.usedAt = new Date().toISOString()

  users[idx] = user
  await writeUsers(users)

  await writeAuditLog('auth.passkey.recovery.complete.success', { ip, userId: user.id })
  return { success: true, message: 'Passkey hinzugefügt. Sie können sich jetzt mit dem neuen Passkey anmelden.' }
})

