// Passkey authentication for login page
import { bufferToBase64url, base64urlToBuffer, getCsrfToken } from './webauthn_utils'
import type { WebAuthnAuthChallengeData, ErrorResponse, AuthSuccessResponse } from './types/webauthn'

document.addEventListener('DOMContentLoaded', () => {
  const passkeyLoginBtn = document.getElementById('passkey-login-btn') as HTMLButtonElement | null
  const emailInput = document.querySelector<HTMLInputElement>('#passkey_login_form input[type="email"]')
  const errorDiv = document.getElementById('passkey-login-error')

  if (!passkeyLoginBtn || !emailInput || !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 authenticateWithPasskey = async () => {
    const email = emailInput.value.trim()

    if (!email) {
      showError('Please enter your email address')
      emailInput.focus()
      return
    }

    try {
      hideError()
      passkeyLoginBtn.disabled = true
      passkeyLoginBtn.textContent = 'Authenticating...'

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

      if (!challengeResponse.ok) {
        const error: ErrorResponse = await challengeResponse.json()
        showError(error.error || 'No passkeys found for this email')
        return
      }

      const challengeData: WebAuthnAuthChallengeData = await challengeResponse.json()

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

      const allowCredentials: PublicKeyCredentialDescriptor[] = challengeData.allowCredentials.map(cred => ({
        type: cred.type as PublicKeyCredentialType,
        id: base64urlToBuffer(cred.id),
        transports: cred.transports as AuthenticatorTransport[]
      }))

      const publicKeyCredentialRequestOptions: PublicKeyCredentialRequestOptions = {
        challenge,
        rpId: challengeData.rpId,
        allowCredentials,
        timeout: challengeData.timeout,
        userVerification: challengeData.userVerification as UserVerificationRequirement
      }

      // 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('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).message) {
        errorMessage = (error as Error).message
      }

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

  passkeyLoginBtn.addEventListener('click', authenticateWithPasskey)

  // Allow pressing Enter in email field to trigger passkey login
  emailInput.addEventListener('keypress', (e) => {
    if (e.key === 'Enter') {
      e.preventDefault()
      authenticateWithPasskey()
    }
  })
})
