/**
 * AIEO Checkout Block Extensions
 *
 * Client-side polish for the WC Cart/Checkout block migration:
 *
 *   1. Conditional invoice fields — VAT, IRS, and "Επάγγελμα /
 *      Δραστηριότητα" are only relevant when the customer has ticked
 *      "Θέλω τιμολόγιο". By default they're hidden; the toggle reveals
 *      them and marks them required.
 *
 *   2. Side-cart → block-checkout/cart sync — when the side cart's own
 *      AJAX modifies WC()->cart server-side, this hook (called from
 *      aieo-side-cart.js) does a fresh `apiFetch` of the Store API and
 *      pushes it into the wc/store/cart data store via receiveCart().
 *      That way the React Cart and Checkout blocks see the new data
 *      immediately instead of waiting for the next user interaction.
 *
 * Loaded only on /cart and /checkout pages (the WC blocks render
 * surfaces). Cheap on other pages — bails early if `wp.data` is absent
 * or the wc/store/cart store isn't registered.
 *
 * @package ai-eshop-optimizer
 * @since 5.2
 */
(function () {
    'use strict';

    if (typeof window === 'undefined') { return; }

    // ------------------------------------------------------------------
    // 1. Conditional invoice fields
    // ------------------------------------------------------------------
    // The Additional Checkout Fields API generates IDs/names from the
    // `aieo/<key>` registration. Different WC versions sanitise the
    // slash differently — sometimes `aieo-wants_invoice`, sometimes
    // `aieo/wants_invoice` (literal), sometimes `aieo-wants-invoice`.
    // Selector matches all forms via attribute-contains (`*=`) on
    // both `id` and `name`, AND we always queryAll (the same field is
    // rendered in BOTH shipping and billing forms when location='address').
    var INVOICE_KEY = 'wants_invoice';
    var DEPENDENT_KEYS = ['billing_vat', 'billing_irs', 'billing_store'];

    /**
     * Find every input/select/textarea on the page whose id OR name
     * attribute contains `aieo` AND the field key. Covers all the
     * sanitisation variants WC has used across versions, AND collects
     * BOTH shipping-form and billing-form copies of the same field.
     */
    function findAllFieldsByKey(key) {
        var sel = [
            'input[id*="aieo"][id*="' + key + '"]',
            'input[name*="aieo"][name*="' + key + '"]',
            'select[id*="aieo"][id*="' + key + '"]',
            'select[name*="aieo"][name*="' + key + '"]',
            'textarea[id*="aieo"][id*="' + key + '"]',
            'textarea[name*="aieo"][name*="' + key + '"]'
        ].join(',');
        var nodes = document.querySelectorAll(sel);
        var out = [];
        for (var i = 0; i < nodes.length; i++) { out.push(nodes[i]); }
        return out;
    }

    function findWrapper(input) {
        return input.closest(
            '.wc-block-components-text-input, ' +
            '.wc-block-components-checkbox, ' +
            '.wc-block-components-address-form__field, ' +
            '.wc-block-components-validated-text-input, ' +
            '[class*="-fields__wrapper"]'
        ) || input.parentElement || input;
    }

    function isToggleChecked() {
        var toggles = findAllFieldsByKey(INVOICE_KEY);
        for (var i = 0; i < toggles.length; i++) {
            if (toggles[i].type === 'checkbox' && toggles[i].checked) { return true; }
        }
        return false;
    }

    /**
     * Find WC core's billing_company / shipping_company inputs. They
     * use plain `name="billing_company"` / `name="shipping_company"`
     * (no `aieo` prefix, no slash) so we match by name directly.
     */
    function findCompanyFields() {
        var nodes = document.querySelectorAll('input[name="billing_company"], input[name="shipping_company"], input[name="company"], input[id*="company"]');
        var out = [];
        for (var i = 0; i < nodes.length; i++) {
            var n = nodes[i];
            // Filter out our `aieo/billing_*` inputs that happened to
            // contain "company" in some other context (defensive).
            if ((n.id && n.id.indexOf('aieo') !== -1) ||
                (n.name && n.name.indexOf('aieo') !== -1)) { continue; }
            out.push(n);
        }
        return out;
    }

    function applyInvoiceVisibility() {
        var wantsInvoice = isToggleChecked();
        DEPENDENT_KEYS.forEach(function (key) {
            var inputs = findAllFieldsByKey(key);
            inputs.forEach(function (input) {
                var wrap = findWrapper(input);
                wrap.style.display = wantsInvoice ? '' : 'none';
                if (wantsInvoice) { input.setAttribute('required', 'required'); }
                else { input.removeAttribute('required'); }
            });
        });

        // Optional: tie the WC core `billing_company` field into the
        // same toggle. Activated by the operator via the "Show
        // company field only when invoice requested" setting in the
        // Checkout Layout module — surfaces as
        // `window.aieoCheckoutLayout.companyConditional === true`.
        var cfg = window.aieoCheckoutLayout || {};
        if (cfg.companyConditional) {
            // Add a body class so the CSS rule shows the company
            // field. We use the class because adding inline styles to
            // the wrapper fights the !important from the CSS.
            var bodyCls = document.body && document.body.classList;
            if (bodyCls) {
                if (wantsInvoice) { bodyCls.add('aieo-checkout-show-company'); }
                else              { bodyCls.remove('aieo-checkout-show-company'); }
            }
            // Also flip the required attribute on the actual input so
            // the form validates B2B customers properly.
            findCompanyFields().forEach(function (input) {
                if (wantsInvoice) { input.setAttribute('required', 'required'); }
                else { input.removeAttribute('required'); }
            });
        }
    }

    function attachInvoiceHandler() {
        var toggles = findAllFieldsByKey(INVOICE_KEY);
        if (!toggles.length) { return false; }
        toggles.forEach(function (toggle) {
            if (toggle.dataset.aieoInvoiceBound) { return; }
            toggle.dataset.aieoInvoiceBound = '1';
            toggle.addEventListener('change', applyInvoiceVisibility);
        });
        applyInvoiceVisibility();
        return true;
    }

    // The block UI mounts asynchronously. Poll briefly until the toggle
    // exists, then bind. Also re-bind on subtree changes so a re-render
    // (after address change, etc.) doesn't lose our handler.
    function pollForInvoiceToggle() {
        var attempts = 0;
        var max = 40; // ~10 seconds at 250ms
        var iv = setInterval(function () {
            attempts++;
            if (attachInvoiceHandler() || attempts >= max) {
                clearInterval(iv);
            }
        }, 250);
    }

    if (document.readyState === 'loading') {
        document.addEventListener('DOMContentLoaded', pollForInvoiceToggle);
    } else {
        pollForInvoiceToggle();
    }

    // Watch for block re-renders (the React tree replaces DOM nodes).
    var observer = new MutationObserver(function () {
        attachInvoiceHandler();
        applyInvoiceVisibility();
    });
    if (document.body) {
        observer.observe(document.body, { childList: true, subtree: true });
    }

    // ------------------------------------------------------------------
    // 2. Imperative cart-data refresh helper for the side cart
    // ------------------------------------------------------------------
    /**
     * Force the WC blocks cart store to fetch fresh data and push it
     * into the React store. Called by aieo-side-cart.js after a
     * server-side cart modification (qty +/-, remove). More reliable
     * than `invalidateResolutionForStoreSelector` alone because it
     * doesn't wait for a UI tick to refetch — the apiFetch is
     * synchronous and the receiveCart() write triggers an immediate
     * re-render.
     */
    window.aieoForceCartRefresh = function () {
        // Silent no-op when wp.data isn't loaded — expected on PDPs,
        // shop archives, anywhere outside block-checkout. The
        // side-cart calls this unconditionally on every cart change
        // (for the rare case of a block-checkout-aware page); logging
        // here would spam the console on every cart action elsewhere.
        if (typeof wp === 'undefined' || !wp.data) { return; }
        try {
            var dispatch = wp.data.dispatch('wc/store/cart');
            // Same reasoning — block-checkout cart store may not be
            // registered on non-checkout pages. Silent skip.
            if (!dispatch) { return; }

            // CRITICAL: do NOT call `setShippingAddress` / `setBillingAddress`
            // here. Those actions OVERWRITE the customer state with
            // whatever is currently in redux — which is the LAST COMMITTED
            // value, not the value the customer is currently typing.
            // Calling them mid-keystroke wipes the user's in-progress
            // input (the "addresses are disappearing" symptom).
            //
            // CRITICAL: do NOT rely on `applyExtensionCartUpdate` either.
            // It only does anything when an `extensionCartUpdate`
            // callback is registered server-side for the namespace
            // (via `ExtendSchema::register_update_callback`). We don't
            // register one for `aieo_table_rate`, so the dispatch is a
            // silent no-op and the React tree never refetches. Side
            // cart and block checkout drift apart (qty=2 in side cart,
            // qty=1 in checkout summary).
            //
            // Primary path: invalidate the cart-data selector
            // resolution (so any subscriber re-resolves) AND directly
            // apiFetch the cart + write it back via `receiveCart`.
            // That writes the fresh server state into redux WITHOUT
            // touching address inputs and triggers an immediate
            // re-render of the line items, totals, and shipping rates.

            if (wp.apiFetch && typeof dispatch.receiveCart === 'function') {
                if (typeof dispatch.invalidateResolutionForStoreSelector === 'function') {
                    dispatch.invalidateResolutionForStoreSelector('getCartData');
                    dispatch.invalidateResolutionForStoreSelector('getCartTotals');
                }
                wp.apiFetch({ path: '/wc/store/v1/cart' }).then(function (cartData) {
                    dispatch.receiveCart(cartData);
                    if (window.console) { console.log('[AIEO] forceCartRefresh via apiFetch+receiveCart'); }
                }).catch(function (err) {
                    if (window.console) { console.log('[AIEO] forceCartRefresh apiFetch failed', err); }
                });
                return;
            }

            // Fallback: experimental updater for older WC blocks
            // versions where `apiFetch` / `receiveCart` aren't exposed.
            if (typeof dispatch.__experimentalUpdateCart === 'function') {
                dispatch.__experimentalUpdateCart();
                if (window.console) { console.log('[AIEO] forceCartRefresh via __experimentalUpdateCart fallback'); }
            }
        } catch (e) {
            if (window.console) { console.log('[AIEO] forceCartRefresh threw', e); }
        }
    };
})();
