// Discoverable passkey authentication (usernameless login)
import { bufferToBase64url, base64urlToBuffer, getCsrfToken } from './webauthn_utils'
import type { WebAuthnAuthChallengeData, ErrorResponse, AuthSuccessResponse } from './types/webauthn'

document.addEventListener('DOMContentLoaded', () => {
  const discoverableBtn = document.getElementById('passkey-discoverable-btn') as HTMLButtonElement | null
  const errorDiv = document.getElementById('passkey-discoverable-error')

  if (!discoverableBtn || !errorDiv) return

  const showError = (message: string) => {
    errorDiv.classList.remove('hidden')
    const errorText = errorDiv.querySelector('p')
    if (errorText) {
      errorText.textContent = message
    }
  }

  const hideError = () => {
    errorDiv.classList.add('hidden')
    const errorText = errorDiv.querySelector('p')
    if (errorText) {
      errorText.textContent = ''
    }
  }

  const authenticateWithDiscoverablePasskey = async () => {
    try {
      hideError()
      discoverableBtn.disabled = true
      discoverableBtn.textContent = 'Authenticating...'

      // Fetch challenge from server (no email required)
      const challengeResponse = await fetch('/api/webauthn/authentication/challenge', {
        method: 'POST',
        headers: {
          'Content-Type': 'application/json',
          'X-CSRF-Token': getCsrfToken()
        }
      })

      if (!challengeResponse.ok) {
        const error: ErrorResponse = await challengeResponse.json()
        showError(error.error || 'Failed to get authentication challenge')
        return
      }

      const challengeData: WebAuthnAuthChallengeData = await challengeResponse.json()

      // Convert challenge to ArrayBuffer
      const challenge = base64urlToBuffer(challengeData.challenge)

      const publicKeyCredentialRequestOptions: PublicKeyCredentialRequestOptions = {
        challenge,
        rpId: challengeData.rpId,
        timeout: challengeData.timeout,
        userVerification: challengeData.userVerification as UserVerificationRequirement
        // No allowCredentials - let the authenticator show all credentials for this RP ID
      }

      // Get assertion from authenticator
      const assertion = await navigator.credentials.get({
        publicKey: publicKeyCredentialRequestOptions
      }) as PublicKeyCredential

      if (!assertion.response || !(assertion.response instanceof AuthenticatorAssertionResponse)) {
        throw new Error('Invalid assertion response')
      }

      const authData = {
        assertion: {
          id: assertion.id,
          rawId: bufferToBase64url(assertion.rawId),
          type: assertion.type,
          response: {
            clientDataJSON: bufferToBase64url(assertion.response.clientDataJSON),
            authenticatorData: bufferToBase64url(assertion.response.authenticatorData),
            signature: bufferToBase64url(assertion.response.signature),
            userHandle: assertion.response.userHandle ?
              bufferToBase64url(assertion.response.userHandle) : null
          }
        }
      }

      // Send to server
      const authResponse = await fetch('/api/webauthn/authenticate', {
        method: 'POST',
        headers: {
          'Content-Type': 'application/json',
          'X-CSRF-Token': getCsrfToken()
        },
        body: JSON.stringify(authData)
      })

      if (authResponse.ok) {
        const result: AuthSuccessResponse = await authResponse.json()
        // Redirect to the provided URL
        window.location.href = result.redirect
      } else {
        showError('Authentication failed')
      }
    } catch (error) {
      console.error('Discoverable authentication error:', error)

      let errorMessage = 'Failed to authenticate'
      if ((error as Error).name === 'NotAllowedError') {
        errorMessage = 'Authentication was cancelled or timed out'
      } else if ((error as Error).name === 'NotSupportedError') {
        errorMessage = 'Your browser or authenticator does not support passkeys'
      } else if ((error as Error).message) {
        errorMessage = (error as Error).message
      }

      showError(errorMessage)
    } finally {
      discoverableBtn.disabled = false
      discoverableBtn.innerHTML = '<svg class="h-5 w-5"><use href="#hero-key"></use></svg> Log in with passkey'
    }
  }

  discoverableBtn.addEventListener('click', authenticateWithDiscoverablePasskey)
})
