/**
 * useProductAnalytics — analytics event binding hook for custom components.
 *
 * Returns event handler props ready to spread onto any element, plus
 * imperative tracking methods. Phase 2b V4 pivot (SCRUM-259) rewires
 * the impression and click side-effects to go through the V4 batched
 * buffers from `<BufferProvider>` rather than emit per-card events.
 *
 * The legacy V3 `client.trackClick(itemId, position, context)` and the
 * hand-rolled `product.impression` / `product.click` events have been
 * removed — the new producer surface is array-shaped and the only
 * supported click helper is `trackObjectClicked({ object_ids: [...] })`,
 * accumulated by the click buffer.
 *
 * Variant select / add-to-cart / custom-event handlers retain their
 * existing `client.trackEvent(...)` payload shape because those events
 * are still single-payload (not batched). They are unchanged from
 * Phase 4c.
 */
import { useCallback, useRef, useEffect } from "react";
import { log } from "@seekora-ai/ui-sdk-core";
import { useSearchImpressionBuffer } from "./useSearchImpressionBuffer";
import { useObjectClickedBuffer } from "./useObjectClickedBuffer";
import { useObjectViewedBuffer } from "./useObjectViewedBuffer";
import { useTrackContext } from "../components/SearchProvider";
const SEARCH_ATTRIBUTED = new Set([
    "results_page",
    "dropdown",
]);
export function useProductAnalytics({ client, product, position = 0, section, tabId, query, context, enabled = true, searchId, surface = "results_page", }) {
    const impressionTrackedRef = useRef(false);
    const observerRef = useRef(null);
    const elementRef = useRef(null);
    const productId = product.id || product.objectID || "";
    const trackCtx = useTrackContext();
    const impressionBuffer = useSearchImpressionBuffer();
    const clickBuffer = useObjectClickedBuffer();
    const viewedBuffer = useObjectViewedBuffer();
    const isSearchAttributed = SEARCH_ATTRIBUTED.has(surface);
    const sendEvent = useCallback(async (eventName, metadata) => {
        if (!enabled || !client)
            return;
        try {
            await client.trackEvent?.({
                event_name: eventName,
                metadata: {
                    product_id: productId,
                    product_title: product.title || product.name,
                    product_price: product.price,
                    position,
                    section,
                    tab_id: tabId,
                    original_query: query,
                    timestamp: Date.now(),
                    source: "product_analytics",
                    ...metadata,
                },
            }, context);
            log.verbose(`ProductAnalytics: ${eventName}`, metadata);
        }
        catch (error) {
            log.warn(`Failed to track ${eventName}`, { error });
        }
    }, [
        client,
        enabled,
        productId,
        product,
        position,
        section,
        tabId,
        query,
        context,
    ]);
    // Build the per-card objectData payload threaded into the parallel
    // `objectData[]` array on the batched event. Title / price / SKU give
    // downstream queries enough to filter without re-joining the catalog.
    const buildObjectData = useCallback(() => ({
        object_type: "product",
        name: product.title || product.name,
        price: product.price,
        ...(product.sku
            ? { sku: product.sku }
            : {}),
        ...(section ? { section } : {}),
    }), [product, section]);
    // Imperative click recorder — routes into the search-attributed or
    // outside-search bucket of the click buffer based on `surface`.
    const trackClick = useCallback(() => {
        if (!enabled || !productId || !trackCtx)
            return;
        try {
            const data = buildObjectData();
            const onePosition = position + 1; // 1-indexed per Algolia
            if (isSearchAttributed) {
                if (!searchId)
                    return;
                clickBuffer.record(productId, onePosition, searchId, data, surface);
            }
            else {
                clickBuffer.recordOutsideSearch(productId, onePosition, data, surface);
            }
        }
        catch (err) {
            log.warn("useProductAnalytics: click record failed", {
                error: err instanceof Error ? err.message : String(err),
            });
        }
    }, [
        enabled,
        productId,
        trackCtx,
        isSearchAttributed,
        searchId,
        position,
        surface,
        clickBuffer,
        buildObjectData,
    ]);
    const trackVariantSelect = useCallback((optionName, value) => {
        sendEvent("product.variant_select", {
            option_name: optionName,
            option_value: value,
        });
    }, [sendEvent]);
    const trackAddToCart = useCallback((variant) => {
        sendEvent("product.add_to_cart", {
            variant_id: variant?.id,
            variant_sku: variant?.sku,
            variant_title: variant?.title,
            variant_price: variant?.price,
        });
    }, [sendEvent]);
    const trackCustomEvent = useCallback((eventName, metadata) => {
        sendEvent(eventName, metadata ?? {});
    }, [sendEvent]);
    // Impression tracking via IntersectionObserver — pushes into the
    // batched buffer (impression for search-attributed; viewed for the
    // rest). Once per card per session via `impressionTrackedRef`.
    const impressionRef = useCallback((node) => {
        if (observerRef.current) {
            observerRef.current.disconnect();
            observerRef.current = null;
        }
        elementRef.current = node;
        if (!node || !enabled || impressionTrackedRef.current)
            return;
        if (!trackCtx)
            return;
        if (typeof IntersectionObserver === "undefined")
            return;
        observerRef.current = new IntersectionObserver((entries) => {
            for (const entry of entries) {
                if (entry.isIntersecting && !impressionTrackedRef.current) {
                    impressionTrackedRef.current = true;
                    try {
                        const data = buildObjectData();
                        const onePosition = position + 1;
                        if (isSearchAttributed) {
                            if (searchId) {
                                impressionBuffer.record(productId, onePosition, searchId, data, surface);
                            }
                        }
                        else {
                            viewedBuffer.record(productId, onePosition, data, surface);
                        }
                    }
                    catch {
                        /* swallow */
                    }
                    observerRef.current?.disconnect();
                }
            }
        }, { threshold: 0.5 });
        observerRef.current.observe(node);
    }, [
        enabled,
        trackCtx,
        isSearchAttributed,
        productId,
        position,
        surface,
        searchId,
        impressionBuffer,
        viewedBuffer,
        buildObjectData,
    ]);
    // Cleanup on unmount
    useEffect(() => {
        return () => {
            observerRef.current?.disconnect();
        };
    }, []);
    const clickProps = {
        onClick: () => trackClick(),
        "data-seekora-product-id": productId,
        "data-seekora-position": position,
    };
    const variantSelectProps = (optionName, value) => ({
        onClick: () => trackVariantSelect(optionName, value),
        "data-seekora-variant-option": optionName,
        "data-seekora-variant-value": value,
    });
    const addToCartProps = (variant) => ({
        onClick: () => trackAddToCart(variant),
        "data-seekora-action": "add-to-cart",
    });
    return {
        clickProps,
        variantSelectProps,
        addToCartProps,
        impressionRef,
        trackClick,
        trackVariantSelect,
        trackAddToCart,
        trackCustomEvent,
    };
}
