"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.renderSelectionSection = void 0;
exports.ValueSelector = ValueSelector;
const tslib_1 = require("tslib");
const React = tslib_1.__importStar(require("react"));
const react_1 = require("react");
const dnd_1 = require("../../../components/dnd");
const CheckBox_1 = require("../../../components/CheckBox");
const icons_1 = require("../../../components/icons");
const Radio_1 = tslib_1.__importDefault(require("../../../components/Radio"));
const AdaptableFormControlTextClear_1 = require("../Forms/AdaptableFormControlTextClear");
const ArrayExtensions_1 = tslib_1.__importDefault(require("../../../Utilities/Extensions/ArrayExtensions"));
const Flex_1 = require("../../../components/Flex");
const clsx_1 = tslib_1.__importDefault(require("clsx"));
function useValuesMap({ options, value, toIdentifier, selectedMap, }) {
    const optionsMap = (0, react_1.useMemo)(() => {
        if (selectedMap) {
            return;
        }
        const map = new Map([]);
        options.forEach((option) => {
            map.set(toIdentifier(option), option);
        });
        return map;
    }, [options, selectedMap]);
    const result = (0, react_1.useMemo)(() => {
        if (selectedMap) {
            return selectedMap;
        }
        const map = new Map([]);
        value.forEach((id) => {
            map.set(id, optionsMap.get(id) ?? null);
        });
        return map;
    }, [optionsMap, selectedMap, value]);
    return { selectedMap: result, optionsMap };
}
const baseClassName = 'ab-ValueSelector';
function ValueSelector(props) {
    const { options, value, filter, onChange, allowReorder = true, singleSelect, toLabel, toListLabel, toIdentifier, showSelectedOnlyLabel, showFilterInput, onShowSelectedOnlyChange, isOptionDisabled, disabled, } = props;
    const [searchInputValue, setSearchInputValue] = React.useState('');
    const preparedToLabel = toListLabel ?? toLabel;
    const [selectedOnly, doSetSelectedOnly] = (0, react_1.useState)(false);
    const setSelectedOnly = (0, react_1.useCallback)((selectedOnly) => {
        doSetSelectedOnly(selectedOnly);
        onShowSelectedOnlyChange?.(selectedOnly);
    }, [onShowSelectedOnlyChange]);
    const { selectedMap } = useValuesMap({
        options,
        toIdentifier,
        value,
    });
    const notifyChange = (0, react_1.useCallback)(() => {
        const newSelection = [...selectedMap.keys()];
        if (!newSelection.length && selectedOnly) {
            setSelectedOnly(false);
        }
        onChange(newSelection, new Map(selectedMap));
    }, [onChange, selectedOnly, selectedMap]);
    const renderOption = (option, index) => {
        const identifier = toIdentifier(option);
        const label = !allowReorder ? preparedToLabel(option) : null;
        const reorderable = typeof allowReorder === 'function' ? allowReorder(option) : allowReorder;
        const renderNode = (props, dragHandleProps) => {
            return (React.createElement(Flex_1.Flex, { alignItems: "center", key: identifier ?? index, "data-index": index, "data-id": identifier, "data-name": "option", ...props, className: (0, clsx_1.default)(`twa:bg-primary twa:text-text-on-primary twa:rounded-standard twa:p-2`, {
                    'twa:mt-1': index,
                    'twa:mt-0': !index,
                }, props.className, `${baseClassName}__option`) },
                React.createElement(Flex_1.Flex, { flexDirection: "row", alignItems: "center", className: "twa:flex-1" },
                    reorderable ? (React.createElement(Flex_1.Box, { ...dragHandleProps, className: (0, clsx_1.default)('twa:mr-3', dragHandleProps?.className) },
                        React.createElement(icons_1.Icon, { name: "drag", style: { cursor: 'grab' } }))) : null,
                    singleSelect ? (React.createElement(Radio_1.default, { checked: selectedMap.has(identifier), "data-name": identifier, onChange: (checked) => {
                            if (checked) {
                                selectedMap.clear();
                                selectedMap.set(identifier, option);
                            }
                            else {
                                selectedMap.delete(identifier);
                            }
                            notifyChange();
                        } }, label)) : (React.createElement(CheckBox_1.CheckBox, { "data-name": identifier, disabled: disabled || (isOptionDisabled ? isOptionDisabled(option) : false), onChange: (checked) => {
                            if (checked) {
                                selectedMap.set(identifier, option);
                            }
                            else {
                                selectedMap.delete(identifier);
                            }
                            notifyChange();
                        }, checked: selectedMap.has(identifier) }, label)),
                    React.createElement(Flex_1.Box, { className: "twa:ml-2 twa:flex-1" }, allowReorder ? preparedToLabel(option) : null))));
        };
        return (React.createElement(dnd_1.Draggable, { key: identifier, index: index, draggableId: `${identifier}`, isDragDisabled: !reorderable }, (draggableProvided) => {
            return renderNode({
                ref: draggableProvided.innerRef,
                ...draggableProvided.draggableProps,
                style: draggableProvided.draggableProps.style,
            }, draggableProvided.dragHandleProps);
        }));
    };
    const showOnlySelectedCheckbox = (React.createElement(CheckBox_1.CheckBox, { disabled: !value.length, checked: selectedOnly, onChange: setSelectedOnly }, showSelectedOnlyLabel ?? 'Show Selected Only'));
    const selectionSectionProps = {
        ...props,
        showOnlySelectedCheckbox,
        onSelectAll: () => {
            options.forEach((option) => {
                selectedMap.set(toIdentifier(option), option);
            });
            notifyChange();
        },
        onClearOption: (id) => {
            selectedMap.delete(id);
            notifyChange();
        },
        onClear: () => {
            selectedMap.clear();
            notifyChange();
        },
    };
    return (React.createElement(Flex_1.Flex, { style: props.style, className: (0, clsx_1.default)('twa:flex-1', baseClassName), flexDirection: "column" },
        React.createElement(Flex_1.Flex, { className: "twa:mb-1" }, showFilterInput && filter ? (React.createElement(AdaptableFormControlTextClear_1.AdaptableFormControlTextClear, { value: searchInputValue, OnTextChange: setSearchInputValue, placeholder: "Type to search", className: "twa:flex-1 twa:border-0 twa:m-[3px]" })) : (React.createElement(Flex_1.Box, { className: "twa:flex-1" }))),
        (0, exports.renderSelectionSection)(selectionSectionProps),
        React.createElement(dnd_1.DragDropContext, { onDragEnd: (result) => {
                const { source, destination } = result;
                const selection = [];
                const extraKeys = [];
                for (let [key, value] of selectedMap) {
                    if (value != null) {
                        selection.push(key);
                    }
                    else {
                        // null/non-existent keys have to be stored separately
                        extraKeys.push(key);
                    }
                }
                const clone = new Map(selectedMap);
                const newSelection = ArrayExtensions_1.default.reorderArray(selection, source.index, destination.index);
                // and then pushed back in the new order, at the end
                newSelection.push(...extraKeys);
                selectedMap.clear();
                newSelection.forEach((key) => {
                    selectedMap.set(key, clone.get(key));
                });
                notifyChange();
            } },
            React.createElement(Flex_1.Flex, { className: `${baseClassName}__body twa:flex-1 twa:overflow-auto`, flexDirection: "column" },
                React.createElement(dnd_1.Droppable, { droppableId: "droppable" }, (droppableProvided) => {
                    return (React.createElement("div", { ref: droppableProvided.innerRef, ...droppableProvided.droppableProps },
                        options
                            .filter((option) => {
                            let result = true;
                            if (filter) {
                                result = filter(option, searchInputValue);
                            }
                            result =
                                result && (selectedOnly ? selectedMap.has(toIdentifier(option)) : true);
                            return result;
                        })
                            .map(renderOption),
                        droppableProvided.placeholder));
                })))));
}
const renderSelectionSection = (props) => {
    const { value, options, disabled, singleSelect, toLabel, toIdentifier, } = props;
    const selectionBox = (React.createElement(Flex_1.Box, { className: "twa:flex twa:flex-col twa:gap-2 twa:py-2" },
        React.createElement(Flex_1.Box, { className: (0, clsx_1.default)('twa:flex twa:flex-row', 'twa:border-b twa:border-primarydark/30 twa:rounded-standard') },
            singleSelect ? (React.createElement(Flex_1.Box, { className: "twa:flex twa:flex-row twa:text-3 twa:font-normal" },
                "(",
                value.length,
                " of ",
                options.length,
                " selected)")) : (React.createElement(CheckBox_1.CheckBox, { className: "twa:ml-0.5 twa:font-bold", checked: !value.length ? false : value.length === options.length ? true : null, onChange: (checked) => {
                    if (checked) {
                        props.onSelectAll();
                    }
                    else {
                        props.onClear();
                    }
                } },
                React.createElement(Flex_1.Box, { className: "twa:flex twa:flex-row twa:items-center twa:gap-3" },
                    "Select All",
                    React.createElement(Flex_1.Box, { className: "twa:text-2 twa:font-normal" },
                        "(",
                        value.length,
                        " of ",
                        options.length,
                        " selected)")))),
            React.createElement("div", { className: "twa:flex-1" }),
            React.createElement(Flex_1.Box, { className: "twa:mr-2 twa:text-2 twa:font-normal" }, props.showOnlySelectedCheckbox))));
    return React.createElement(Flex_1.Box, { className: (0, clsx_1.default)(`${baseClassName}__header `) }, selectionBox);
};
exports.renderSelectionSection = renderSelectionSection;
