/* global Square, fkwcsq_gift_card_params */

/**
 * FunnelKit Square Gift Card Handler
 *
 * Handles Square Gift Card payment method initialization and tokenization.
 *
 * Architecture note (mirrors WooCommerce Square):
 * - "Apply" tokenizes the card and POSTs the nonce to the server, which stores
 *   it in session (no API call, no pre-authorization).
 * - A checkout review refresh (update_checkout) is then triggered, which calls
 *   add_gift_card_fragments() server-side: that does the read-only balance check
 *   (retrieve_gift_card), updates the session, and returns HTML fragments with
 *   the applied state and balance info.
 * - "Remove" just clears the session — no API call needed.
 *
 * @package FunnelKit_Square
 */

(function ($) {
    'use strict';

    // State management
    let giftCard = null;
    let payments = null;
    let isInitialized = false;
    let isInitializing = false;
    let isProcessing = false;
    let submitAfterApply = false;

    /**
     * Check whether the Square gift card iframe is attached.
     *
     * @returns {boolean}
     */
    function hasAttachedIframe() {
        return $('#fkwcsq-gift-card-container iframe').length > 0;
    }

    /**
     * Initialize the gift card handler.
     */
    function init() {
        $(document.body).on('updated_checkout', initializeGiftCard);
        $(document.body).on('updated_checkout', handleUpdatedCheckout);
        $(document.body).on('payment_method_selected', handlePaymentMethodChange);

        if ($('#fkwcsq-gift-card-container').length) {
            initializeGiftCard();
        }

        $('form.checkout, form#order_review').on('checkout_place_order_fkwcsq_gift_card', handlePlaceOrderGiftCard);

        $(document).on('click', '.fkwcsq-remove-gift-card', handleRemoveGiftCard);
    }

    /**
     * Handle payment method change.
     */
    function handlePaymentMethodChange() {
        const selectedPayment = $('input[name="payment_method"]:checked').val();

        if (selectedPayment === 'fkwcsq_gift_card' && !isInitialized) {
            initializeGiftCard();
        }
    }

    /**
     * Initialize Square Gift Card SDK.
     */
    async function initializeGiftCard() {
        const container = document.getElementById('fkwcsq-gift-card-container');

        if (!container || !$(container).is(':visible')) {
            return;
        }

        if (isInitializing) {
            return;
        }

        if (isInitialized && giftCard && hasAttachedIframe()) {
            return;
        }

        if (typeof Square === 'undefined') {
            console.error('Square SDK not loaded');
            showError(fkwcsq_gift_card_params.i18n.error_generic);
            return;
        }

        if (!fkwcsq_gift_card_params.application_id || !fkwcsq_gift_card_params.location_id) {
            showError('Square Gift Card is not configured correctly. Missing application or location ID.');
            return;
        }

        isInitializing = true;

        try {
            if (!payments) {
                payments = await Square.payments(
                    fkwcsq_gift_card_params.application_id,
                    fkwcsq_gift_card_params.location_id
                );
            }

            if (giftCard) {
                await destroyGiftCard();
            }

            $('#fkwcsq-gift-card-container').empty();

            giftCard = await payments.giftCard();
            await giftCard.attach('#fkwcsq-gift-card-container');

            isInitialized = true;
            $('#fkwcsq-gift-card-container').addClass('fkwcsq-initialized');

            giftCard.addEventListener('inputEvent', handleInputEvent);

        } catch (error) {
            console.error('Gift card initialization error:', error);
            showError(error && error.message ? error.message : fkwcsq_gift_card_params.i18n.error_generic);
        } finally {
            isInitializing = false;
        }
    }

    /**
     * Handle input events from Square gift card field.
     *
     * @param {Object} event Input event
     */
    function handleInputEvent(event) {
        if (event.eventType === 'focusClassAdded') {
            hideError();
        }
    }

    /**
     * Check if a gift card has been applied.
     *
     * The server renders .fkwcsq-gift-card-applied (via payment_fields or fragment)
     * when a gift card token is in session and the balance has been confirmed.
     *
     * @returns {boolean}
     */
    function isGiftCardApplied() {
        return $('.fkwcsq-gift-card-applied').length > 0;
    }

    /**
     * Handle Place Order when gift card payment is selected.
     * Applies gift card first if not yet applied, then allows checkout to proceed.
     *
     * @param {Object} e Event object
     * @returns {boolean|undefined}
     */
    function handlePlaceOrderGiftCard(e) {
        if (isGiftCardApplied()) {
            return true;
        }

        if (!giftCard || isProcessing) {
            if (!giftCard) {
                showError(fkwcsq_gift_card_params.i18n.error_generic);
            }
            return false;
        }

        const $placeOrderBtn = $('#place_order');
        if (!$placeOrderBtn.length) {
            return true;
        }

        submitAfterApply = true;
        isProcessing = true;
        const originalText = $placeOrderBtn.attr('data-value') || $placeOrderBtn.val() || $placeOrderBtn.text();
        $placeOrderBtn.prop('disabled', true).val(fkwcsq_gift_card_params.i18n.applying);
        hideError();

        applyGiftCardForCheckout()
            .then(() => {
                // update_checkout will refresh fragments (balance check) and
                // handleUpdatedCheckout() will then submit the form.
                $(document.body).trigger('update_checkout');
            })
            .catch((error) => {
                console.error('Gift card apply error:', error);
                showError(error.message || fkwcsq_gift_card_params.i18n.error_generic);
                $placeOrderBtn.prop('disabled', false).val(originalText);
                submitAfterApply = false;
            })
            .finally(() => {
                isProcessing = false;
            });

        return false;
    }

    /**
     * After a checkout refresh: if we stored a token and the fragment has confirmed
     * the gift card applied state, submit the form. If the balance was insufficient
     * the server clears the session and returns a "not-applied" fragment — in that
     * case re-enable the Place Order button and reinitialize the gift card field.
     */
    function handleUpdatedCheckout() {
        if (!submitAfterApply) {
            return;
        }

        if (isGiftCardApplied()) {
            submitAfterApply = false;
            const $form = $('form.checkout, form#order_review');
            if ($form.length) {
                $form.submit();
            }
        } else {
            // Balance was insufficient — fragment returned the "not-applied" state.
            // Reset state and restore the Place Order button so the user can act.
            submitAfterApply = false;
            $('#place_order').prop('disabled', false);

            // Re-initialize the gift card field into the refreshed container.
            isInitialized = false;
            giftCard = null;
            initializeGiftCard();
        }
    }

    /**
     * Tokenize the gift card and send the nonce to the server.
     *
     * @returns {Promise}
     */
    async function applyGiftCardForCheckout() {
        const result = await giftCard.tokenize();

        if (result.status !== 'OK') {
            throw new Error(result.errors ? result.errors[0].message : fkwcsq_gift_card_params.i18n.error_invalid);
        }

        const response = await applyGiftCardToServer(result.token);

        if (!response.success) {
            throw new Error(response.data.message || fkwcsq_gift_card_params.i18n.error_generic);
        }

        // Server just stored the token. Balance check happens in the subsequent
        // update_checkout → add_gift_card_fragments() call.
        return response.data;
    }

    /**
     * POST gift card token to server for session storage.
     *
     * @param {string} token Gift card nonce
     * @returns {Promise} AJAX response
     */
    function applyGiftCardToServer(token) {
        return $.ajax({
            url: fkwcsq_gift_card_params.ajax_url,
            type: 'POST',
            data: {
                action: 'fkwcsq_apply_gift_card',
                nonce: fkwcsq_gift_card_params.apply_nonce,
                token
            }
        });
    }

    /**
     * Handle remove gift card button click.
     *
     * Clears the session server-side. No API call needed — with autocomplete=true
     * there is no pre-authorization to cancel.
     *
     * @param {Event} e Click event
     */
    function handleRemoveGiftCard(e) {
        e.preventDefault();

        if (isProcessing) {
            return;
        }

        isProcessing = true;

        $.ajax({
            url: fkwcsq_gift_card_params.ajax_url,
            type: 'POST',
            data: {
                action: 'fkwcsq_remove_gift_card',
                nonce: fkwcsq_gift_card_params.remove_nonce
            },
            success () {
                $(document.body).trigger('update_checkout');
            },
            complete () {
                isProcessing = false;
            }
        });
    }

    /**
     * Show error message.
     *
     * @param {string} message Error message
     */
    function showError(message) {
        $('#fkwcsq-gift-card-error')
            .text(message)
            .show();
    }

    /**
     * Hide error message.
     */
    function hideError() {
        $('#fkwcsq-gift-card-error').hide();
    }

    /**
     * Destroy gift card instance.
     */
    async function destroyGiftCard() {
        if (giftCard) {
            try {
                await giftCard.destroy();
            } catch (error) {
                // Silently handle
            }
            giftCard = null;
            isInitialized = false;
        }
    }

    // Initialize on document ready
    $(document).ready(init);

    $(document).on('change', 'input[name="payment_method"]', handlePaymentMethodChange);

    $(window).on('pagehide', destroyGiftCard);

})(jQuery);
