/**
 * AIEO_DMM_Variations_Gallery — frontend script.
 *
 * REWRITTEN 2026-05-04: previous implementation (lifted verbatim from
 * OM PPE) created a sibling `<div class="om-ppe-variant-gallery-{id}">`
 * for every selected variation and toggled `display:none` on the
 * original. On block-themed product pages with stacked-by-default
 * gallery layouts that left BOTH galleries visible, producing the
 * "stacked galleries" bug reported in production.
 *
 * The new implementation does NOT create sibling elements. Instead it
 * mutates the existing WC product gallery's first `<img>` src + alt
 * + zoom href in place when a variation is selected. DOM-stable — no
 * sibling can ever be created — so the bug can't recur regardless of
 * theme layout. Reads the per-variation image set from the
 * `variation_gallery_images` array that
 * `AIEO_DMM_Variations_Gallery::add_variation_gallery_data` already
 * adds to every variation's data payload (no JSON-blob handshake
 * needed; we use the same data path WC emits inline on the form).
 *
 * Public API kept for back-compat: `window.OMPPEVariationsGallery.init`
 * still exists so any quick-view module that called the old name keeps
 * working. Aliased as `window.AIEOVariationsGallery` going forward.
 *
 * @package ai-eshop-optimizer
 */

(function ($) {
    'use strict';

    // Neutralise WC core's own image-swap. WC's
    // `wc_variations_image_update` (in add-to-cart-variation.js) runs on
    // every `found_variation` and tries to match the variation image to
    // a gallery thumbnail via FlexSlider's `flexslider-click`; when no
    // thumb matches it calls `wc_variations_image_reset()` and reverts
    // to the parent image. That CLOBBERS our swap-in-place and
    // produces the "click once, see nothing; click again to deselect,
    // see image" symptom (our reset path wins on the second click only
    // because WC's handler doesn't run on `reset_data`). Replacing
    // both fns with no-ops makes our bridge the sole writer of the
    // main `<img>` src for variation events.
    if ($ && $.fn) {
        $.fn.wc_variations_image_update = function () { return this; };
        $.fn.wc_variations_image_reset  = function () { return this; };
    }

    // Module-level reset state — keyed by gallery DOM node so we can
    // restore the parent image on `reset_data` even when the form is
    // re-rendered (AIEO swatches re-bind their own `found_variation`
    // listeners after each cache hydration, which used to clobber our
    // per-form state object).
    var resetState = new WeakMap();

    function locateGallery($form) {
        var $product = $form.closest('.product');
        var $gallery = $product.length
            ? $product.find('.woocommerce-product-gallery, .wp-block-woocommerce-product-image-gallery').first()
            : $('.woocommerce-product-gallery, .wp-block-woocommerce-product-image-gallery').first();
        return $gallery.length ? $gallery : null;
    }

    function captureReset($gallery) {
        var node = $gallery.get(0);
        if (resetState.has(node)) { return; }
        var $firstImg = $gallery.find('.woocommerce-product-gallery__image').first().find('img').first();
        var $firstAnchor = $gallery.find('.woocommerce-product-gallery__image').first().find('a').first();
        resetState.set(node, {
            src:    $firstImg.attr('src') || '',
            srcset: $firstImg.attr('srcset') || '',
            href:   $firstAnchor.attr('href') || ''
        });
    }

    function pickVariationUrl(variation) {
        if (!variation) { return ''; }
        if (Array.isArray(variation.variation_gallery_images) && variation.variation_gallery_images.length) {
            var first = variation.variation_gallery_images[0];
            var url = (first && (first.url || first.full || first.src)) || '';
            if (url) { return url; }
        }
        if (variation.image) {
            return variation.image.full_src || variation.image.src || '';
        }
        return '';
    }

    var AIEOVariationsGallery = {
        debug: false,
        /**
         * Bind a global delegated listener for `found_variation` and
         * `reset_data`. We use document-level delegation (instead of
         * binding on `.variations_form` directly) because the AIEO
         * swatches script calls `wc_variation_form()` and re-initialises
         * its own `found_variation` listeners after cache hydration,
         * which can race with our document-ready bind. Delegation on
         * `document` is immune to that — events bubble up regardless of
         * when/how the form was initialised.
         */
        init: function ($context) {
            var ctx = $context && $context.length ? $context : $(document);

            ctx.find('.variations_form').each(function () {
                var $form = $(this);
                var $gallery = locateGallery($form);
                if ($gallery) { captureReset($gallery); }
            });
        }
    };

    // Document-level delegated handlers — never get unbound by other
    // scripts. The wildcard selector matches every `.variations_form`
    // on the page, current or future.
    $(document)
        .on('found_variation.aieoVariationsGallery', '.variations_form', function (event, variation) {
            var $form = $(this);
            var $gallery = locateGallery($form);
            if (!$gallery) { return; }
            captureReset($gallery);
            var url = pickVariationUrl(variation);
            if (AIEOVariationsGallery.debug) {
                console.log('[AIEO VG] found_variation', { url: url, variation: variation });
            }
            if (url) {
                swapMainImage($gallery, url);
            }
        })
        .on('reset_data.aieoVariationsGallery', '.variations_form', function () {
            var $form = $(this);
            var $gallery = locateGallery($form);
            if (!$gallery) { return; }
            var node = $gallery.get(0);
            var rs = resetState.get(node);
            if (AIEOVariationsGallery.debug) {
                console.log('[AIEO VG] reset_data', rs);
            }
            if (rs && rs.src) {
                swapMainImage($gallery, rs.src, rs.srcset, rs.href);
            }
        });

    /**
     * Swap the FIRST gallery slide's image in place. Targets:
     *   - `<img class="wp-post-image">` `src` (and clears `srcset` so
     *     responsive images don't override).
     *   - The wrapping `<a href>` (zoom-to-fullscreen URL).
     *   - `data-large_image` (PhotoSwipe / WC zoom uses this for the
     *     full-size view).
     *
     * Does NOT create a new element. Does NOT hide / show siblings.
     * Same DOM, mutated in place — the bug source removed by
     * construction.
     */
    function swapMainImage($gallery, url, restoreSrcset, restoreHref) {
        if (!url) { return; }
        var $firstSlide = $gallery.find('.woocommerce-product-gallery__image').first();
        if (!$firstSlide.length) { return; }

        var $img = $firstSlide.find('img').first();
        if ($img.length) {
            $img.attr('src', url);
            $img.attr('data-large_image', url);
            if (typeof restoreSrcset === 'string') {
                $img.attr('srcset', restoreSrcset);
            } else {
                // For variation swaps we don't have a srcset — clearing
                // it forces the browser to use `src` directly.
                $img.removeAttr('srcset');
            }
        }
        var $a = $firstSlide.find('a').first();
        if ($a.length) {
            $a.attr('href', typeof restoreHref === 'string' && restoreHref ? restoreHref : url);
        }
        // Notify any zoom plugins (WC zoom, theme custom plugins) so
        // they re-init against the new image. WC's standard custom
        // event — every gallery integration listens for it.
        try {
            $gallery.get(0).dispatchEvent(new CustomEvent('wc_gallery_changed', { bubbles: true }));
        } catch (_e) { /* IE — non-fatal */ }
    }

    // Public surface — keep the OM PPE name as an alias so any other
    // code (e.g., side-cart Quick View) that called the old global
    // continues to work without a churn pass.
    window.AIEOVariationsGallery = AIEOVariationsGallery;
    window.OMPPEVariationsGallery = AIEOVariationsGallery;

    $(function () {
        AIEOVariationsGallery.init();
    });

    // Re-init for AJAX-injected variation forms (Quick View etc.).
    $(document).on('aieo:quickview:opened', function (e, data) {
        if (data && data.$body) {
            AIEOVariationsGallery.init(data.$body);
        }
    });

})(jQuery);
