/**
 * ZA Creative Login Shield - WebAuthn / Passkeys
 *
 * Handles passkey registration (profile page) and passkey login
 * (wp-login.php and the custom login page).
 */
(function() {
    'use strict';

    if ( typeof window.zaclsWebAuthn === 'undefined' || ! window.zaclsWebAuthn.enabled ) {
        return;
    }

    if ( typeof navigator.credentials === 'undefined' ||
         typeof window.PublicKeyCredential === 'undefined' ||
         typeof window.fetch === 'undefined' ||
         typeof window.atob === 'undefined' ) {
        return;
    }

    var config = window.zaclsWebAuthn;

    function base64urlToArrayBuffer( base64url ) {
        var base64 = String( base64url ).replace( /-/g, '+' ).replace( /_/g, '/' );
        var padding = base64.length % 4;
        if ( padding ) {
            base64 += '===='.substring( padding );
        }
        var binary = window.atob( base64 );
        var bytes = new Uint8Array( binary.length );
        for ( var i = 0; i < binary.length; i++ ) {
            bytes[i] = binary.charCodeAt( i );
        }
        return bytes.buffer;
    }

    function bufferToBase64url( buffer ) {
        var binary = '';
        var bytes = new Uint8Array( buffer );
        for ( var i = 0; i < bytes.byteLength; i++ ) {
            binary += String.fromCharCode( bytes[i] );
        }
        return window.btoa( binary ).replace( /\+/g, '-' ).replace( /\//g, '_' ).replace( /=+$/, '' );
    }

    function post( data ) {
        var formData = new FormData();
        formData.append( 'action', data.action );
        formData.append( 'nonce', config.nonce );
        if ( data.credential ) {
            formData.append( 'credential', JSON.stringify( data.credential ) );
        }
        if ( data.name ) {
            formData.append( 'name', data.name );
        }
        if ( data.redirect_to ) {
            formData.append( 'redirect_to', data.redirect_to );
        }
        return fetch( config.ajaxUrl, {
            method: 'POST',
            body: formData
        } ).then( function( response ) {
            return response.json();
        } );
    }

    function showMessage( el, text, isError ) {
        if ( ! el ) {
            return;
        }
        el.style.display = 'block';
        el.style.color = isError ? '#dc3232' : '#46b450';
        el.textContent = text;
    }

    function getTransports( credential ) {
        if ( credential.response && typeof credential.response.getTransports === 'function' ) {
            return credential.response.getTransports();
        }
        return [];
    }

    function getMessage( data, fallback ) {
        return ( data && data.message ) ? data.message : fallback;
    }

    function handleRegistrationFailure( data ) {
        window.alert( getMessage( data, config.i18n.error ) );
    }

    var registerBtn = document.getElementById( 'zacls-register-passkey' );
    if ( registerBtn ) {
        registerBtn.addEventListener( 'click', function() {
            post( { action: 'zacls_webauthn_create' } ).then( function( data ) {
                if ( ! data.success ) {
                    handleRegistrationFailure( data.data );
                    return;
                }

                var options = data.data;
                options.challenge = base64urlToArrayBuffer( options.challenge );
                options.user.id = base64urlToArrayBuffer( options.user.id );
                if ( options.excludeCredentials ) {
                    options.excludeCredentials.forEach( function( credential ) {
                        credential.id = base64urlToArrayBuffer( credential.id );
                    } );
                }

                return navigator.credentials.create( { publicKey: options } ).then( function( credential ) {
                    if ( ! credential ) {
                        throw new Error( config.i18n.error );
                    }

                    var payload = {
                        id: credential.id,
                        rawId: bufferToBase64url( credential.rawId ),
                        type: credential.type,
                        transports: getTransports( credential ),
                        response: {
                            clientDataJSON: bufferToBase64url( credential.response.clientDataJSON ),
                            attestationObject: bufferToBase64url( credential.response.attestationObject )
                        }
                    };

                    return post( { action: 'zacls_webauthn_register', credential: payload } );
                } ).then( function( response ) {
                    if ( response.success ) {
                        window.alert( getMessage( response.data, config.i18n.registered ) );
                        window.location.reload();
                    } else {
                        handleRegistrationFailure( response.data );
                    }
                } );
            } ).catch( function() {
                handleRegistrationFailure( null );
            } );
        } );
    }

    var loginBtn = document.getElementById( 'zacls_passkey_login_button' );
    if ( loginBtn ) {
        loginBtn.addEventListener( 'click', function() {
            var msg = document.getElementById( 'zacls_passkey_message' );

            post( { action: 'zacls_webauthn_get' } ).then( function( data ) {
                if ( ! data.success ) {
                    showMessage( msg, getMessage( data.data, config.i18n.error ), true );
                    return;
                }

                var options = data.data;
                options.challenge = base64urlToArrayBuffer( options.challenge );

                return navigator.credentials.get( { publicKey: options } ).then( function( credential ) {
                    if ( ! credential ) {
                        throw new Error( config.i18n.canceled );
                    }

                    var payload = {
                        id: credential.id,
                        rawId: bufferToBase64url( credential.rawId ),
                        type: credential.type,
                        response: {
                            clientDataJSON: bufferToBase64url( credential.response.clientDataJSON ),
                            authenticatorData: bufferToBase64url( credential.response.authenticatorData ),
                            signature: bufferToBase64url( credential.response.signature ),
                            userHandle: credential.response.userHandle
                                ? bufferToBase64url( credential.response.userHandle )
                                : null
                        }
                    };

                    return post( {
                        action: 'zacls_webauthn_verify',
                        credential: payload,
                        redirect_to: config.redirectTo
                    } );
                } ).then( function( response ) {
                    if ( response.success ) {
                        window.location.href = response.data.redirect;
                    } else {
                        showMessage( msg, getMessage( response.data, config.i18n.failed ), true );
                    }
                } );
            } ).catch( function( err ) {
                showMessage( msg, ( err && err.message ) ? err.message : config.i18n.failed, true );
            } );
        } );
    }
})();