// Dabil WebAuthn (passkey / Face ID / fingerprint) client helpers.
window.WA = {
  // Manual base64url → ArrayBuffer decode. Avoids atob(), whose iOS Safari
  // implementation throws "The string did not match the expected pattern" on
  // some valid inputs. This decoder ignores any stray/invalid characters.
  b64urlToBuf(s) {
    const chars = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/';
    s = (s || '').replace(/-/g, '+').replace(/_/g, '/').replace(/=+$/, '');
    const out = [];
    let buffer = 0, bits = 0;
    for (let i = 0; i < s.length; i++) {
      const v = chars.indexOf(s[i]);
      if (v < 0) continue;
      buffer = (buffer << 6) | v;
      bits += 6;
      if (bits >= 8) { bits -= 8; out.push((buffer >> bits) & 0xFF); }
    }
    return new Uint8Array(out).buffer;
  },
  bufToB64url(buf) {
    const bytes = new Uint8Array(buf); let bin = '';
    for (const b of bytes) bin += String.fromCharCode(b);
    return btoa(bin).replace(/\+/g, '-').replace(/\//g, '_').replace(/=+$/, '');
  },
  supported() { return !!(window.PublicKeyCredential && navigator.credentials && navigator.credentials.create); },
  async platformAvailable() {
    try { return this.supported() && await PublicKeyCredential.isUserVerifyingPlatformAuthenticatorAvailable(); }
    catch (e) { return false; }
  },

  // Register a passkey for the currently signed-in user (called from Settings).
  async register() {
    const opts = await (await fetch('webauthn_register_options.php', { method: 'POST' })).json();
    if (opts.error) throw new Error('Please sign in again, then try enabling biometric sign-in.');
    const pub = {
      challenge: this.b64urlToBuf(opts.challenge),
      rp: opts.rp,
      user: { id: this.b64urlToBuf(opts.user.id), name: opts.user.name, displayName: opts.user.displayName },
      pubKeyCredParams: opts.pubKeyCredParams,
      timeout: opts.timeout,
      attestation: opts.attestation,
      authenticatorSelection: opts.authenticatorSelection,
      excludeCredentials: (opts.excludeCredentials || []).map(c => ({ type: 'public-key', id: this.b64urlToBuf(c.id) }))
    };
    let cred;
    try {
      cred = await navigator.credentials.create({ publicKey: pub });
    } catch (err) {
      if (err && (err.name === 'NotAllowedError' || err.name === 'AbortError')) throw new Error('Setup was cancelled or timed out. Please try again.');
      if (err && err.name === 'InvalidStateError') throw new Error('This device already has a passkey for your account.');
      throw new Error('Biometric setup could not run in this browser. Open the site in Safari or Chrome.');
    }
    if (!cred) throw new Error('No passkey was created.');
    const body = {
      id: cred.id, rawId: this.bufToB64url(cred.rawId), type: cred.type,
      response: {
        clientDataJSON: this.bufToB64url(cred.response.clientDataJSON),
        attestationObject: this.bufToB64url(cred.response.attestationObject)
      }
    };
    const res = await (await fetch('webauthn_register.php', { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify(body) })).json();
    if (!res.ok) throw new Error(res.error || 'Could not save your passkey.');
    return true;
  },

  // Sign in with a passkey. Requires an identifier (email/phone) so the server
  // can return the matching credentials — this is the most reliable path across
  // browsers and in-app views.
  async login(identifier) {
    if (!identifier) throw new Error('Enter your email or phone first, then tap Face ID / fingerprint.');
    let opts;
    try {
      const fd = new FormData(); fd.append('identifier', identifier);
      opts = await (await fetch('webauthn_login_options.php', { method: 'POST', body: fd })).json();
    } catch (e) { throw new Error('Could not reach the server. Please check your connection and try again.'); }
    if (!opts || !opts.challenge) throw new Error('Could not start biometric sign-in. Please try again.');
    if (!opts.allowCredentials || opts.allowCredentials.length === 0) {
      throw new Error('No biometric sign-in is set up for this account yet. Turn it on in Settings → Security & Privacy after signing in with your password.');
    }
    const pub = {
      challenge: this.b64urlToBuf(opts.challenge),
      rpId: opts.rpId,
      timeout: opts.timeout,
      userVerification: opts.userVerification,
      allowCredentials: opts.allowCredentials.map(c => ({ type: 'public-key', id: this.b64urlToBuf(c.id), transports: ['internal'] }))
    };
    let a;
    try {
      a = await navigator.credentials.get({ publicKey: pub });
    } catch (err) {
      if (err && (err.name === 'NotAllowedError' || err.name === 'AbortError')) throw new Error('Sign-in was cancelled or timed out. Please try again.');
      throw new Error('Biometric sign-in could not run in this browser. Open the site in Safari or Chrome, or sign in with your password.');
    }
    if (!a) throw new Error('No passkey was selected.');
    const body = {
      id: a.id, rawId: this.bufToB64url(a.rawId), type: a.type,
      response: {
        clientDataJSON: this.bufToB64url(a.response.clientDataJSON),
        authenticatorData: this.bufToB64url(a.response.authenticatorData),
        signature: this.bufToB64url(a.response.signature),
        userHandle: a.response.userHandle ? this.bufToB64url(a.response.userHandle) : null
      }
    };
    const res = await (await fetch('webauthn_login.php', { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify(body) })).json();
    if (!res.ok) throw new Error(res.error || 'Biometric sign-in failed.');
    return res.redirect || 'dashboard.php';
  }
};
