/*---------------------------------------------------------------------------------------------
 * Copyright (c) Bentley Systems, Incorporated. All rights reserved.
 * See LICENSE.md in the project root for license terms and full copyright notice.
 *--------------------------------------------------------------------------------------------*/
/** @packageDocumentation
 * @module Widget
 */
import "./Tab.scss";
import classnames from "classnames";
import * as React from "react";
import { Key } from "ts-key-enum";
import { assert } from "@itwin/core-bentley";
import { Icon, Point, Rectangle, Timer, useRefs, useResizeObserver, } from "@itwin/core-react";
import { useDragTab } from "../base/DragManager";
import { MeasureContext, NineZoneDispatchContext, ShowWidgetIconContext, TabNodeContext, } from "../base/NineZone";
import { usePointerCaptor } from "../base/usePointerCaptor";
import { PanelSideContext } from "../widget-panels/Panel";
import { WidgetTabsEntryContext } from "./Tabs";
import { restrainInitialWidgetSize, WidgetContext, WidgetIdContext, } from "./Widget";
import { TabIdContext } from "./ContentRenderer";
import { TabTarget } from "../target/TabTarget";
import { WidgetMenuTab } from "./MenuTab";
import { WidgetOverflowContext } from "./Overflow";
import { useLayout, useLayoutStore } from "../base/LayoutStore";
import { useFloatingWidgetId } from "./FloatingWidget";
import { getWidgetState } from "../state/internal/WidgetStateHelpers";
import { useIsMaximizedWidget } from "../../preview/enable-maximized-widget/useMaximizedWidget";
/** @internal */
export function WidgetTabProvider({ id, first, firstInactive, last, showOnlyTabIcon, }) {
    const tabNode = React.useContext(TabNodeContext);
    const position = React.useMemo(() => ({
        first,
        firstInactive,
        last,
    }), [first, firstInactive, last]);
    return (React.createElement(TabIdContext.Provider, { value: id },
        React.createElement(TabPositionContext.Provider, { value: position },
            React.createElement(IconOnlyOnWidgetTabContext.Provider, { value: !!showOnlyTabIcon }, tabNode))));
}
/** Component that displays a tab in a side panel widget.
 * @internal
 */
export function WidgetTab(props) {
    const widgetOverflow = React.useContext(WidgetOverflowContext);
    const overflown = !!widgetOverflow;
    if (overflown)
        return React.createElement(WidgetMenuTab, { ...props });
    return React.createElement(WidgetTabComponent, { ...props });
}
function WidgetTabComponent(props) {
    const id = React.useContext(TabIdContext);
    const { first, firstInactive, last } = React.useContext(TabPositionContext);
    const widgetTabsEntryContext = React.useContext(WidgetTabsEntryContext);
    const side = React.useContext(PanelSideContext);
    const widgetId = React.useContext(WidgetIdContext);
    const showIconOnly = React.useContext(IconOnlyOnWidgetTabContext);
    const showWidgetIcon = React.useContext(ShowWidgetIconContext);
    assert(!!id);
    assert(!!widgetId);
    const iconSpec = useLayout((state) => state.tabs[id].iconSpec);
    const label = useLayout((state) => state.tabs[id].label);
    const activeTabId = useLayout((state) => getWidgetState(state, widgetId).activeTabId);
    const minimized = useLayout((state) => getWidgetState(state, widgetId).minimized);
    const maximizedWidget = useIsMaximizedWidget();
    const resizeObserverRef = useResizeObserver(widgetTabsEntryContext?.onResize);
    const pointerCaptorRef = useTabInteractions({ clickOnly: maximizedWidget });
    const refs = useRefs(resizeObserverRef, pointerCaptorRef);
    const active = activeTabId === id;
    const className = classnames("nz-widget-tab", active && "nz-active", undefined === side && minimized && "nz-minimized", first && "nz-first", last && "nz-last", firstInactive && "nz-first-inactive", props.className);
    const showLabel = (showIconOnly && !iconSpec) ||
        (showWidgetIcon && !showIconOnly) ||
        !showWidgetIcon;
    return (React.createElement("div", { "data-item-id": id, "data-item-type": "widget-tab", className: className, ref: refs, role: "tab", style: props.style, title: label, tabIndex: 0 },
        (showWidgetIcon || showIconOnly) && iconSpec && (React.createElement(Icon, { iconSpec: iconSpec })),
        showLabel && React.createElement("span", null, label),
        props.badge && React.createElement("div", { className: "nz-badge" }, props.badge),
        React.createElement(TabTarget, null)));
}
/** @internal */
export function useTabInteractions({ onClick, onDoubleClick, onDragStart, clickOnly, }) {
    const id = React.useContext(TabIdContext);
    const widgetContext = React.useContext(WidgetContext);
    const measure = React.useContext(MeasureContext);
    const dispatch = React.useContext(NineZoneDispatchContext);
    const side = React.useContext(PanelSideContext);
    const widgetId = React.useContext(WidgetIdContext);
    const widgetTabsEntryContext = React.useContext(WidgetTabsEntryContext);
    const floatingWidgetId = useFloatingWidgetId();
    assert(!!id);
    assert(!!widgetId);
    const layoutStore = useLayoutStore();
    const tabRef = React.useRef(layoutStore.getState().tabs[id]);
    const clickCount = React.useRef(0);
    // eslint-disable-next-line deprecation/deprecation
    const doubleClickTimer = React.useRef(new Timer(300));
    const initialPointerPosition = React.useRef();
    const overflown = !widgetTabsEntryContext;
    React.useEffect(() => layoutStore.subscribe((state) => {
        tabRef.current = state.tabs[id];
    }), [layoutStore, id]);
    const handleClick = React.useCallback(() => {
        dispatch({
            type: "WIDGET_TAB_CLICK",
            side,
            widgetId,
            id,
        });
        onClick?.();
    }, [dispatch, widgetId, id, side, onClick]);
    const handleDoubleClick = React.useCallback(() => {
        if (clickOnly)
            return;
        dispatch({
            type: "WIDGET_TAB_DOUBLE_CLICK",
            side,
            widgetId,
            floatingWidgetId,
            id,
        });
        onDoubleClick?.();
    }, [
        clickOnly,
        dispatch,
        floatingWidgetId,
        widgetId,
        id,
        side,
        onDoubleClick,
    ]);
    const handleDragTabStart = useDragTab({
        tabId: id,
    });
    const handleDragStart = React.useCallback((pointerPosition) => {
        if (clickOnly)
            return;
        assert(!!ref.current);
        assert(!!initialPointerPosition.current);
        const nzBounds = measure();
        const nzOffset = new Point(-nzBounds.left, -nzBounds.top);
        let bounds = Rectangle.create(ref.current.getBoundingClientRect());
        bounds = bounds.offset(nzOffset);
        const tab = tabRef.current;
        const userSized = tab.userSized ||
            (tab.isFloatingWidgetResizable && !!tab.preferredFloatingWidgetSize);
        let position = bounds.topLeft();
        const widgetBounds = widgetContext.measure();
        const widgetSize = restrainInitialWidgetSize(widgetBounds.getSize(), nzBounds.getSize());
        if (overflown) {
            position = initialPointerPosition.current.offset(nzOffset);
            position = position.offset({ x: -7, y: -7 });
        }
        const dragOffset = initialPointerPosition.current.getOffsetTo(pointerPosition);
        position = position.offset(dragOffset);
        handleDragTabStart({
            initialPointerPosition: Point.create(initialPointerPosition.current),
            pointerPosition,
            widgetSize,
        });
        dispatch({
            type: "WIDGET_TAB_DRAG_START",
            floatingWidgetId,
            side,
            widgetId,
            id,
            position,
            userSized,
        });
        onDragStart?.();
        initialPointerPosition.current = undefined;
    }, [
        clickOnly,
        measure,
        widgetContext,
        handleDragTabStart,
        dispatch,
        floatingWidgetId,
        side,
        widgetId,
        id,
        onDragStart,
        overflown,
    ]);
    const handlePointerDown = React.useCallback((args, e) => {
        e.type === "touchstart" &&
            floatingWidgetId &&
            dispatch({
                type: "FLOATING_WIDGET_BRING_TO_FRONT",
                id: floatingWidgetId,
            });
        initialPointerPosition.current = new Point(args.clientX, args.clientY);
    }, [dispatch, floatingWidgetId]);
    const handlePointerMove = React.useCallback((args) => {
        if (!initialPointerPosition.current)
            return;
        const pointerPosition = new Point(args.clientX, args.clientY);
        const distance = initialPointerPosition.current.getDistanceTo(pointerPosition);
        if (distance < 10)
            return;
        handleDragStart(pointerPosition);
    }, [handleDragStart]);
    const handlePointerUp = React.useCallback(() => {
        clickCount.current++;
        initialPointerPosition.current = undefined;
        doubleClickTimer.current.start();
    }, []);
    const pointerCaptorRef = usePointerCaptor(handlePointerDown, handlePointerMove, handlePointerUp);
    const ref = React.useRef();
    const refs = useRefs(pointerCaptorRef, ref);
    React.useEffect(() => {
        const timer = doubleClickTimer.current;
        timer.setOnExecute(() => {
            if (clickCount.current === 1)
                handleClick();
            else
                handleDoubleClick();
            clickCount.current = 0;
        });
        const keydown = (e) => {
            if (e.key === " " || e.key === Key.Enter.valueOf()) {
                handleClick();
            }
        };
        const instance = ref.current;
        instance && instance.addEventListener("keydown", keydown);
        return () => {
            timer.setOnExecute(undefined);
            instance && instance.removeEventListener("keydown", keydown);
        };
    }, [handleClick, handleDoubleClick]);
    return refs;
}
/** @internal */
export const TabPositionContext = React.createContext(undefined);
TabPositionContext.displayName = "nz:TabPositionContext";
/** @internal */
export const IconOnlyOnWidgetTabContext = React.createContext(false);
IconOnlyOnWidgetTabContext.displayName = "nz:IconOnlyOnWidgetTabContext";
//# sourceMappingURL=Tab.js.map