"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.toDisplayValueDefault = toDisplayValueDefault;
exports.TreeDropdown = TreeDropdown;
const tslib_1 = require("tslib");
const React = tslib_1.__importStar(require("react"));
const FieldWrap_1 = tslib_1.__importDefault(require("../../FieldWrap"));
const TreeList_1 = require("../TreeList");
const react_1 = require("react");
const OverlayTrigger_1 = tslib_1.__importDefault(require("../../OverlayTrigger"));
const NotifyResize_1 = tslib_1.__importDefault(require("../../NotifyResize"));
const Input_1 = tslib_1.__importDefault(require("../../Input"));
const InfiniteTable_1 = require("../../InfiniteTable");
const SimpleButton_1 = tslib_1.__importDefault(require("../../SimpleButton"));
const CheckBox_1 = require("../../CheckBox");
const useLatest_1 = require("../../utils/useLatest");
const re_resizable_1 = require("re-resizable");
const AdaptableComputedCSSVarsContext_1 = require("../../../View/AdaptableComputedCSSVarsContext");
const Flex_1 = require("../../Flex");
const resizableDirections = {
    right: true,
    bottom: true,
    bottomRight: true,
};
function toDisplayValueDefault(value) {
    if (!Array.isArray(value)) {
        return `${value}`;
    }
    return value.map((v) => (Array.isArray(v) ? v.join('-') : v)).join(', ');
}
const getLabelColumn = (field, { includeExpandCollapseButton }) => {
    return {
        field,
        defaultFlex: 1,
        renderTreeIcon: true,
        defaultSortable: false,
        resizable: false,
        renderSelectionCheckBox: ({ rowInfo, dataSourceApi, api }) => {
            if (!rowInfo.isTreeNode) {
                return null;
            }
            return (React.createElement(CheckBox_1.CheckBox, { className: "twa:mx-1", checked: rowInfo?.rowSelected, onChange: (checked) => {
                    dataSourceApi.treeApi.setNodeSelection(rowInfo.nodePath, checked);
                    api.focus();
                } }));
        },
        renderHeader: ({ dataSourceApi, api, allRowsSelected, someRowsSelected }) => {
            const { treeApi } = dataSourceApi;
            const allFirstLevelCollapsed = dataSourceApi
                .getOriginalDataArray()
                .every((item) => !treeApi.isNodeExpanded([item.id]));
            return (React.createElement(Flex_1.Flex, { flexDirection: 'row', alignItems: 'center', className: "twa:w-full", onMouseDown: (e) => {
                    // so we can keep the focus on the Grid
                    e.preventDefault();
                } },
                React.createElement(CheckBox_1.CheckBox, { checked: someRowsSelected && !allRowsSelected ? null : allRowsSelected, className: "twa:mr-2", onChange: () => {
                        if (allRowsSelected) {
                            dataSourceApi.treeApi.deselectAll();
                        }
                        else {
                            dataSourceApi.treeApi.selectAll();
                        }
                        api.focus();
                    } }, allRowsSelected ? '(Deselect All)' : '(Select All)'),
                React.createElement(Flex_1.Flex, { className: "twa:flex-1" }),
                includeExpandCollapseButton ? (React.createElement(SimpleButton_1.default, { label: "toggle-expand-collapse", icon: allFirstLevelCollapsed ? 'expand-all' : 'collapse-all', onMouseDown: () => {
                        if (allFirstLevelCollapsed) {
                            dataSourceApi.treeApi.expandAll();
                        }
                        else {
                            dataSourceApi.treeApi.collapseAll();
                        }
                    }, iconPosition: "end" })) : null));
        },
    };
};
const sizeFull = {
    width: '100%',
    height: '100%',
};
function getRowCount(options) {
    return options.reduce((acc, option) => {
        if (Array.isArray(option.children)) {
            return acc + getRowCount(option.children) + 1;
        }
        return acc + 1;
    }, 0);
}
function TreeDropdown(props) {
    const [visible, doSetVisible] = (0, react_1.useState)(false);
    const overlayDOMRef = (0, react_1.useRef)(null);
    const getProps = (0, useLatest_1.useLatest)(props);
    const computedCSSVars = (0, AdaptableComputedCSSVarsContext_1.useAdaptableComputedCSSVars)();
    const [treeExpandState, setTreeExpandState] = (0, react_1.useState)(undefined);
    const [searchValue, setSearchValue] = (0, react_1.useState)('');
    const labelField = props.labelField ?? 'label';
    const [stateValue, setStateValue] = (0, react_1.useState)(props.value !== undefined ? props.value : props.defaultValue || []);
    const onChange = (0, react_1.useCallback)((value) => {
        const paths = value instanceof InfiniteTable_1.TreeSelectionState
            ? value.getState().selectedPaths
            : value.selectedPaths || [];
        if (props.value === undefined) {
            setStateValue(paths);
        }
        props.onChange?.(paths);
    }, [props.onChange, props.value]);
    const value = props.value !== undefined ? props.value : stateValue;
    const treeSelection = (0, react_1.useMemo)(() => {
        const selection = {
            defaultSelection: false,
            selectedPaths: value,
        };
        return selection;
    }, [value]);
    const rowCount = (0, react_1.useMemo)(() => {
        return getRowCount(props.options);
    }, [props.options]);
    const hasChildren = rowCount > props.options.length;
    const columns = (0, react_1.useMemo)(() => {
        return {
            label: getLabelColumn(labelField, {
                includeExpandCollapseButton: hasChildren,
            }),
        };
    }, [labelField, hasChildren]);
    const [size, setSize] = (0, react_1.useState)({
        width: 0,
        height: rowCount * 35,
    });
    const setHeight = (0, react_1.useCallback)((height) => {
        setSize((s) => {
            return {
                ...s,
                height,
            };
        });
    }, []);
    const setWidth = (0, react_1.useCallback)((width) => {
        setSize((s) => {
            return {
                ...s,
                width,
            };
        });
    }, []);
    const getSize = (0, useLatest_1.useLatest)(size);
    (0, react_1.useEffect)(() => {
        if (!getSize().height) {
            setHeight(rowCount * 35);
        }
    }, [rowCount]);
    const setVisible = (visible) => {
        if (visible) {
            const { onMenuOpen } = getProps();
            if (onMenuOpen) {
                onMenuOpen();
            }
            requestAnimationFrame(() => {
                doSetVisible(visible);
            });
        }
        else {
            const { onMenuClose } = getProps();
            if (onMenuClose) {
                onMenuClose();
            }
            doSetVisible(visible);
        }
    };
    const [treeListApi, setTreeListApi] = (0, react_1.useState)(null);
    const { listSizeConstraints } = props;
    const nodeMatches = (0, react_1.useCallback)(({ data }) => {
        return !searchValue
            ? data
            : `${data[labelField]}`.toLowerCase().includes(searchValue.toLowerCase());
    }, [searchValue]);
    const filterFunction = (0, react_1.useCallback)(({ data, filterTreeNode }) => {
        if (!Array.isArray(data.children)) {
            return nodeMatches({ data });
        }
        // allow non-leaf nodes to match
        if (nodeMatches({ data })) {
            return data;
        }
        return filterTreeNode(data);
    }, [nodeMatches]);
    return (React.createElement(Flex_1.Flex, { flexDirection: 'row', className: "ab-TreeDropdown twa:w-full", style: props.style, onMouseDown: props.onMouseDown, onBlur: (e) => {
            const { relatedTarget } = e;
            const overlayDOMNode = overlayDOMRef.current;
            if ((overlayDOMNode && relatedTarget == overlayDOMNode) ||
                overlayDOMNode?.contains(relatedTarget)) {
                return;
            }
            setVisible(false);
        } },
        React.createElement(NotifyResize_1.default, { onResize: (newSize) => {
                setWidth(newSize.width);
            } }),
        React.createElement(OverlayTrigger_1.default, { visible: visible, targetOffset: 20, alignPosition: [
                // overlay - target
                ['TopLeft', 'BottomLeft'],
                ['TopRight', 'BottomRight'],
                ['BottomLeft', 'TopLeft'],
                ['BottomRight', 'TopRight'],
            ], render: () => {
                const minWidth = listSizeConstraints?.minWidth ||
                    computedCSSVars['--ab-cmp-select-menu__min-width'] ||
                    240;
                const maxWidth = listSizeConstraints?.maxWidth ||
                    computedCSSVars['--ab-cmp-select-menu__max-width'] ||
                    '60vw';
                const minHeight = listSizeConstraints?.minHeight || 200;
                const maxHeight = listSizeConstraints?.maxHeight ||
                    computedCSSVars['--ab-cmp-select-menu__max-height'] ||
                    '50vh';
                const resizable = getProps().resizable;
                const treeListStyle = resizable
                    ? { ...sizeFull }
                    : {
                        width: size.width,
                        height: size.height,
                        maxWidth,
                        minHeight,
                        maxHeight,
                        minWidth,
                    };
                if (!hasChildren) {
                    // @ts-ignore - don't leave any space for the > expand icon, as there are no children
                    treeListStyle['--infinite-group-row-column-nesting'] = 'calc(var(--ab-base-space) * 2)';
                }
                const treeList = (React.createElement(TreeList_1.TreeList, { primaryKey: props.primaryKey ?? 'id', treeFilterFunction: filterFunction, columnHeaderHeight: 30, onReady: ({ api }) => {
                        setTreeListApi(api);
                        api.focus();
                    }, defaultTreeExpandState: treeExpandState, onTreeExpandStateChange: setTreeExpandState, columns: columns, options: props.options, treeSelection: treeSelection, onTreeSelectionChange: (0, InfiniteTable_1.withSelectedLeafNodesOnly)(onChange), style: treeListStyle }));
                let children = (React.createElement(Flex_1.Flex, { flexDirection: 'column', className: "twa:h-full" },
                    React.createElement(Flex_1.Flex, { className: "twa:bg-defaultbackground twa:p-1 twa:items-center twa:justify-stretch twa:justify-items-stretch" },
                        React.createElement(Input_1.default, { "data-name": "menulist-search-input", placeholder: "Search...", style: { width: '100%' }, value: searchValue, onChange: (e) => setSearchValue(e.target.value) })),
                    treeList));
                if (resizable) {
                    const onResizeStop = (_e, _direction, ref) => {
                        const newSize = {
                            width: ref.style.width,
                            height: ref.style.height,
                        };
                        setSize(newSize);
                    };
                    children = (React.createElement(re_resizable_1.Resizable, { enable: resizableDirections, minWidth: minWidth, maxWidth: maxWidth, minHeight: minHeight, maxHeight: maxHeight, defaultSize: size, onResizeStop: onResizeStop, onResizeStart: (e) => {
                            // in order to prevent focus from being lost
                            e.preventDefault();
                        } }, children));
                }
                return (React.createElement(Flex_1.Box, { ref: overlayDOMRef, className: "ab-TreeDropdownOverlay", "data-name": "menu-container", style: {
                        fontSize: 'var(--ab-cmp-select__font-size)',
                    } }, children));
            } },
            React.createElement(FieldWrap_1.default, { style: props.fieldStyle, className: "twa:w-full" },
                React.createElement(Input_1.default, { type: "text", readOnly: true, "data-name": "Select Values", "aria-expanded": visible, placeholder: props.placeholder ?? 'Select a value', className: `twa:w-full ${props.clearable ? 'twa:pr-0' : ''}`, value: props.toDisplayValue ? props.toDisplayValue(value) : toDisplayValueDefault(value), onFocus: () => {
                        if (!visible) {
                            setVisible(true);
                        }
                        treeListApi?.focus();
                    } }),
                props.clearable && (React.createElement(SimpleButton_1.default, { style: {
                        visibility: Array.isArray(value) && value.length > 0 ? 'visible' : 'hidden',
                    }, variant: "text", icon: "close", onClick: () => onChange({ selectedPaths: [] }) }))))));
}
