/**
 * @license MIT
 * author: Cube Dev Team
 * @cube-dev/ui-kit v0.0.0-canary-9f40d0e
 * Released under the MIT license.
 */

import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
import { Children, cloneElement, isValidElement, useEffect, useLayoutEffect, useMemo, useRef, useState, } from 'react';
import { useDraggableItem, useFocus, useFocusVisible, useHover, useTab, } from 'react-aria';
import { useEvent } from '../../../_internal/hooks/index.js';
import { CloseIcon, MoreIcon } from '../../../icons/index.js';
import { mergeProps } from '../../../utils/react/index.js';
import { ItemAction } from '../../actions/ItemAction/index.js';
import { ItemActionProvider } from '../../actions/ItemActionContext.js';
import { Menu, MenuTrigger } from '../../actions/Menu/index.js';
import { useContextMenu } from '../../actions/use-context-menu.js';
import { EditableTitle } from './EditableTitle.js';
import { TabContainer, TabElement } from './styled.js';
import { TabDropIndicator } from './TabDropIndicator.js';
import { useTabsContext } from './TabsContext.js';
import { RADIO_SIZE_MAP } from './types.js';
// =============================================================================
// Event handlers for actions to prevent event propagation to tab button
// =============================================================================
const ACTIONS_EVENT_HANDLERS = {
    onClick: (e) => e.stopPropagation(),
    onPointerDown: (e) => e.stopPropagation(),
    onPointerUp: (e) => e.stopPropagation(),
    onMouseDown: (e) => e.stopPropagation(),
    onMouseUp: (e) => e.stopPropagation(),
    onKeyDown: (e) => {
        if (e.key === 'Enter' || e.key === ' ') {
            e.stopPropagation();
        }
    },
};
/**
 * Extracts the raw key from a React element, stripping the ".$" prefix
 * that React adds via Children.map/toArray.
 */
function getRawKey(element) {
    if (element.key == null)
        return null;
    const keyStr = String(element.key);
    return keyStr.startsWith('.$') ? keyStr.slice(2) : keyStr;
}
/**
 * Process menu items for predefined action keys (rename, delete).
 * Auto-adds labels and disables items when requirements aren't met.
 */
function processMenuItems(children, effectiveIsEditable, isDeletable) {
    return Children.toArray(children).map((child) => {
        if (!isValidElement(child))
            return child;
        const childKey = getRawKey(child);
        const childProps = child.props;
        // Handle predefined action keys
        if (childKey === 'rename') {
            return cloneElement(child, {
                children: childProps.children ?? 'Rename',
                isDisabled: childProps.isDisabled ?? !effectiveIsEditable,
            });
        }
        if (childKey === 'delete') {
            return cloneElement(child, {
                children: childProps.children ?? 'Delete',
                theme: childProps.theme ?? 'danger',
                isDisabled: childProps.isDisabled ?? !isDeletable,
            });
        }
        // Recursively process Menu.Section children
        if (childProps.children && typeof childProps.children !== 'string') {
            return cloneElement(child, {
                children: processMenuItems(childProps.children, effectiveIsEditable, isDeletable),
            });
        }
        return child;
    });
}
/**
 * Check if menu children is empty (null, undefined, or empty fragment)
 */
function isMenuEmpty(menu) {
    if (menu === null || menu === undefined)
        return true;
    const children = Children.toArray(menu);
    return children.length === 0;
}
// =============================================================================
// TabButton Component
// =============================================================================
/**
 * Individual tab button component.
 *
 * Uses TabsContext to access shared props, dramatically reducing prop drilling.
 * Handles:
 * - Tab selection and keyboard navigation
 * - Inline title editing
 * - Menu and context menu
 * - Drag-and-drop reordering
 * - Focus and hover states
 */
export function TabButton({ item, tabData, isLastTab }) {
    // Get shared context
    const { state, type, size, showActionsOnHover: parentShowActionsOnHover, isEditable: parentIsEditable, menu: parentMenu, menuTriggerProps: parentMenuTriggerProps, menuProps: parentMenuProps, contextMenu: parentContextMenu, onAction: parentOnAction, onDelete, dragState, dropState, editingKey, editValue, setEditValue, startEditing, submitEditing, cancelEditing, } = useTabsContext();
    const ref = useRef(null);
    const containerRef = useRef(null);
    const actionsRef = useRef(null);
    const { tabProps } = useTab({ key: item.key }, state, ref);
    // Measure actions width for proper space allocation in Item
    const [actionsWidth, setActionsWidth] = useState(0);
    // Drag-and-drop support - only enable when both states are provided
    const isDraggable = !!dragState && !!dropState;
    // useDraggableItem must be called unconditionally (Rules of Hooks)
    // When dragState is undefined, we pass a minimal mock state to satisfy the hook
    const mockDragState = useMemo(() => ({
        collection: state.collection,
        selectionManager: state.selectionManager,
        isDragging: () => false,
        getKeysForDrag: () => new Set(),
        isDisabled: false,
        startDrag: () => { },
        endDrag: () => { },
    }), [state.collection, state.selectionManager]);
    const dragResult = useDraggableItem({ key: item.key }, dragState ?? mockDragState);
    const effectiveDragProps = isDraggable ? dragResult.dragProps : {};
    const isDragging = isDraggable && dragResult.isDragging;
    // Controlled state for menu trigger (enables keyboard opening with Shift+F10)
    const [isMenuOpen, setIsMenuOpen] = useState(false);
    // Hover, focus, and focus-visible state handling
    const { hoverProps, isHovered } = useHover({});
    const [isFocused, setIsFocused] = useState(false);
    const { focusProps } = useFocus({ onFocusChange: setIsFocused });
    const { isFocusVisible } = useFocusVisible();
    // Suppress focus-visible when restoring focus after editing
    const [suppressFocusVisible, setSuppressFocusVisible] = useState(false);
    const effectiveFocusVisible = isFocusVisible && !suppressFocusVisible;
    const isActive = state.selectedKey === item.key;
    const isDisabled = state.disabledKeys.has(item.key);
    const isDeletable = !!onDelete;
    const isEditing = editingKey === item.key;
    // Compute effective values - Tab-level overrides Tabs-level
    const effectiveIsEditable = tabData.isEditable ?? parentIsEditable ?? false;
    const effectiveMenu = tabData.menu === null ? null : tabData.menu ?? parentMenu;
    const effectiveMenuTriggerProps = {
        ...parentMenuTriggerProps,
        ...tabData.menuTriggerProps,
    };
    const effectiveMenuProps = {
        ...parentMenuProps,
        ...tabData.menuProps,
    };
    const effectiveContextMenu = tabData.contextMenu ?? parentContextMenu ?? false;
    const effectiveType = tabData.type ?? type ?? 'default';
    // Delete button shown only if onDelete is set AND no menu
    const showDeleteButton = isDeletable && isMenuEmpty(effectiveMenu);
    // Process menu items for auto-labels and disabled states
    const processedMenu = effectiveMenu && !isMenuEmpty(effectiveMenu)
        ? processMenuItems(effectiveMenu, effectiveIsEditable, isDeletable)
        : null;
    const handleDelete = useEvent(() => {
        onDelete?.(item.key);
    });
    const handleStartEditing = useEvent(() => {
        if (!effectiveIsEditable || isDisabled)
            return;
        const titleText = typeof tabData.title === 'string' ? tabData.title : String(item.key);
        startEditing(item.key, titleText);
    });
    const handleSubmitEditing = useEvent(() => {
        submitEditing(item.key, editValue, tabData.onTitleChange);
        // Suppress focus-visible and restore focus to the tab button after editing
        setSuppressFocusVisible(true);
        requestAnimationFrame(() => {
            ref.current?.focus();
        });
    });
    const handleCancelEditing = useEvent(() => {
        cancelEditing();
        // Suppress focus-visible and restore focus to the tab button after editing
        setSuppressFocusVisible(true);
        requestAnimationFrame(() => {
            ref.current?.focus();
        });
    });
    const handleEditValueChange = useEvent((value) => {
        setEditValue(value);
    });
    // Handle menu actions - predefined actions first, then callbacks
    const handleMenuAction = useEvent((action) => {
        // Strip the ".$" prefix that React adds via Children.toArray/map
        const actionStr = String(action);
        const normalizedAction = actionStr.startsWith('.$')
            ? actionStr.slice(2)
            : actionStr;
        // Handle predefined actions first (only if requirements are met)
        if (normalizedAction === 'rename' && effectiveIsEditable) {
            handleStartEditing();
        }
        if (normalizedAction === 'delete' && isDeletable) {
            onDelete?.(item.key);
        }
        // Call Tab-level onAction first (with normalized action)
        tabData.onAction?.(normalizedAction);
        // Then call Tabs-level onAction with tab key (with normalized action)
        parentOnAction?.(normalizedAction, item.key);
    });
    // Keyboard handler for accessibility shortcuts (WAI-ARIA Tabs Pattern)
    const handleKeyDown = useEvent((e) => {
        // Reset focus-visible suppression on any keyboard interaction
        if (suppressFocusVisible) {
            setSuppressFocusVisible(false);
        }
        // F2 to start editing (standard rename shortcut)
        if (e.key === 'F2' && effectiveIsEditable && !isDisabled) {
            e.preventDefault();
            e.stopPropagation();
            handleStartEditing();
        }
        // Shift+F10 opens the menu (standard context menu shortcut)
        if (e.key === 'F10' && e.shiftKey && processedMenu) {
            e.preventDefault();
            e.stopPropagation();
            setIsMenuOpen(true);
        }
        // Delete key for direct tab deletion (ARIA Tabs pattern optional feature)
        if ((e.key === 'Delete' || e.key === 'Backspace') && isDeletable) {
            e.preventDefault();
            onDelete?.(item.key);
        }
    });
    const mods = useMemo(() => ({
        type: effectiveType,
        active: isActive,
        deletable: isDeletable,
        disabled: isDisabled,
        editing: isEditing,
        hovered: isHovered,
        focused: isFocused,
        'focus-visible': effectiveFocusVisible,
        draggable: isDraggable,
        dragging: isDragging,
    }), [
        effectiveType,
        isActive,
        isDeletable,
        isDisabled,
        isEditing,
        isHovered,
        isFocused,
        effectiveFocusVisible,
        isDraggable,
        isDragging,
    ]);
    // Scroll active tab into view
    useEffect(() => {
        if (ref.current && isActive) {
            ref.current.scrollIntoView?.({ block: 'nearest', inline: 'nearest' });
        }
    }, [isActive]);
    // Build menu element
    const menuElement = processedMenu ? (_jsx(Menu, { ...effectiveMenuProps, onAction: handleMenuAction, children: processedMenu })) : null;
    // Use the useContextMenu hook for context menu handling
    const contextMenu = useContextMenu(Menu, { placement: 'bottom start' }, {
        ...effectiveMenuProps,
        onAction: handleMenuAction,
        children: processedMenu,
    });
    // Build menu trigger action with controlled state for keyboard accessibility
    const menuAction = menuElement ? (_jsxs(MenuTrigger, { isOpen: isMenuOpen, onOpenChange: setIsMenuOpen, children: [_jsx(ItemAction, { tabIndex: -1, icon: _jsx(MoreIcon, {}), ...effectiveMenuTriggerProps }), menuElement] })) : null;
    // Build delete button (only shown when no menu)
    const deleteAction = showDeleteButton ? (_jsx(ItemAction, { tabIndex: -1, icon: _jsx(CloseIcon, {}), tooltip: "Delete tab", onPress: handleDelete })) : null;
    // Order: custom actions → menu trigger → delete button
    const actions = tabData.actions || menuAction || deleteAction ? (_jsxs(_Fragment, { children: [tabData.actions, menuAction, deleteAction] })) : undefined;
    // Measure actions width to pass to Item for proper space allocation
    useLayoutEffect(() => {
        if (actions && actionsRef.current) {
            const width = Math.round(actionsRef.current.offsetWidth);
            if (width !== actionsWidth) {
                setActionsWidth(width);
            }
        }
    }, [actions, actionsWidth]);
    // Determine effective size
    const effectiveSize = tabData.size ?? size ?? 'medium';
    const itemSize = effectiveType === 'radio'
        ? RADIO_SIZE_MAP[effectiveSize === 'large' ? 'large' : 'medium']
        : effectiveSize;
    // Determine Item type prop
    const itemType = effectiveType === 'default' ? (isActive ? 'clear' : 'neutral') : 'neutral';
    // Determine shape - file/panel types use sharp edges
    const isFileOrPanelType = effectiveType === 'file' || effectiveType === 'panel';
    const itemShape = isFileOrPanelType ? 'sharp' : undefined;
    // Determine showActionsOnHover - tab-level overrides parent-level
    const effectiveShowActionsOnHover = tabData.showActionsOnHover ?? parentShowActionsOnHover;
    // Render title with editing support if editable
    const titleContent = effectiveIsEditable ? (_jsx(EditableTitle, { title: tabData.title, isEditing: isEditing, editValue: isEditing ? editValue : '', onEditValueChange: handleEditValueChange, onStartEditing: handleStartEditing, onSubmit: handleSubmitEditing, onCancel: handleCancelEditing })) : (tabData.title);
    // Extract tab-specific props and pass through the rest (style props) to the Item
    const { title: _title, content: _content, key: _key, isDisabled: _isDisabled, prerender: _prerender, keepMounted: _keepMounted, size: _size, type: _type, actions: _actions, showActionsOnHover: _showActionsOnHover, isEditable: _isEditable, onTitleChange: _onTitleChange, menu: _menu, menuTriggerProps: _menuTriggerProps, menuProps: _menuProps, contextMenu: _contextMenu, onAction: _onAction, qa, qaVal, styles, ...itemStyleProps } = tabData;
    // Use the hook's targetRef when context menu is enabled
    const effectiveContainerRef = effectiveContextMenu && processedMenu
        ? contextMenu.targetRef
        : containerRef;
    // ARIA: indicate popup menu presence
    const ariaProps = processedMenu ? { 'aria-haspopup': 'menu' } : {};
    // Mods for TabContainer
    const containerMods = {
        ...mods,
        'show-actions-on-hover': effectiveShowActionsOnHover,
    };
    return (_jsxs(TabContainer, { ref: effectiveContainerRef, "data-size": itemSize, mods: containerMods, tokens: { '$actions-width': `${actionsWidth}px` }, ...effectiveDragProps, children: [isDraggable && dropState && (_jsx(TabDropIndicator, { target: { type: 'item', key: item.key, dropPosition: 'before' }, dropState: dropState, position: "before" })), _jsx(TabElement, { preserveActionsSpace: true, showActionsOnHover: effectiveShowActionsOnHover, as: "button", ...mergeProps(tabProps, hoverProps, focusProps, {
                    onKeyDown: handleKeyDown,
                }), ...ariaProps, ...itemStyleProps, ref: ref, qa: qa ?? `Tab-${String(item.key)}`, qaVal: qaVal, styles: styles, mods: mods, isSelected: isActive, isDisabled: isDisabled, size: itemSize, type: itemType, shape: itemShape, actions: actions ? true : undefined, children: titleContent }), actions && (_jsx("div", { ref: actionsRef, "data-element": "Actions", ...ACTIONS_EVENT_HANDLERS, children: _jsx(ItemActionProvider, { type: itemType, theme: "default", isDisabled: isDisabled, children: actions }) })), effectiveContextMenu && processedMenu && contextMenu.rendered, isDraggable && dropState && isLastTab && (_jsx(TabDropIndicator, { target: { type: 'item', key: item.key, dropPosition: 'after' }, dropState: dropState, position: "after" }))] }));
}

        