/**
 * AIEO Address Autocomplete — block-checkout port.
 *
 * The legacy `aieo-address-autocomplete.js` targets the shortcode
 * checkout's `#billing_address_search` / `#shipping_address_search`
 * inputs and populates `#billing_address_1`, `#billing_city`,
 * `#billing_postcode` etc. directly via `.val()`.
 *
 * Block checkout uses React-managed `<input>` elements with different
 * IDs, and direct value writes don't propagate to redux state. This
 * file:
 *
 *   1. Watches for the block address inputs to mount in the DOM.
 *   2. Attaches Google Places autocomplete to each `address_1` input.
 *   3. On place selection, dispatches `setShippingAddress` /
 *      `setBillingAddress` actions on the `wc/store/cart` data store
 *      with the parsed address components — that triggers WC's normal
 *      cart-recalc flow (so shipping rates update for the new postcode).
 *
 * Loaded only when the legacy module config (`omAI` global) is present
 * — that global is localised by AIEO_DMM_Address_Autocomplete and
 * carries the Google API key, country, and language.
 *
 * @package ai-eshop-optimizer
 * @since 5.2
 */
(function ($) {
    'use strict';

    if (typeof window === 'undefined' || !window.omAI || !window.omAI.api_key) { return; }

    var attached = { shipping: false, billing: false };

    function waitForGoogle(cb) {
        var attempts = 0;
        var iv = setInterval(function () {
            attempts++;
            if (typeof google !== 'undefined' && google.maps && google.maps.places) {
                clearInterval(iv);
                cb();
            } else if (attempts > 80) { // ~20s
                clearInterval(iv);
                if (window.console) { console.warn('[AIEO] Google Places API did not load'); }
            }
        }, 250);
    }

    /**
     * Find a block address input by its semantic suffix. Block IDs look
     * like `shipping-address_1`, `billing-address_1`, etc. The wrapper
     * we eventually attach Places to is the input itself.
     */
    function findBlockInput(group, suffix) {
        return document.querySelector(
            'input[id="' + group + '-' + suffix + '"], ' +
            'input[id$="-' + group + '-' + suffix + '"]'
        );
    }

    function parseAddressComponents(place) {
        var out = {
            address_1: '',
            city: '',
            postcode: '',
            country: '',
            state: '',
        };
        if (!place || !place.address_components) { return out; }

        var streetNumber = '', route = '';
        place.address_components.forEach(function (c) {
            var t = c.types;
            if (t.indexOf('street_number') !== -1) { streetNumber = c.long_name; }
            else if (t.indexOf('route') !== -1) { route = c.long_name; }
            else if (t.indexOf('locality') !== -1 ||
                     t.indexOf('postal_town') !== -1) { out.city = c.long_name; }
            else if (t.indexOf('administrative_area_level_1') !== -1) { out.state = c.short_name; }
            else if (t.indexOf('postal_code') !== -1) { out.postcode = c.long_name; }
            else if (t.indexOf('country') !== -1) { out.country = c.short_name; }
        });
        // Greek convention: route first, then street number.
        out.address_1 = (route + (streetNumber ? ' ' + streetNumber : '')).trim();
        if (!out.address_1 && place.formatted_address) {
            out.address_1 = place.formatted_address.split(',')[0].trim();
        }
        return out;
    }

    /**
     * Push the parsed address into the wc/store/cart redux store via
     * the canonical setShippingAddress / setBillingAddress actions.
     * That triggers WC's update-customer flow which:
     *   - persists the address server-side
     *   - re-renders the address fields with the new values
     *   - recomputes shipping rates for the new postcode
     */
    function pushAddressToStore(group, parsed) {
        if (typeof wp === 'undefined' || !wp.data || !wp.data.dispatch) { return; }
        try {
            var dispatch = wp.data.dispatch('wc/store/cart');
            var select   = wp.data.select('wc/store/cart');
            if (!dispatch || !select) { return; }

            var customer = select.getCustomerData();
            var current  = (group === 'billing') ? customer.billingAddress : customer.shippingAddress;
            var next = Object.assign({}, current, {
                address_1: parsed.address_1 || current.address_1,
                city:      parsed.city      || current.city,
                postcode:  parsed.postcode  || current.postcode,
            });
            // Country / state — only override when Google returned a value
            // we trust (avoids wiping a manually-typed entry).
            if (parsed.country)  { next.country = parsed.country; }
            if (parsed.state)    { next.state   = parsed.state; }

            if (group === 'billing' && typeof dispatch.setBillingAddress === 'function') {
                dispatch.setBillingAddress(next);
            } else if (typeof dispatch.setShippingAddress === 'function') {
                dispatch.setShippingAddress(next);
            }
            if (window.console) {
                console.log('[AIEO] address autocomplete -> ' + group, next);
            }
        } catch (e) {
            if (window.console) { console.warn('[AIEO] pushAddressToStore failed', e); }
        }
    }

    function attachToInput(group) {
        if (attached[group]) { return; }
        var input = findBlockInput(group, 'address_1');
        if (!input) { return; }
        // Skip if Google's autocomplete dropdown is already attached
        // (each Autocomplete sets a `_autocomplete` property).
        if (input.dataset.aieoAcAttached) { return; }
        input.dataset.aieoAcAttached = '1';
        attached[group] = true;

        var opts = {
            types: ['address'],
            fields: ['address_components', 'formatted_address'],
        };
        if (window.omAI.country) {
            opts.componentRestrictions = { country: window.omAI.country };
        }

        var ac = new google.maps.places.Autocomplete(input, opts);
        ac.addListener('place_changed', function () {
            var place = ac.getPlace();
            var parsed = parseAddressComponents(place);
            pushAddressToStore(group, parsed);
        });
    }

    function pollAndAttach() {
        attachToInput('shipping');
        attachToInput('billing');
    }

    function start() {
        waitForGoogle(function () {
            // Initial attempt
            pollAndAttach();
            // Block UI mounts asynchronously and may re-render — keep
            // re-attempting (cheaply) for a while.
            var attempts = 0;
            var iv = setInterval(function () {
                attempts++;
                pollAndAttach();
                if (attempts > 30 || (attached.shipping && attached.billing)) {
                    clearInterval(iv);
                }
            }, 500);

            // Re-attach if the React tree replaces the inputs (e.g.,
            // after a customer-data update). Guarded by attached flags
            // and the input's data-aieo-ac-attached attribute so it
            // doesn't double-bind.
            var observer = new MutationObserver(function () {
                if (!attached.shipping) { attachToInput('shipping'); }
                if (!attached.billing)  { attachToInput('billing'); }
                // If a previously-attached input was removed and a new
                // one mounted, the dataset attr is gone too — reset and
                // re-attach.
                ['shipping', 'billing'].forEach(function (group) {
                    if (attached[group]) {
                        var input = findBlockInput(group, 'address_1');
                        if (!input || !input.dataset.aieoAcAttached) {
                            attached[group] = false;
                            attachToInput(group);
                        }
                    }
                });
            });
            if (document.body) {
                observer.observe(document.body, { childList: true, subtree: true });
            }
        });
    }

    if (document.readyState === 'loading') {
        document.addEventListener('DOMContentLoaded', start);
    } else {
        start();
    }
})(typeof jQuery !== 'undefined' ? jQuery : function(){});
