(function($) {
    'use strict';

    var CONFIG = window.FLUX_HOSTED || {};
    var flux = null;
    var elements = null;
    var fields = {};
    var fieldState = {};
    var authData = null;
    var authTokenExpiry = 0;
    var authTokenUses = 0;
    var MAX_TOKEN_USES = 5;
    var currentContext = null; // 'checkout' or 'modal'
    var modalOrderId = null;

    // Auto-authorization state (matches example/index.html pattern)
    var authorizedToken = null;
    var authorizationResult = null;
    var authError = null;
    var isAuthorizing = false;
    var authDebounceTimer = null;

    var REQUIRED_FIELDS = [
        'cardNumber', 'cardExpiry', 'cardCvv', 'cardName', 'phone',
        'billingAddress', 'billingCity', 'billingState', 'billingZip', 'billingCountry'
    ];

    var OPTIONAL_FIELDS = ['billingAddress2', 'email'];

    // =========================================================================
    // Auth Token Management
    // =========================================================================

    function fetchAuthToken() {
        return $.ajax({
            url: CONFIG.ajax_url,
            type: 'POST',
            data: {
                action: 'flux_hosted_auth',
                nonce: CONFIG.auth_nonce,
            },
        }).then(function(response) {
            if (response.success) {
                authData = response.data;
                authTokenExpiry = Date.now() + (14 * 60 * 1000);
                authTokenUses = 0;
                // Push the fresh token into the existing SDK instance (if any)
                // so already-mounted iframes pick it up without remounting and
                // losing typed card data. SDKs older than 1.0.6 don't expose
                // refreshAuthToken — the destroy/rebuild fallback in
                // consumeTokenUse handles those.
                if (flux && typeof flux.refreshAuthToken === 'function') {
                    flux.refreshAuthToken(authData.authToken);
                }
                return authData;
            }
            throw new Error(response.data && response.data.message || 'Auth failed');
        });
    }

    function isTokenValid() {
        return authData && Date.now() < authTokenExpiry && authTokenUses < MAX_TOKEN_USES;
    }

    function ensureAuthToken() {
        if (isTokenValid()) {
            return $.Deferred().resolve(authData).promise();
        }
        return fetchAuthToken();
    }

    function consumeTokenUse() {
        authTokenUses++;
        if (authTokenUses >= MAX_TOKEN_USES) {
            // Hit the per-token use limit. Refresh in-place via the SDK so we
            // don't tear down iframes and lose typed card data.
            fetchAuthToken().then(function(data) {
                if (flux && typeof flux.refreshAuthToken === 'function') {
                    flux.refreshAuthToken(data.authToken);
                } else {
                    // SDK too old to support in-place refresh — fall back to
                    // the destroy/rebuild path (loses card data, but rare).
                    authorizedToken = null;
                    authorizationResult = null;
                    destroySDK();
                    var prefix = currentContext === 'checkout' ? 'flux-hf' : 'flux-hf-modal';
                    initSDK(data, prefix);
                }
            });
        }
    }

    // =========================================================================
    // WP nonce refresh (proactive)
    //
    // WP nonces age out (12-24h, sometimes shorter behind caching). A customer
    // who sits on the checkout page past that window will hit "Your session has
    // expired" when they finally click Place Order. Re-issue them every 8 min
    // and update CONFIG so the next AJAX call uses the fresh value.
    // =========================================================================
    var nonceRefreshTimer = null;

    function refreshNoncesNow() {
        if (!CONFIG.ajax_url) return;
        return $.ajax({
            url: CONFIG.ajax_url,
            type: 'POST',
            data: { action: 'flux_refresh_nonces' },
        }).then(function(response) {
            if (response && response.success && response.data) {
                if (response.data.auth_nonce)     CONFIG.auth_nonce     = response.data.auth_nonce;
                if (response.data.pay_nonce)      CONFIG.pay_nonce      = response.data.pay_nonce;
                if (response.data.cart_nonce)     CONFIG.cart_nonce     = response.data.cart_nonce;
                if (response.data.checkout_nonce) CONFIG.checkout_nonce = response.data.checkout_nonce;
                // Also keep FLUX_PAYNOW (used by the side-cart Pay Now) in sync.
                if (window.FLUX_PAYNOW) {
                    if (response.data.cart_nonce)     window.FLUX_PAYNOW.cart_nonce = response.data.cart_nonce;
                    if (response.data.checkout_nonce) window.FLUX_PAYNOW.nonce      = response.data.checkout_nonce;
                }
            }
        });
    }

    function startNonceRefresh() {
        if (nonceRefreshTimer) return;
        nonceRefreshTimer = setInterval(refreshNoncesNow, 8 * 60 * 1000);
    }

    // Kick the refresh loop on every page load that has the SDK config.
    if (CONFIG.ajax_url) {
        $(function() { startNonceRefresh(); });
    }

    // =========================================================================
    // SDK Initialization
    // =========================================================================

    function destroySDK() {
        if (flux) {
            flux.destroy();
            flux = null;
            elements = null;
            fields = {};
        }
    }

    function initSDK(data, prefix) {
        destroySDK();

        flux = new FluxHostedFields(data.authToken, data.publicKey);
        elements = flux.elements();
        currentContext = prefix === 'flux-hf' ? 'checkout' : 'modal';

        resetState();
        mountFields(prefix);
    }

    // =========================================================================
    // State Management
    // =========================================================================

    function resetState() {
        fieldState = {};
        REQUIRED_FIELDS.forEach(function(f) {
            fieldState[f] = { valid: false, complete: false };
        });
        OPTIONAL_FIELDS.forEach(function(f) {
            fieldState[f] = { valid: true, complete: true };
        });
        authorizedToken = null;
        authorizationResult = null;
        authError = null;
        isAuthorizing = false;
        clearTimeout(authDebounceTimer);
    }

    function allFieldsValid() {
        return REQUIRED_FIELDS.every(function(f) {
            return fieldState[f] && fieldState[f].valid && fieldState[f].complete;
        });
    }

    // =========================================================================
    // Field Mounting
    // =========================================================================

    function mountFields(prefix) {
        var addressOptions = {
            placeholder: '123 Main St',
            googleApiKey: 'AIzaSyBU-dr62CT1brAoCMCDnrsuMLNY-_HndPg'
        };

        var fieldDefs = [
            { type: 'cardNumber',      id: prefix + '-card-number',      key: 'cardNumber',      options: { placeholder: '1234 1234 1234 1234' } },
            { type: 'cardExpiry',      id: prefix + '-card-expiry',      key: 'cardExpiry',      options: { placeholder: 'MM / YY' } },
            { type: 'cardCvv',         id: prefix + '-card-cvv',         key: 'cardCvv',         options: { placeholder: 'CVV' } },
            { type: 'cardName',        id: prefix + '-card-name',        key: 'cardName',        options: { placeholder: 'John Smith' } },
            { type: 'email',           id: prefix + '-email',            key: 'email',           options: { placeholder: 'email@example.com' } },
            { type: 'phone',           id: prefix + '-phone',            key: 'phone',           options: { placeholder: '(555) 123-4567' } },
            { type: 'billingAddress',  id: prefix + '-billing-address',  key: 'billingAddress',  options: addressOptions },
            { type: 'billingAddress2', id: prefix + '-billing-address2', key: 'billingAddress2', options: { placeholder: 'Apt 4B' } },
            { type: 'billingCity',     id: prefix + '-billing-city',     key: 'billingCity',     options: { placeholder: 'City' } },
            { type: 'billingState',    id: prefix + '-billing-state',    key: 'billingState',    options: { placeholder: 'State' } },
            { type: 'billingZip',      id: prefix + '-billing-zip',      key: 'billingZip',      options: { placeholder: 'ZIP' } },
            { type: 'billingCountry',  id: prefix + '-billing-country',  key: 'billingCountry',  options: { placeholder: 'US' } },
        ];

        fieldDefs.forEach(function(def) {
            var container = document.getElementById(def.id);
            if (!container) return;

            var field = elements.create(def.type, def.options);
            field.mount('#' + def.id);
            fields[def.key] = field;

            field.on('change', function(event) {
                fieldState[def.key] = { valid: event.valid, complete: event.complete };
                updateFieldUI(def.id, event);
                onFieldChange();

                // Auto-fill city/state/zip/country when address selected via autocomplete
                if (def.type === 'billingAddress' && event.address) {
                    autoFillAddressFields(event.address);
                }
            });

            field.on('focus', function() {
                $('#' + def.id).addClass('focused');
            });

            field.on('blur', function() {
                $('#' + def.id).removeClass('focused');
            });

            if (def.type === 'billingAddress') {
                setupAddressSuggestions(field, prefix);
            }
        });

        // Pre-fill email/phone from WooCommerce customer data
        var prefill = CONFIG.prefill || {};
        if (prefill.billing_email && fields.email) {
            setTimeout(function() { fields.email.setValue(prefill.billing_email); }, 1000);
        }
        if (prefill.billing_phone && fields.phone) {
            setTimeout(function() { fields.phone.setValue(prefill.billing_phone); }, 1000);
        }
    }

    function setupAddressSuggestions(field, prefix) {
        var dropdownId = prefix + '-address-suggestions';
        var $dropdown = $('#' + dropdownId);

        field.on('suggestions', function(event) {
            var suggestions = event.suggestions || [];
            if (suggestions.length === 0) {
                $dropdown.removeClass('visible').empty();
                return;
            }

            var html = suggestions.map(function(s) {
                return '<div class="flux-hf-suggestion-item" data-place-id="' +
                    FluxHostedFields.sanitizeAttr(s.placeId) + '">' +
                    '<div class="flux-hf-suggestion-main">' + FluxHostedFields.sanitizeHtml(s.mainText) + '</div>' +
                    '<div class="flux-hf-suggestion-secondary">' + FluxHostedFields.sanitizeHtml(s.secondaryText) + '</div>' +
                    '</div>';
            }).join('');

            $dropdown.html(html).addClass('visible');

            $dropdown.find('.flux-hf-suggestion-item').on('mousedown', function(e) {
                e.preventDefault();
                var placeId = $(this).attr('data-place-id');
                field.selectSuggestion(placeId);
                $dropdown.removeClass('visible');
            });
        });

        field.on('blur', function() {
            setTimeout(function() { $dropdown.removeClass('visible'); }, 200);
        });
    }

    function autoFillAddressFields(address) {
        if (address.city && fields.billingCity) {
            fields.billingCity.setValue(address.city);
        }
        if (address.state && fields.billingState) {
            fields.billingState.setValue(address.state);
        }
        if (address.postalCode && fields.billingZip) {
            fields.billingZip.setValue(address.postalCode);
        }
        if (address.country && fields.billingCountry) {
            fields.billingCountry.setValue(address.country);
        }
    }

    // =========================================================================
    // UI Helpers
    // =========================================================================

    function updateFieldUI(fieldId, event) {
        var $container = $('#' + fieldId);
        var $error = $('#' + fieldId + '-error');

        $container.removeClass('valid invalid');

        if (event.complete && event.valid) {
            $container.addClass('valid');
            if ($error.length) $error.text('');
        } else if (event.complete && !event.valid) {
            $container.addClass('invalid');
            if ($error.length) $error.text(event.error && event.error.message || 'Invalid');
        } else if (event.error) {
            if ($error.length) $error.text(event.error.message);
        } else {
            if ($error.length) $error.text('');
        }
    }

    function showAuthStatus(ctx) {
        var id = ctx === 'checkout' ? '#flux-hf-auth-status' : '#flux-hf-modal-auth-status';
        $(id).show();
    }

    function hideAuthStatus(ctx) {
        var id = ctx === 'checkout' ? '#flux-hf-auth-status' : '#flux-hf-modal-auth-status';
        $(id).hide();
    }

    function showError(ctx, msg) {
        var id = ctx === 'checkout' ? '#flux-hf-error-msg' : '#flux-hf-modal-error-msg';
        $(id).text(msg).show();
    }

    function hideError(ctx) {
        var id = ctx === 'checkout' ? '#flux-hf-error-msg' : '#flux-hf-modal-error-msg';
        $(id).hide();
    }

    // =========================================================================
    // Auto-Authorization (matches example/index.html pattern)
    //
    // Flow:
    //   1. User fills fields
    //   2. When all required fields are valid, debounce 500ms → authorize
    //   3. Authorization calls flux.createToken() to tokenize & auth the card
    //   4. On success → store token, enable Pay/Place Order button
    //   5. On any field change → clear token, re-authorize
    // =========================================================================

    function onFieldChange() {
        // Clear previous authorization when any field changes
        if (authorizedToken || authError) {
            authorizedToken = null;
            authorizationResult = null;
            authError = null;
            if (currentContext === 'checkout') {
                $('#flux_card_token').val('');
                $('#flux_card_last_four').val('');
                $('#flux_card_brand').val('');
            }
        }
        hideError(currentContext);
        updateUI();
        scheduleAuthorization();
    }

    function scheduleAuthorization() {
        clearTimeout(authDebounceTimer);
        authDebounceTimer = setTimeout(attemptAuthorization, 500);
    }

    function attemptAuthorization() {
        if (isAuthorizing || authorizedToken || !allFieldsValid() || !flux) return;

        isAuthorizing = true;
        authError = null;
        updateUI();

        ensureAuthToken().then(function(data) {
            if (!flux) {
                initSDK(data, currentContext === 'checkout' ? 'flux-hf' : 'flux-hf-modal');
                isAuthorizing = false;
                authError = 'Session refreshed. Please re-enter your card details.';
                updateUI();
                return $.Deferred().reject().promise();
            }
            return doTokenize();
        }).then(function(result) {
            if (!result) return;
            isAuthorizing = false;

            if (result.error) {
                if (result.error.code === 'API_ERROR') {
                    destroySDK();
                    authError = 'Session expired. Please re-enter your card details.';
                    fetchAuthToken().then(function(data) {
                        var prefix = currentContext === 'checkout' ? 'flux-hf' : 'flux-hf-modal';
                        initSDK(data, prefix);
                    });
                } else {
                    authError = result.error.message || 'Card authorization failed';
                }
                updateUI();
                return;
            }
            if (result.authorizationStatus === 'DECLINED') {
                authError = 'Card declined: ' + (result.declineReason || 'Please try another card');
                updateUI();
                return;
            }

            // Success — store authorized token
            authorizedToken = result.cardToken;
            authorizationResult = result;

            if (currentContext === 'checkout') {
                $('#flux_card_token').val(result.cardToken);
                $('#flux_card_last_four').val(result.lastFour || '');
                $('#flux_card_brand').val(result.cardBrand || '');
            }
            updateUI();
        }).fail(function(err) {
            isAuthorizing = false;
            authError = (err && err.message) || 'Authorization failed';
            updateUI();
        });
    }

    function doTokenize() {
        var prefill = CONFIG.prefill || {};
        return flux.createToken({
            email: prefill.billing_email || '',
            firstName: prefill.billing_first_name || '',
            lastName: prefill.billing_last_name || '',
            phone: prefill.billing_phone || '',
        }).then(function(result) {
            consumeTokenUse();
            return result;
        });
    }

    function updateUI() {
        var ctx = currentContext;
        if (!ctx) return;

        // Auth status indicator
        if (isAuthorizing) {
            showAuthStatus(ctx);
        } else {
            hideAuthStatus(ctx);
        }

        // Error message
        if (authError && !isAuthorizing) {
            showError(ctx, authError);
        } else {
            hideError(ctx);
        }

        // Button state
        if (ctx === 'checkout') {
            var $btn = $('form.checkout #place_order');
            if (isAuthorizing) {
                $btn.prop('disabled', true).text('Authorizing...');
            } else if (authorizedToken) {
                $btn.prop('disabled', false).text('Place Order');
            } else {
                $btn.prop('disabled', true).text('Place Order');
            }
        } else if (ctx === 'modal') {
            var $mbtn = $('#flux-hf-modal-pay-btn');
            if (isAuthorizing) {
                $mbtn.prop('disabled', true).text('Authorizing...');
            } else if (authorizedToken) {
                $mbtn.prop('disabled', false).text('Pay Now');
            } else {
                $mbtn.prop('disabled', true).text('Pay Now');
            }
        }
    }

    // =========================================================================
    // Checkout Page Flow
    // =========================================================================

    function initCheckoutFlow() {
        fetchAuthToken().then(function(data) {
            initSDK(data, 'flux-hf');
        }).fail(function(err) {
            console.error('Flux: Failed to initialize hosted fields', err);
        });

        // WooCommerce fires this before submit
        $(document.body).on('checkout_place_order_flux_gateway', function() {
            if ($('#flux_card_token').val()) {
                return true; // Token already set via auto-auth, let WC proceed
            }
            if (!allFieldsValid()) {
                showError('checkout', 'Please complete all required fields.');
            }
            return false;
        });
    }

    // =========================================================================
    // Modal Flow (Cart / Mini-Cart)
    // =========================================================================

    function openModal(orderId) {
        modalOrderId = orderId;

        var $overlay = $('#flux-hf-modal-overlay');
        $overlay.show();
        $('body').css('overflow', 'hidden');

        // Reset auth state for modal
        authorizedToken = null;
        authorizationResult = null;
        authError = null;
        isAuthorizing = false;

        hideError('modal');
        hideAuthStatus('modal');
        $('#flux-hf-modal-pay-btn').prop('disabled', true).text('Pay Now');

        if (!flux) {
            ensureAuthToken().then(function(data) {
                initSDK(data, 'flux-hf-modal');
            }).fail(function(err) {
                showError('modal', 'Failed to load payment form: ' + (err.message || err));
            });
        }

        // Close handlers
        $('.flux-hf-modal-close').off('click').on('click', closeModal);
        $overlay.off('click.fluxmodal').on('click.fluxmodal', function(e) {
            if (e.target === this) closeModal();
        });
        $(document).off('keydown.fluxmodal').on('keydown.fluxmodal', function(e) {
            if (e.key === 'Escape') closeModal();
        });

        // Pay button — just processes with pre-authorized token
        $('#flux-hf-modal-pay-btn').off('click').on('click', modalPayClicked);
    }

    function closeModal() {
        $('#flux-hf-modal-overlay').hide();
        $('body').css('overflow', '');
        $(document).off('keydown.fluxmodal');
    }

    function modalPayClicked() {
        if (!authorizedToken || isAuthorizing) return;

        var $btn = $('#flux-hf-modal-pay-btn');
        $btn.prop('disabled', true).text('Processing...');
        hideError('modal');

        $.ajax({
            url: CONFIG.ajax_url,
            type: 'POST',
            data: {
                action: 'flux_hosted_pay',
                nonce: CONFIG.pay_nonce,
                order_id: modalOrderId,
                card_token: authorizedToken,
                last_four: authorizationResult.lastFour || '',
                card_brand: authorizationResult.cardBrand || '',
            },
        }).then(function(response) {
            if (response.success) {
                window.location.href = response.data.redirect;
            } else {
                var msg = (response.data && response.data.message) || 'Payment failed';
                $btn.prop('disabled', false).text('Pay Now');
                showError('modal', msg);
            }
        }).fail(function() {
            $btn.prop('disabled', false).text('Pay Now');
            showError('modal', 'Network error. Please try again.');
        });
    }

    // =========================================================================
    // Cart Page Button Handler
    // =========================================================================

    // Match by class as well as id — some themes strip ids when re-rendering
    // the cart sidebar. Also use a capturing-phase listener at document level
    // via jQuery delegation so we run before any theme handler that might
    // try to navigate.
    $(document).on('click', '#flux-cart-checkout-btn, .flux-cart-checkout', function(e) {
        // Cart Pay Now in hosted-fields mode now navigates to the checkout
        // page (where the inline hosted-fields form lives) instead of opening
        // a modal on the cart page. Order is created normally on checkout
        // submit — no need to pre-create here.
        e.preventDefault();
        e.stopPropagation();
        var $btn = $(this);
        if ($btn.prop('disabled')) return;
        $btn.text('Loading checkout...').prop('disabled', true);
        var url = (CONFIG && CONFIG.checkout_url) || '/checkout/';
        window.location.href = url;
    });

    // =========================================================================
    // Listen for mini-cart open-modal event (from flux-paynow.js)
    // =========================================================================

    window.addEventListener('flux:open-modal', function(e) {
        var orderId = e.detail && e.detail.orderId;
        if (orderId) {
            openModal(orderId);
        }
    });

    // =========================================================================
    // Init on DOM Ready
    // =========================================================================

    $(document).ready(function() {
        if (CONFIG.is_checkout) {
            initCheckoutFlow();
        }
    });

})(jQuery);
