import { verifyAuthenticationResponse } from '@simplewebauthn/server'
import { createSession, generateToken, migrateUserRoles, readUsers, writeUsers } from '../../../utils/auth.js'
import { getWebAuthnConfig } from '../../../utils/webauthn-config.js'
import { consumeAuthChallenge } from '../../../utils/webauthn-challenges.js'
import { fromBase64Url, parseClientDataJSON } from '../../../utils/webauthn-encoding.js'
import { getAuthCookieOptions } from '../../../utils/cookies.js'
import { writeAuditLog } from '../../../utils/audit-log.js'
import { getClientIp } from '../../../utils/rate-limit.js'

function findUserByCredentialId(users, credentialId) {
  const cid = String(credentialId || '')
  for (const u of users) {
    const pks = Array.isArray(u.passkeys) ? u.passkeys : []
    const match = pks.find(pk => pk && pk.credentialId === cid)
    if (match) return { user: u, passkey: match }
  }
  return { user: null, passkey: null }
}

export default defineEventHandler(async (event) => {
  // CORS-Header für Cross-Device Authentication
  const requestOrigin = getHeader(event, 'origin')
  if (requestOrigin) {
    setHeader(event, 'Access-Control-Allow-Origin', requestOrigin)
    setHeader(event, 'Access-Control-Allow-Credentials', 'true')
    setHeader(event, 'Access-Control-Allow-Methods', 'POST, OPTIONS')
    setHeader(event, 'Access-Control-Allow-Headers', 'Content-Type, Authorization')
  }

  if (getMethod(event) === 'OPTIONS') {
    return { success: true }
  }

  const ip = getClientIp(event)
  const body = await readBody(event)
  const response = body?.credential
  if (!response) {
    throw createError({ statusCode: 400, statusMessage: 'Credential fehlt' })
  }

  // Challenge aus clientDataJSON holen
  const clientData = parseClientDataJSON(response.response?.clientDataJSON)
  const challenge = clientData?.challenge
  if (!challenge) {
    throw createError({ statusCode: 400, statusMessage: 'Ungültige Passkey-Antwort (Challenge fehlt)' })
  }

  if (!consumeAuthChallenge(challenge)) {
    await writeAuditLog('auth.passkey.login.failed', { ip, reason: 'unknown_or_expired_challenge' })
    throw createError({ statusCode: 400, statusMessage: 'Login-Session abgelaufen. Bitte erneut versuchen.' })
  }

  const users = await readUsers()
  const { user, passkey } = findUserByCredentialId(users, response.id)
  if (!user || !passkey) {
    await writeAuditLog('auth.passkey.login.failed', { ip, reason: 'credential_not_found' })
    throw createError({ statusCode: 401, statusMessage: 'Passkey unbekannt' })
  }

  if (user.active === false) {
    await writeAuditLog('auth.passkey.login.failed', { ip, userId: user.id, reason: 'inactive' })
    throw createError({
      statusCode: 403,
      statusMessage: 'Ihr Konto wurde noch nicht freigeschaltet. Bitte warten Sie auf die Bestätigung des Vorstands.'
    })
  }

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

  const authenticator = {
    credentialID: fromBase64Url(passkey.credentialId),
    credentialPublicKey: fromBase64Url(passkey.publicKey),
    counter: Number(passkey.counter) || 0,
    transports: passkey.transports || undefined
  }

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

  if (!verification.verified) {
    await writeAuditLog('auth.passkey.login.failed', { ip, userId: user.id, reason: 'verification_failed' })
    throw createError({ statusCode: 401, statusMessage: 'Passkey-Login fehlgeschlagen' })
  }

  // Counter/lastUsed aktualisieren
  passkey.counter = verification.authenticationInfo?.newCounter ?? passkey.counter
  passkey.lastUsedAt = new Date().toISOString()
  await writeUsers(users)

  const token = generateToken(user)
  await createSession(user.id, token)

  setCookie(event, 'auth_token', token, { ...getAuthCookieOptions() })

  await writeAuditLog('auth.passkey.login.success', { ip, userId: user.id })

  const migratedUser = migrateUserRoles({ ...user })
  const roles = Array.isArray(migratedUser.roles)
    ? migratedUser.roles
    : (migratedUser.role ? [migratedUser.role] : ['mitglied'])

  return {
    success: true,
    token,
    user: {
      id: user.id,
      email: user.email,
      name: user.name,
      roles
    },
    role: roles[0] || 'mitglied'
  }
})


