/**
 * AIEO Swatches — Interactivity API path.
 *
 * Hydrates into the existing DOM emitted by class-aieo-dmm-swatches-runtime.php
 * (selectors `.om-product-swatches`, `.om-variations-wrapper` — see CONTRACT.md)
 * and replaces the jQuery click-handler / variation-resolver with a vanilla
 * implementation that:
 *
 *   1. Reads variation map from `window.omSwatchSettings.cartVariations` and
 *      a per-product `data-aieo-swatch-variations` JSON blob (when the
 *      runtime renderer emits it; falls back to a `wc-ajax=aieo_swatch_get_variations`
 *      lookup keyed by product id).
 *   2. Tracks selected attributes per swatch group in the `aieo/swatches`
 *      IAPI store.
 *   3. On the parent product form's submit (single product) or on a swatch
 *      group's "Add to cart" button (archive), routes through the
 *      `aieo/cart` store's `addItem` action — which means side-cart-IAPI
 *      and sticky-atc-IAPI both auto-update without their own listeners.
 *   4. Emits `aieo:swatches:variation` whenever the resolved variation id
 *      changes (CONTRACT.md).
 *
 * Phase C-γ scope: cart-store integration is the measurable benefit. The
 * full multi-select-batch-add flow remains on jQuery for now; the IAPI
 * version targets the high-traffic single-select path.
 *
 * Loaded only when `aieo_dmm_swatches_iapi_enabled` resolves true.
 */

import { store } from '@wordpress/interactivity';

const cartStore     = store( 'aieo/cart' );
const swatchesStore = store( 'aieo/swatches' );

/* --------------------------------------------------------------------- */

function dispatch( name, detail ) {
    document.body.dispatchEvent( new CustomEvent( name, { bubbles: true, detail } ) );
}

/**
 * Read the variation map for a product — array of:
 *   { variation_id, attributes: { attribute_pa_size: 'm', ... }, in_stock, price }
 *
 * Source order:
 *   1. data-aieo-swatch-variations on the swatch root (server-localized).
 *   2. window.aieoSwatches.variations[productId] (set by future server-side hydration).
 *   3. Lazy AJAX fetch (returns []).
 */
async function loadVariations( root, productId ) {
    const inline = root.dataset.aieoSwatchVariations;
    if ( inline ) {
        try { return JSON.parse( inline ); } catch ( e ) { /* fall through */ }
    }
    const aieoSw = window.aieoSwatches || {};
    if ( aieoSw.variations && aieoSw.variations[ productId ] ) {
        return aieoSw.variations[ productId ];
    }
    // Lazy AJAX — uses the existing aieo_swatch_get_variations endpoint
    // (registered in class-aieo-dmm-swatches-ajax.php). Returns the same
    // shape WC's variation form expects.
    const cfg = window.aieoIapiConfig || {};
    const url = ( cfg.adminAjaxUrl || '/wp-admin/admin-ajax.php' )
        + '?action=aieo_swatch_get_variations&product_id=' + productId;
    try {
        const res  = await fetch( url, { method: 'GET', credentials: 'same-origin' } );
        const data = await res.json();
        if ( data && data.success && Array.isArray( data.data && data.data.variations ) ) {
            return data.data.variations;
        }
    } catch ( e ) { /* swallow */ }
    return [];
}

/**
 * Resolve a variation id from a selected-attributes map. Returns 0 when
 * the selection is incomplete or no variation matches.
 */
function resolveVariationId( variations, selected ) {
    if ( ! Array.isArray( variations ) || ! selected ) { return 0; }
    const wantKeys = Object.keys( selected );
    if ( wantKeys.length === 0 ) { return 0; }

    for ( let i = 0; i < variations.length; i++ ) {
        const v = variations[ i ];
        if ( ! v || ! v.attributes ) { continue; }
        let match = true;
        for ( let k = 0; k < wantKeys.length; k++ ) {
            const key = wantKeys[ k ];
            const want = String( selected[ key ] ).toLowerCase();
            const have = String( v.attributes[ key ] || '' ).toLowerCase();
            // WC variation rows can carry `''` to mean "any". Treat empty
            // as match-anything for that attribute.
            if ( have !== '' && have !== want ) { match = false; break; }
        }
        if ( match ) { return parseInt( v.variation_id, 10 ) || 0; }
    }
    return 0;
}

/**
 * Hydrate one swatch group root.
 */
async function hydrate( root ) {
    if ( root.dataset.aieoSwatchHydrated === '1' ) { return; }
    root.dataset.aieoSwatchHydrated = '1';

    const productId = parseInt( root.dataset.productId, 10 ) || 0;
    if ( productId <= 0 ) { return; }

    const variations = await loadVariations( root, productId );
    const state = swatchesStore.state.byProduct;
    state[ productId ] = state[ productId ] || {
        selectedAttributes:  {},
        selectedVariationId: 0,
        availableVariations: variations,
        inCartQty:           0
    };
    state[ productId ].availableVariations = variations;

    // Click handler — every option element inside .om-variations-wrapper
    // carries `data-attribute_name` (e.g. `attribute_pa_size`) and
    // `data-value`. Matches the DOM the legacy renderer emits.
    root.addEventListener( 'click', function ( ev ) {
        const opt = ev.target.closest( '[data-attribute_name][data-value]' );
        if ( ! opt ) { return; }
        ev.preventDefault();

        const attr = opt.dataset.attribute_name;
        const val  = opt.dataset.value;
        const slot = state[ productId ];
        if ( slot.selectedAttributes[ attr ] === val ) {
            // Re-click clears the selection.
            delete slot.selectedAttributes[ attr ];
        } else {
            slot.selectedAttributes[ attr ] = val;
        }

        // Visual: toggle a generic `is-selected` class within the same
        // attribute group. CSS owns the actual styling.
        const peers = root.querySelectorAll(
            '[data-attribute_name="' + CSS.escape( attr ) + '"]'
        );
        peers.forEach( function ( p ) { p.classList.remove( 'is-selected' ); } );
        if ( slot.selectedAttributes[ attr ] !== undefined ) {
            opt.classList.add( 'is-selected' );
        }

        const vid = resolveVariationId( variations, slot.selectedAttributes );
        if ( vid !== slot.selectedVariationId ) {
            slot.selectedVariationId = vid;
            dispatch( 'aieo:swatches:variation', {
                productId:    productId,
                variationId:  vid,
                attributes:   Object.assign( {}, slot.selectedAttributes )
            } );

            // Mirror the resolved variation id into the WC variation form
            // hidden input if present, so a downstream "Add to cart"
            // button submit posts the correct variation.
            const form = root.closest( 'form.cart' );
            if ( form ) {
                let vidInput = form.querySelector( 'input[name="variation_id"]' );
                if ( ! vidInput ) {
                    vidInput = document.createElement( 'input' );
                    vidInput.type = 'hidden';
                    vidInput.name = 'variation_id';
                    form.appendChild( vidInput );
                }
                vidInput.value = String( vid );
                Object.keys( slot.selectedAttributes ).forEach( function ( k ) {
                    let inp = form.querySelector( 'input[name="' + k + '"], select[name="' + k + '"]' );
                    if ( ! inp ) {
                        inp = document.createElement( 'input' );
                        inp.type = 'hidden';
                        inp.name = k;
                        form.appendChild( inp );
                    }
                    inp.value = slot.selectedAttributes[ k ];
                } );
            }
        }
    } );

    // Per-card add-to-cart button (archive page path).
    const addBtn = root.querySelector( '[data-aieo-swatch-add]' );
    if ( addBtn ) {
        addBtn.addEventListener( 'click', async function ( ev ) {
            ev.preventDefault();
            const slot = state[ productId ];
            if ( ! slot.selectedVariationId ) {
                addBtn.classList.add( 'aieo-swatch-add--needs-pick' );
                setTimeout( function () { addBtn.classList.remove( 'aieo-swatch-add--needs-pick' ); }, 800 );
                return;
            }
            addBtn.disabled = true;
            try {
                await cartStore.actions.addItem( {
                    productId:   productId,
                    variationId: slot.selectedVariationId,
                    quantity:    1,
                    variation:   slot.selectedAttributes
                } );
            } finally {
                addBtn.disabled = false;
            }
        } );
    }
}

/**
 * Mount. Run on DOMContentLoaded for any pre-rendered swatch groups, and
 * on `aieo:reco:rendered` for groups that arrive lazily.
 */
function mountAll( root ) {
    ( root || document ).querySelectorAll( '.om-product-swatches' ).forEach( hydrate );
}

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

document.body.addEventListener( 'aieo:reco:rendered', function ( ev ) {
    mountAll( ( ev.detail && ev.detail.root ) || document );
} );

/* Diagnostics */
if ( window.aieoIapiConfig && window.aieoIapiConfig.debug ) {
    /* eslint-disable no-console */
    console.info( '[AIEO IAPI] swatches module loaded' );
    /* eslint-enable no-console */
}
