/**
 * HierarchicalMenu Component
 *
 * Displays a hierarchical menu for nested category navigation
 * Example: Electronics > Phones > iPhone
 */
import React, { useState, useMemo, useCallback, useRef, useEffect, } from "react";
import { useSearchContext } from "./SearchProvider";
import { useSearchState } from "../hooks/useSearchState";
import { clsx } from "clsx";
import { ensureSeekoraStyles } from "../styles/inject";
export const HierarchicalMenu = ({ attributes, separator = " > ", limit = 10, showMore = true, showMoreLimit = 20, renderItem, onSelect, className, style, theme: customTheme, rootPath = null, sortBy = "name", items: itemsProp, }) => {
    const { theme, stateManager } = useSearchContext();
    const { results, refinements, addRefinement, removeRefinement } = useSearchState();
    const hierarchicalTheme = customTheme || {};
    // Coerce rootPath to a safe string. Empty string means "show all roots".
    const rp = rootPath ?? "";
    const [expanded, setExpanded] = useState({});
    useEffect(() => {
        ensureSeekoraStyles();
    }, []);
    // Get hierarchical facet data from results
    const getHierarchicalData = useCallback(() => {
        if (itemsProp)
            return itemsProp;
        if (!results)
            return [];
        // Try to find hierarchical facet data in various response formats
        const facets = results
            .facets ||
            results.facet_counts ||
            {};
        // Build hierarchy from flat facet data
        const rootAttribute = attributes[0];
        const rootFacet = facets[rootAttribute] || {};
        const items = [];
        Object.entries(rootFacet).forEach(([value, count]) => {
            const isRefined = refinements.some((r) => r.field === rootAttribute && r.value === value);
            items.push({
                label: value,
                value,
                count: count,
                isRefined,
                data: getChildItems(value, 1),
            });
        });
        return items;
    }, [results, attributes, refinements, itemsProp]);
    // Get child items for a parent value
    const getChildItems = useCallback((parentValue, level) => {
        if (level >= attributes.length)
            return [];
        if (!results)
            return [];
        const facets = results
            .facets ||
            results.facet_counts ||
            {};
        const attribute = attributes[level];
        const facet = facets[attribute] || {};
        const items = [];
        Object.entries(facet).forEach(([value, count]) => {
            // Check if this item belongs to the parent
            if (value.startsWith(parentValue + separator)) {
                const label = value
                    .replace(parentValue + separator, "")
                    .split(separator)[0];
                const isRefined = refinements.some((r) => r.field === attribute && r.value === value);
                // Only add direct children
                const remainingPath = value.replace(parentValue + separator, "");
                if (!remainingPath.includes(separator)) {
                    items.push({
                        label,
                        value,
                        count: count,
                        isRefined,
                        data: getChildItems(value, level + 1),
                    });
                }
            }
        });
        return items;
    }, [results, attributes, separator, refinements]);
    // Get sorted and limited items
    const processedItems = useMemo(() => {
        let items = getHierarchicalData();
        // When rootPath is provided (non-empty), restrict display to items whose
        // value starts with that prefix. When rootPath is null/undefined (rp === ""),
        // no filtering — show all root-level items.
        if (rp !== "") {
            items = items.filter((item) => item.value?.startsWith(rp));
        }
        // Sort
        items = [...items].sort((a, b) => {
            if (sortBy === "count") {
                return (b.count || 0) - (a.count || 0);
            }
            if (sortBy === "isRefined") {
                if (a.isRefined && !b.isRefined)
                    return -1;
                if (!a.isRefined && b.isRefined)
                    return 1;
            }
            return a.label.localeCompare(b.label);
        });
        return items;
    }, [getHierarchicalData, sortBy, rp]);
    // Handle item click
    const handleItemClick = useCallback((item, level) => {
        const attribute = attributes[level] || attributes[0];
        if (item.isRefined) {
            // Remove this and all child refinements
            attributes.slice(level).forEach((attr) => {
                refinements
                    .filter((r) => r.field === attr && r.value.startsWith(item.value))
                    .forEach((r) => removeRefinement(r.field, r.value, false));
            });
            stateManager.search();
        }
        else {
            // Clear sibling refinements at this level
            refinements
                .filter((r) => r.field === attribute && r.value !== item.value)
                .forEach((r) => removeRefinement(r.field, r.value, false));
            // Add this refinement
            addRefinement(attribute, item.value, true);
        }
        if (onSelect) {
            onSelect(item.value, level);
        }
    }, [
        attributes,
        refinements,
        addRefinement,
        removeRefinement,
        stateManager,
        onSelect,
    ]);
    // Toggle show more
    const toggleShowMore = (level) => {
        setExpanded((prev) => ({ ...prev, [level]: !prev[level] }));
    };
    const containerRef = useRef(null);
    // Collect all visible treeitem elements within the container
    const getVisibleTreeItems = useCallback(() => {
        if (!containerRef.current)
            return [];
        return Array.from(containerRef.current.querySelectorAll('[role="treeitem"]'));
    }, []);
    // Keyboard navigation handler for the tree
    const handleKeyDown = useCallback((e) => {
        const items = getVisibleTreeItems();
        if (items.length === 0)
            return;
        const activeElement = document.activeElement;
        // Find the treeitem that is or contains the active element
        const currentItem = items.find((item) => item === activeElement || item.contains(activeElement));
        const currentIndex = currentItem ? items.indexOf(currentItem) : -1;
        switch (e.key) {
            case "ArrowDown": {
                e.preventDefault();
                const nextIndex = currentIndex < items.length - 1 ? currentIndex + 1 : 0;
                const button = items[nextIndex].querySelector("button");
                if (button)
                    button.focus();
                else
                    items[nextIndex].focus();
                break;
            }
            case "ArrowUp": {
                e.preventDefault();
                const prevIndex = currentIndex > 0 ? currentIndex - 1 : items.length - 1;
                const button = items[prevIndex].querySelector("button");
                if (button)
                    button.focus();
                else
                    items[prevIndex].focus();
                break;
            }
            case "ArrowRight": {
                if (!currentItem)
                    break;
                const isExpanded = currentItem.getAttribute("aria-expanded");
                if (isExpanded === "false") {
                    // Expand (select) this item
                    e.preventDefault();
                    const button = currentItem.querySelector("button");
                    if (button)
                        button.click();
                }
                else if (isExpanded === "true") {
                    // Move to first child
                    e.preventDefault();
                    const childList = currentItem.querySelector('[role="group"]');
                    if (childList) {
                        const firstChild = childList.querySelector('[role="treeitem"]');
                        if (firstChild) {
                            const button = firstChild.querySelector("button");
                            if (button)
                                button.focus();
                            else
                                firstChild.focus();
                        }
                    }
                }
                break;
            }
            case "ArrowLeft": {
                if (!currentItem)
                    break;
                const isExpanded = currentItem.getAttribute("aria-expanded");
                if (isExpanded === "true") {
                    // Collapse this item
                    e.preventDefault();
                    const button = currentItem.querySelector("button");
                    if (button)
                        button.click();
                }
                else {
                    // Move focus to parent treeitem
                    e.preventDefault();
                    const parentGroup = currentItem.closest('[role="group"]');
                    if (parentGroup) {
                        const parentItem = parentGroup.closest('[role="treeitem"]');
                        if (parentItem) {
                            const button = parentItem.querySelector(":scope > button");
                            if (button)
                                button.focus();
                            else
                                parentItem.focus();
                        }
                    }
                }
                break;
            }
            case "Enter": {
                if (!currentItem)
                    break;
                e.preventDefault();
                const button = currentItem.querySelector("button");
                if (button)
                    button.click();
                break;
            }
            default:
                break;
        }
    }, [getVisibleTreeItems]);
    // Render a level of the hierarchy
    const renderLevel = (items, level) => {
        if (!items || items.length === 0)
            return null;
        const isLevelExpanded = expanded[level] || false;
        const displayLimit = isLevelExpanded ? showMoreLimit : limit;
        const displayItems = items.slice(0, displayLimit);
        const hasMore = items.length > displayLimit;
        const isNested = level > 0;
        return (React.createElement("ul", { role: level === 0 ? "tree" : "group", className: clsx("seekora-hierarchical-menu__level", hierarchicalTheme.list, isNested && "seekora-hierarchical-menu__level--nested"), ...(isNested
                ? {
                    style: { "--seekora-hmenu-depth": level },
                }
                : {}) },
            displayItems.map((item) => (React.createElement("li", { key: item.value, role: "treeitem", ...(item.data && item.data.length > 0
                    ? { "aria-expanded": !!item.isRefined }
                    : {}), className: clsx("seekora-hierarchical-menu__item", hierarchicalTheme.item, item.isRefined && "seekora-hierarchical-menu__item--active", item.isRefined && hierarchicalTheme.itemSelected, item.isRefined &&
                    item.data &&
                    item.data.length > 0 &&
                    "seekora-hierarchical-menu__item--expanded", item.data && item.data.length > 0 && hierarchicalTheme.itemParent) }, renderItem ? (renderItem(item, level)) : (React.createElement(React.Fragment, null,
                React.createElement("button", { type: "button", onClick: () => handleItemClick(item, level), className: clsx("seekora-hierarchical-menu__item-btn", hierarchicalTheme.link) },
                    React.createElement("span", { className: clsx("seekora-hierarchical-menu__label", hierarchicalTheme.label) }, item.label),
                    item.count !== undefined && (React.createElement("span", { className: clsx("seekora-hierarchical-menu__count", hierarchicalTheme.count) }, item.count))),
                item.isRefined &&
                    item.data &&
                    item.data.length > 0 &&
                    renderLevel(item.data, level + 1)))))),
            showMore && hasMore && (React.createElement("li", null,
                React.createElement("button", { type: "button", onClick: () => toggleShowMore(level), className: clsx("seekora-hierarchical-menu__show-more", hierarchicalTheme.showMore) }, isLevelExpanded
                    ? "Show less"
                    : `Show ${items.length - displayLimit} more`)))));
    };
    if (processedItems.length === 0) {
        return null;
    }
    return (React.createElement("div", { ref: containerRef, className: clsx("seekora-hierarchical-menu", hierarchicalTheme.root, className), style: style, tabIndex: 0, onKeyDown: handleKeyDown }, renderLevel(processedItems, 0)));
};
