/*---------------------------------------------------------------------------------------------
 * 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 "./Widget.scss";
import classnames from "classnames";
import * as React from "react";
import { assert } from "@itwin/core-bentley";
import { Rectangle, useRefs } from "@itwin/core-react/internal";
import { useDragWidget } from "../base/DragManager.js";
import { getUniqueId, MeasureContext, NineZoneDispatchContext, } from "../base/NineZone.js";
import { PanelSideContext } from "../widget-panels/Panel.js";
import { useLayout } from "../base/LayoutStore.js";
import { getWidgetState } from "../state/internal/WidgetStateHelpers.js";
import { useFloatingWidgetId } from "./FloatingWidget.js";
/** @internal */
export function WidgetProvider(props) {
    return (React.createElement(WidgetIdContext.Provider, { value: props.id }, props.children));
}
/** @internal */
export const Widget = React.forwardRef(function Widget(props, forwardedRef) {
    const dispatch = React.useContext(NineZoneDispatchContext);
    const side = React.useContext(PanelSideContext);
    const id = React.useContext(WidgetIdContext);
    const measureNz = React.useContext(MeasureContext);
    const floatingWidgetId = useFloatingWidgetId();
    assert(!!id);
    const { preferredFloatingWidgetSize, userSized } = useLayout((state) => {
        const widget = getWidgetState(state, id);
        const tab = state.tabs[widget.activeTabId];
        return {
            preferredFloatingWidgetSize: tab.preferredFloatingWidgetSize,
            userSized: tab.userSized ||
                (tab.isFloatingWidgetResizable && !!tab.preferredFloatingWidgetSize),
        };
    }, true);
    const elementRef = React.useRef(null);
    const widgetId = floatingWidgetId === undefined ? id : floatingWidgetId;
    const onDragStart = React.useCallback((updateId, initialPointerPosition, pointerPosition) => {
        assert(!!elementRef.current);
        if (floatingWidgetId !== undefined)
            return;
        const nzBounds = measureNz();
        let bounds = Rectangle.create(elementRef.current.getBoundingClientRect());
        const size = restrainInitialWidgetSize(bounds.getSize(), nzBounds.getSize());
        bounds = bounds.setSize(size);
        if (preferredFloatingWidgetSize) {
            bounds = bounds.setSize(preferredFloatingWidgetSize);
        }
        // Pointer is outside of tab area. Need to re-adjust widget bounds so that tab is behind pointer
        if (initialPointerPosition.x > bounds.right) {
            const offset = initialPointerPosition.x - bounds.right + 20;
            bounds = bounds.offsetX(offset);
        }
        const dragOffset = initialPointerPosition.getOffsetTo(pointerPosition);
        bounds = bounds.offset(dragOffset);
        // Adjust bounds to be relative to 9z origin
        bounds = bounds.offset({ x: -nzBounds.left, y: -nzBounds.top });
        const newFloatingWidgetId = getUniqueId();
        updateId(newFloatingWidgetId);
        assert(!!side);
        dispatch({
            type: "PANEL_WIDGET_DRAG_START",
            newFloatingWidgetId,
            id,
            bounds,
            side,
            userSized,
        });
    }, [
        dispatch,
        floatingWidgetId,
        id,
        side,
        measureNz,
        preferredFloatingWidgetSize,
        userSized,
    ]);
    useDragWidget({
        widgetId,
        onDragStart,
    });
    React.useEffect(() => {
        const listener = () => {
            floatingWidgetId &&
                dispatch({
                    type: "FLOATING_WIDGET_BRING_TO_FRONT",
                    id: floatingWidgetId,
                });
        };
        const element = elementRef.current;
        element?.addEventListener("click", listener);
        return () => {
            element?.removeEventListener("click", listener);
        };
    }, [dispatch, floatingWidgetId]);
    const measure = React.useCallback(() => {
        if (!elementRef.current)
            return new Rectangle();
        const bounds = elementRef.current.getBoundingClientRect();
        return Rectangle.create(bounds);
    }, []);
    const widgetContextValue = React.useMemo(() => ({
        measure,
    }), [measure]);
    const ref = useRefs(forwardedRef, elementRef);
    const className = classnames("nz-widget-widget", props.className);
    return (React.createElement(WidgetContext.Provider, { value: widgetContextValue },
        React.createElement("div", { className: className, onMouseEnter: props.onMouseEnter, onMouseLeave: props.onMouseLeave, onTransitionEnd: props.onTransitionEnd, ref: ref, style: props.style, "data-widget-id": props.widgetId }, props.children)));
});
/** @internal */
export const WidgetIdContext = React.createContext(undefined);
WidgetIdContext.displayName = "nz:WidgetIdContext";
/** @internal */
export const WidgetContext = React.createContext(null);
WidgetContext.displayName = "nz:WidgetContext";
const minWidth = 200;
const minHeight = 200;
/** @internal */
export function restrainInitialWidgetSize(size, nzSize) {
    const width = Math.max(Math.min(nzSize.width / 3, size.width), minWidth);
    const height = Math.max(Math.min(nzSize.height / 3, size.height), minHeight);
    return {
        width,
        height,
    };
}
/** @internal */
export function useActiveTabId() {
    const id = React.useContext(WidgetIdContext);
    assert(!!id);
    return useLayout((state) => {
        const widget = getWidgetState(state, id);
        return widget.activeTabId;
    });
}
//# sourceMappingURL=Widget.js.map