/**
 * Suggestions Analytics Hook
 *
 * Provides analytics tracking for query suggestions components using
 * Analytics V3 event structure and schema/fields (event_name, event_ts,
 * correlation_id/search_id via context, and V3 top-level fields such as
 * original_query, position, section, clicked_item_id, click_type, tab_id,
 * suggestions_count, etc.). All events are sent via client.trackEvent(payload, context)
 * so the SDK can attach correlation_id, search_id, event_ts, orgcode, xstoreid.
 */
import { useCallback, useRef, useEffect } from "react";
import { trackSuggestionClicked, trackSuggestionImpression, } from "@seekora-ai/search-sdk";
import { log } from "@seekora-ai/ui-sdk-core";
import { useTrackContext } from "../components/SearchProvider";
// ============================================================================
// V4 Suggestion Clicked dual-emit (Phase 4b — SCRUM-259)
//
// useSuggestionsAnalytics already emits V3 events for the various
// suggestion-click flavours (query suggestions, recent searches, trending,
// products inside the dropdown, categories, brands). Per spec Section 5A
// event 17 all of these are ONE canonical event in V4: `Suggestion Clicked`
// with a `suggestion_type` discriminator. We dual-emit alongside V3 so
// every existing callsite gets V4 attribution for free.
//
// The V3 emission path stays unchanged for backwards compat. Future cleanup
// can retire it once V4 consumers are validated end-to-end (same migration
// strategy as the Filter Applied -> Facet Applied transition in Facets).
// ============================================================================
/**
 * Mint a UUID v4 for `suggestion_event_id`. Prefers `crypto.randomUUID()`
 * (Chrome 92+, Safari 15.4+, Firefox 95+, Node 19+ — well above our 2026
 * support floor) and falls back to a Math.random-based v4 for ancient
 * environments. Spec Section 5A event 17 requires this id to be
 * client-minted so the suggestion's downstream attribution chain can
 * reference it (Search Submitted carries `triggered_by_suggestion_id`).
 */
function mintSuggestionEventId() {
    const g = typeof globalThis !== "undefined"
        ? globalThis
        : {};
    if (g.crypto && typeof g.crypto.randomUUID === "function") {
        return g.crypto.randomUUID();
    }
    // RFC 4122 v4 fallback (xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx).
    const bytes = new Uint8Array(16);
    for (let i = 0; i < 16; i++)
        bytes[i] = Math.floor(Math.random() * 256);
    bytes[6] = (bytes[6] & 0x0f) | 0x40; // version 4
    bytes[8] = (bytes[8] & 0x3f) | 0x80; // variant 10
    const hex = Array.from(bytes, (b) => b.toString(16).padStart(2, "0"));
    return (hex.slice(0, 4).join("") +
        "-" +
        hex.slice(4, 6).join("") +
        "-" +
        hex.slice(6, 8).join("") +
        "-" +
        hex.slice(8, 10).join("") +
        "-" +
        hex.slice(10, 16).join(""));
}
// ============================================================================
// Event Names — historical V3 enum
//
// Retained as a comment-only reference. The V3 REST path was retired
// SCRUM-272; the V4 emitters in this hook stamp Jitsu-native event names
// ("Suggestion Clicked", "Suggestion Impression") via the search-sdk
// helpers. The legacy string keys below show which dropdown actions used
// to map onto V3 names if anyone needs to grep historical analytics_v2
// rows or compare V3-era dashboards.
//
//   SUGGESTION_CLICK       = "suggestions.click"
//   SUGGESTION_IMPRESSION  = "suggestions.impression"
//   PRODUCT_CLICK          = "suggestions.product_click"
//   CATEGORY_CLICK         = "suggestions.category_click"
//   BRAND_CLICK            = "suggestions.brand_click"
//   TAB_SELECT             = "suggestions.tab_select"          (no V4 equivalent)
//   RECENT_CLICK           = "suggestions.recent_click"
//   TRENDING_CLICK         = "suggestions.trending_click"
//   SEARCH_SUBMIT          = "suggestions.search_submit"
//   DROPDOWN_OPEN          = "suggestions.dropdown_open"       (no V4 equivalent)
//   DROPDOWN_CLOSE         = "suggestions.dropdown_close"      (no V4 equivalent)
//   VARIANT_SELECT         = "product.variant_select"
//   VARIANT_HOVER          = "product.variant_hover"
//   ADD_TO_CART            = "product.add_to_cart"
//   PRODUCT_IMPRESSION     = "product.impression"
//   SWATCH_CLICK           = "product.swatch_click"
// ============================================================================
// ============================================================================
// Hook Implementation
// ============================================================================
export function useSuggestionsAnalytics(options) {
    const { client, enabled = true, analyticsTags = [], impressionDebounce = 500, trackImpressions = true, trackClicks = true, context: contextOption, } = options;
    // Refs for debouncing and tracking
    const impressionTimerRef = useRef(null);
    const lastImpressionRef = useRef(null);
    const dropdownOpenTimeRef = useRef(null);
    // V4 emission target (Phase 4b — SCRUM-259). When no SearchProvider is
    // above, useTrackContext returns null and emitV4Suggestion becomes a
    // no-op — V3 path still works.
    const trackCtx = useTrackContext();
    // Cleanup on unmount
    useEffect(() => {
        return () => {
            if (impressionTimerRef.current) {
                clearTimeout(impressionTimerRef.current);
            }
        };
    }, []);
    /**
     * V4 dual-emit helper for spec event 17 (Suggestion Clicked).
     * All 5 click flavours (query/recent/trending/product/category/brand)
     * land here with the right `suggestion_type` discriminator.
     * No-op when trackCtx is null OR trackClicks=false. Never throws --
     * analytics must never break the click flow.
     */
    const emitV4SuggestionClicked = useCallback((suggestionText, position, suggestionType, queryPrefix, productFields) => {
        if (!trackCtx || !trackClicks)
            return;
        if (!suggestionText)
            return; // can't attribute an empty suggestion
        try {
            trackSuggestionClicked(trackCtx, {
                suggestion_event_id: mintSuggestionEventId(),
                suggestion_text: suggestionText,
                // Spec uses 1-indexed positions; existing V3 callers pass
                // 0-indexed. Normalize at the boundary.
                suggestion_position: position + 1,
                suggestion_type: suggestionType,
                query_prefix: queryPrefix,
                // Product-subset object attribution — only present for
                // suggestion_type="product". The SDK's track() wrapper will
                // also attempt an object_data cache lookup for any ids that
                // arrive without explicit object_data, but we prefer supplying
                // it directly from the suggestion response since suggestion
                // products may not be in the active search cache.
                ...(productFields ?? {}),
            });
        }
        catch (emitErr) {
            log.warn("useSuggestionsAnalytics: V4 emit failed", {
                suggestionText,
                suggestionType,
                error: emitErr instanceof Error ? emitErr.message : String(emitErr),
            });
        }
    }, [trackCtx, trackClicks]);
    // (SCRUM-272) The legacy V3 sendEvent helper that POSTed to
    // /api/analytics/batch was deleted in this commit. Every event surface
    // below now routes exclusively through the V4 emitters
    // (trackSuggestionClicked / trackSuggestionImpression) so /v1/b on Jitsu
    // is the single ingest path. Events without a V4 counterpart
    // (suggestions.tab_select, suggestions.dropdown_open,
    // suggestions.dropdown_close) became no-ops — the spec drops them.
    // V3-only tenants that still consumed this hook need to provision V4
    // (SearchProvider + register_jitsu) to keep receiving analytics.
    // V4 Suggestion Impression emitter (Phase 4b — SCRUM-272).
    // Mirrors emitV4SuggestionClicked: no-op when trackCtx is null OR
    // trackImpressions=false. Wires through the search-sdk
    // trackSuggestionImpression helper which routes to Jitsu /v1/b with
    // the V4 canonical event name and per-tenant orgcode/xstoreid stamps.
    const emitV4SuggestionImpression = useCallback((queryPrefix, suggestionTexts) => {
        if (!trackCtx || !trackImpressions)
            return;
        if (suggestionTexts.length === 0)
            return;
        try {
            trackSuggestionImpression(trackCtx, {
                query_prefix: queryPrefix,
                suggestion_texts: suggestionTexts,
                suggestions_count: suggestionTexts.length,
                surface: "header_search",
            });
        }
        catch (emitErr) {
            log.warn("useSuggestionsAnalytics: V4 impression emit failed", {
                queryPrefix,
                suggestionCount: suggestionTexts.length,
                error: emitErr instanceof Error ? emitErr.message : String(emitErr),
            });
        }
    }, [trackCtx, trackImpressions]);
    // Track suggestion click — V4 only. Query suggestions land as
    // suggestion_type="query"; data.query is the query_prefix.
    const trackSuggestionClick = useCallback((data) => {
        if (!trackClicks)
            return;
        emitV4SuggestionClicked(data.suggestion.query ?? "", data.position, "query", data.query);
    }, [trackClicks, emitV4SuggestionClicked]);
    // Track product click — V4 only. Fires two events:
    //   1. Object Clicked / Object Clicked Outside Search via the search-sdk
    //      client (carries object_id + search_id for funnel attribution).
    //   2. Suggestion Clicked with suggestion_type="product" so the V4
    //      suggestion-funnel cube sees the same row.
    const trackProductClick = useCallback((data) => {
        if (!trackClicks)
            return;
        const searchContext = contextOption;
        if (client) {
            const itemId = data.product.id || data.product.objectID || "";
            const pos = data.position + 1;
            const searchId = searchContext
                ?.search_id;
            const params = {
                object_ids: [itemId],
                object_positions: [pos],
            };
            const p = searchId
                ? client.trackObjectClicked({ ...params, search_id: searchId })
                : client.trackObjectClickedOutsideSearch(params);
            Promise.resolve(p).catch(() => { });
        }
        const text = data.product.title || data.product.name || data.product.objectID || "";
        const productId = data.product.id || data.product.objectID || "";
        const objectPos = data.position + 1;
        emitV4SuggestionClicked(String(text), data.position, "product", data.query, {
            object_ids: [productId],
            object_positions: [objectPos],
            object_data: [
                {
                    name: data.product.title || data.product.name || "",
                    price: data.product.price,
                    image_url: data.product.image || "",
                    url: data.product.url || "",
                },
            ],
        });
    }, [client, contextOption, trackClicks, emitV4SuggestionClicked]);
    // Track category click — V4 only. suggestion_type="category".
    const trackCategoryClick = useCallback((category, query) => {
        if (!trackClicks)
            return;
        emitV4SuggestionClicked(category.value ?? "", 0, "category", query);
    }, [trackClicks, emitV4SuggestionClicked]);
    // Track brand click — V4 only. Brand suggestions bridge into the
    // category enum since spec Section 5A only allows query/product/category.
    const trackBrandClick = useCallback((brand, query) => {
        if (!trackClicks)
            return;
        emitV4SuggestionClicked(brand.name ?? "", 0, "category", query);
    }, [trackClicks, emitV4SuggestionClicked]);
    // Track tab selection — no V4 counterpart. tabs are a UI affordance,
    // not a tracked clickstream event in the V4 schema (Section 5A enum
    // closes the door on adding new event types). Public API kept so
    // existing consumer code compiles; emission intentionally dropped.
    const trackTabSelect = useCallback((_tab, _query) => {
        /* no-op — see comment above */
    }, []);
    // Track recent search click — V4 only. Recent-row picks are still
    // query suggestions per the V4 funnel; no query_prefix because the
    // user didn't type anything before clicking.
    const trackRecentSearchClick = useCallback((search) => {
        if (!trackClicks)
            return;
        emitV4SuggestionClicked(search.query ?? "", 0, "query");
    }, [trackClicks, emitV4SuggestionClicked]);
    // Track trending click — V4 only. suggestion_type="query".
    const trackTrendingClick = useCallback((trending, position) => {
        if (!trackClicks)
            return;
        emitV4SuggestionClicked(trending.query ?? "", position, "query");
    }, [trackClicks, emitV4SuggestionClicked]);
    // Track impression (debounced)
    const trackImpression = useCallback((data) => {
        if (!trackImpressions)
            return;
        // Create a hash of the impression to avoid duplicates
        const impressionHash = `${data.query}:${data.suggestions.length}:${data.products?.length || 0}`;
        if (impressionHash === lastImpressionRef.current)
            return;
        // Clear existing timer
        if (impressionTimerRef.current) {
            clearTimeout(impressionTimerRef.current);
        }
        impressionTimerRef.current = setTimeout(() => {
            lastImpressionRef.current = impressionHash;
            emitV4SuggestionImpression(data.query, data.suggestions.slice(0, 10).map((s) => s.query));
        }, impressionDebounce);
    }, [emitV4SuggestionImpression, trackImpressions, impressionDebounce]);
    // Track search submit — V4 "Search Submitted" is emitted by
    // SearchStateManager.runSearch in @seekora-ai/ui-sdk-core, which is the
    // canonical source. This hook's wrapper is intentionally a no-op so
    // double-emission cannot happen. Public API kept for back-compat.
    const trackSearchSubmit = useCallback((_query, _fromSuggestion, _suggestion) => {
        /* no-op — see comment above */
    }, []);
    // Track dropdown open — no V4 counterpart. The V4 funnel infers
    // dropdown lifetime from the Suggestion Impression / Suggestion Clicked
    // timestamps that fire while it's open. Public API kept; emission
    // dropped. dropdownOpenTimeRef remains to support trackDropdownClose
    // duration computation should a future V4 event surface need it.
    const trackDropdownOpen = useCallback((_query) => {
        dropdownOpenTimeRef.current = Date.now();
    }, []);
    // Track dropdown close — no V4 counterpart. Same reasoning as
    // trackDropdownOpen above. Resets the open-time ref.
    const trackDropdownClose = useCallback((_query, _selectedSuggestion) => {
        dropdownOpenTimeRef.current = null;
    }, []);
    return {
        trackSuggestionClick,
        trackProductClick,
        trackCategoryClick,
        trackBrandClick,
        trackTabSelect,
        trackRecentSearchClick,
        trackTrendingClick,
        trackImpression,
        trackSearchSubmit,
        trackDropdownOpen,
        trackDropdownClose,
    };
}
export default useSuggestionsAnalytics;
