/**
 * @file
 * Handles WebAuthn registration via a Drupal form.
 */

(($, Drupal) => {
  'use strict';

  const showMessages = (messages = []) => {
    const drupalMessages = new Drupal.Message();
    drupalMessages.clear();
    messages.forEach(({ message, options }) => {
      drupalMessages.add(message, options);
    });
  };

  const base64urlToUint8Array = (base64url) => {
    let base64 = base64url.replace(/-/g, '+').replace(/_/g, '/').replace(/=/g, '');
    const pad = base64.length % 4;
    if (pad) {
      if (pad === 1) throw new Error('Invalid base64url string');
      base64 += '='.repeat(4 - pad);
    }
    const binary = window.atob(base64);
    return Uint8Array.from(binary, (c) => c.charCodeAt(0));
  };

  const uint8ArrayToBase64url = (buffer) => {
    return btoa(String.fromCharCode(...new Uint8Array(buffer)))
      .replace(/\+/g, '-').replace(/\//g, '_').replace(/=/g, '');
  };

  const registerWebAuthn = async (csrfToken) => {
    const response = await $.ajax({
      url: `/mo-webauthn/attestation`,
      type: 'GET',
      data: { token: csrfToken },
      dataType: 'json',
    });
    response.challenge = base64urlToUint8Array(response.challenge);
    response.user.id = base64urlToUint8Array(response.user.id);
    if (response.excludeCredentials) {
      response.excludeCredentials = response.excludeCredentials.map((cred) => ({
        ...cred,
        id: base64urlToUint8Array(cred.id),
      }));
    }
    const credential = await navigator.credentials.create({
      publicKey: response
    });
    const attestation = credential.response;
    return {
      id: credential.id,
      rawId: uint8ArrayToBase64url(credential.rawId),
      type: credential.type,
      response: {
        clientDataJSON: uint8ArrayToBase64url(attestation.clientDataJSON),
        attestationObject: uint8ArrayToBase64url(attestation.attestationObject),
      },
      extensions: credential.getClientExtensionResults?.(),
    };
  };

  Drupal.behaviors.moWebauthnRegister = {
    attach(context) {
      const btn = context.querySelector('#mo-webauthn-register-btn');
      if (!btn || btn.dataset.attached === 'true') return;
      btn.dataset.attached = 'true';
      btn.addEventListener('click', async (e) => {
        e.preventDefault();
        const csrf = document.getElementById('mo-csrf-token').value;
        const form = btn.closest('form');
        try {
          const webauthnData = await registerWebAuthn(csrf);
          form.querySelector('input[name="credential"]').value = JSON.stringify(webauthnData);
          // Submit the form after credential is attached
          form.submit();
        } catch (err) {
          let message = {
            message: Drupal.t('Unable to registration WebAuthn credential. Contact the site administrator if the problem persists.'),
            options: {'type': 'error'}
          };
          if (err['responseText']) {
            let responseText = JSON.parse(err['responseText']);
            message['message'] = responseText['message'];
          }
          showMessages([message]);
        }
      });
    }
  };

})(jQuery, Drupal);
