import { Fragment as _Fragment, jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
import { useEffect, useMemo, useRef, useState } from 'react';
import './Select.scss';
import Icon from '../Icon';
import Typography from '../Typography';
import classNames from 'classnames';
import { createPortal } from 'react-dom';
import Dropdown from './components/Dropdown';
import { getValue } from '../../utils/getSelectOptionValue/getSelectOptionValue';
import usePortalPosition from '../../hooks/usePortalPosition';
import Tooltip from '../Tooltip';
import { checkEmpty } from '../../utils/checkEmpty/checkEmpty';
import { truncateText } from '../../utils/truncateText/truncateText';
const Select = ({ label = 'Default Label', showLabel = true, optionsList = [], selectedOption = { label: '', value: '' }, onChange = () => { }, errorMsg = '', className = '', optionZIndex = 1500, disabled = false, showBorder = true, required = true, optionsRequired = true, selectedOptionColor = 'var(--ff-select-text-color)', labelAccessor = '', valueAccessor = '', height = 32, width = '100%', onBlur = () => { }, disableInput = false, showIcon = false, placeHolder = '', showToolTip = false, onCancelModal = () => { }, onSaveModal = () => { }, modalJSXProps = _jsx(_Fragment, {}), recurrence = false, showArrowIcon = true, showClearIcon = false, handelClear = () => { }, showOptions = { open: false, toggle: false }, tooltip = false, background = '', borderRadius = '0px', noResultsMessage, dropDownRef, dropDownHeight = 160, onSearchText, isCustomButtonDisabled = false, hasInnerClearIcon = false, dropdownInnerIconWidth = 0, onDropdownOpen = () => { }, }) => {
    const selectWidth = typeof width === 'number' ? `${width}px` : width;
    const memoizedOptionsList = useMemo(() => optionsList, [optionsList]);
    const [highlightedIndex, setHighlightedIndex] = useState(-1);
    const [showDropdownOptions, setShowDropdownOptions] = useState(false);
    const [customRecurrence, setCustomRecurrence] = useState(false);
    const [searchedOption, setSearchedOption] = useState({
        searchedText: '',
        searchedIcon: '',
        searchedIconColor: '',
    });
    const { searchedText, searchedIcon, searchedIconColor } = searchedOption;
    const [selectOptionList, setSelectOptionList] = useState([]);
    const [dropdownPosition, setDropdownPosition] = useState({
        positionX: 0,
        positionY: 0,
        width: 0,
        fromBottom: 0,
    });
    const DropdownRef = useRef(null);
    const selectWrapperRef = useRef(null);
    const inputRef = useRef(null);
    const selectArrowRef = useRef(null);
    const calculatePosition = usePortalPosition(inputRef, showDropdownOptions);
    const handleIconClick = () => {
        if (disabled)
            return;
        setShowDropdownOptions(!showDropdownOptions);
        setSearchedOption({
            ...searchedOption,
            searchedText: getValue(selectedOption, valueAccessor) || '',
        });
        setSelectOptionList(optionsList);
        if (!showDropdownOptions && inputRef.current) {
            inputRef.current.focus();
        }
    };
    const handleChange = (event) => {
        if (disabled)
            return;
        const { value } = event.target;
        onSearchText?.(value);
        const filteredOptions = optionsList.filter((option) => {
            const valueData = getValue(option, valueAccessor);
            return typeof valueData === 'string'
                ? valueData.toLowerCase().includes(value.toLowerCase().trim())
                : valueData === Number(value);
        });
        setSelectOptionList(filteredOptions);
        setSearchedOption({
            ...searchedOption,
            searchedText: value,
        });
    };
    const onSelectUpdatePosition = () => {
        if (!showDropdownOptions || !DropdownRef?.current || disabled)
            return;
        setDropdownPosition(calculatePosition(inputRef));
    };
    const onSelectToggleScroll = (isEnabled) => {
        const scrollWidth = window.innerWidth - document.documentElement.clientWidth;
        if (isEnabled) {
            document.body.style.paddingRight = '';
            document.body.style.overflow = '';
        }
        else {
            document.body.style.paddingRight = `${scrollWidth}px`;
            document.body.style.overflow = 'hidden';
        }
    };
    const handleFocus = () => {
        if (disabled)
            return;
        setShowDropdownOptions(true);
    };
    useEffect(() => {
        if (showOptions.open) {
            setShowDropdownOptions(true);
        }
    }, [showOptions.toggle]);
    const onSelectBlur = () => {
        setShowDropdownOptions(false);
        setDropdownPosition({
            positionX: 0,
            positionY: 0,
            fromBottom: 0,
            width: 0,
        });
        setSelectOptionList(optionsList);
        if (inputRef?.current === document.activeElement) {
            inputRef?.current?.blur();
            setSearchedOption({
                searchedText: getValue(selectedOption, valueAccessor) || '',
                searchedIcon: selectedOption.iconName || '',
                searchedIconColor: selectedOption.iconColor,
            });
            setCustomRecurrence(false);
            onBlur();
        }
    };
    const onSelectOptionSelector = (option) => {
        if (disabled)
            return;
        const isCustomRecurrence = option?.recurrence || false;
        setCustomRecurrence(isCustomRecurrence);
        setSearchedOption({
            searchedText: getValue(selectedOption, valueAccessor),
            searchedIcon: selectedOption.iconName,
            searchedIconColor: selectedOption.iconColor,
        });
        if (!isCustomRecurrence) {
            onSelectBlur();
        }
        if (onChange) {
            onChange(option);
        }
    };
    const handleResizeOrScroll = () => onSelectUpdatePosition();
    const getScrollParent = (element) => {
        const scrollableParents = [];
        if (!element)
            return scrollableParents;
        let parent = element.parentElement;
        while (parent) {
            const tagName = parent.tagName.toLowerCase();
            // Skip tbody and similar non-scrollable semantic containers
            if (tagName === 'tbody') {
                parent = parent.parentElement;
                continue;
            }
            const style = window.getComputedStyle(parent);
            const overflowY = style.overflowY;
            const overflowX = style.overflowX;
            const isScrollable = (overflowY === 'auto' ||
                overflowY === 'scroll' ||
                overflowX === 'auto' ||
                overflowX === 'scroll') &&
                (parent.scrollHeight > parent.clientHeight ||
                    parent.scrollWidth > parent.clientWidth);
            if (isScrollable) {
                scrollableParents.push(parent);
            }
            parent = parent.parentElement;
        }
        // as fallback also include window scroll (document.body)
        return scrollableParents.length ? scrollableParents : [document.body];
    };
    useEffect(() => {
        if (!showDropdownOptions || disabled)
            return;
        const selectedIndex = sortedOptions.findIndex((item) => item.type === 'option' &&
            getValue(item.option, valueAccessor) ===
                getValue(selectedOption, valueAccessor));
        const fallbackIndex = getNextSelectableIndex(sortedOptions, 0, 1);
        setHighlightedIndex(selectedIndex >= 0 ? selectedIndex : fallbackIndex);
        onDropdownOpen();
        if (optionsRequired) {
            onSelectToggleScroll(false);
        }
        onSelectUpdatePosition();
        const scrollableParents = getScrollParent(inputRef.current);
        window.addEventListener('resize', handleResizeOrScroll);
        scrollableParents.forEach((parent) => {
            parent.addEventListener('scroll', onSelectBlur);
        });
        return () => {
            onSelectToggleScroll(true);
            window.removeEventListener('resize', handleResizeOrScroll);
            scrollableParents.forEach((parent) => {
                parent.removeEventListener('scroll', onSelectBlur);
            });
        };
    }, [showDropdownOptions]);
    useEffect(() => {
        setSearchedOption({
            searchedText: getValue(selectedOption, valueAccessor),
            searchedIcon: selectedOption.iconName,
            searchedIconColor: selectedOption.iconColor,
        });
    }, [
        selectedOption?.label,
        selectedOption?.value,
        selectedOption?.iconName,
        getValue(selectedOption, valueAccessor),
    ]);
    useEffect(() => {
        setSelectOptionList(memoizedOptionsList);
    }, [memoizedOptionsList]);
    if (showLabel) {
        placeHolder = '';
    }
    const [isTruncated, setIsTruncated] = useState(false);
    const [displaySearchedText, setDisplaySearchedText] = useState('');
    useEffect(() => {
        const updateTruncation = () => {
            const input = inputRef.current;
            if (!input)
                return;
            // derive properties from input
            const styles = window.getComputedStyle(input);
            const paddingLeft = parseFloat(styles.paddingLeft || '0');
            const paddingRight = parseFloat(styles.paddingRight || '0');
            const availableWidth = input.clientWidth - paddingLeft - paddingRight;
            const fontSize = parseFloat(styles.fontSize || '12');
            const fontFamily = styles.fontFamily;
            const letterSpacing = parseFloat(styles.letterSpacing || '0') || 0;
            const truncated = truncateText(searchedText, availableWidth, 'pixel', fontSize, fontFamily, letterSpacing);
            setDisplaySearchedText(truncated);
            setIsTruncated(truncated !== searchedText); // if different → truncated → show tooltip
        };
        updateTruncation();
        window.addEventListener('resize', updateTruncation);
        return () => {
            window.removeEventListener('resize', updateTruncation);
        };
    }, [searchedText, width]);
    const getNextSelectableIndex = (items, startIndex, direction) => {
        let index = startIndex;
        while (index >= 0 && index < items.length) {
            const item = items[index];
            const isGroup = item?.type === 'group';
            const isDisabled = item?.type === 'option' && item?.option?.disable;
            if (!isGroup && !isDisabled) {
                return index;
            }
            index += direction;
        }
        return startIndex - direction;
    };
    function moveSelectedToTopByGroup(data, selectedValue, selectedGroup) {
        const result = [];
        let currentGroup = null;
        let groupOptions = [];
        const flushGroup = () => {
            if (!currentGroup)
                return;
            let selected = [];
            let others = groupOptions;
            if (currentGroup === selectedGroup) {
                selected = groupOptions.filter((item) => item?.option?.value === selectedValue);
                others = groupOptions.filter((item) => item?.option?.value !== selectedValue);
            }
            result.push({ type: 'group', groupName: currentGroup }, ...selected, ...others);
            groupOptions = [];
        };
        for (const item of data) {
            if (item?.type === 'group') {
                flushGroup();
                currentGroup = item.groupName;
            }
            else {
                groupOptions.push(item);
            }
        }
        flushGroup();
        return result;
    }
    const groupBy = 'group';
    const sortedOptions = useMemo(() => {
        if (checkEmpty(selectOptionList))
            return [];
        if (selectOptionList[0]?.hasOwnProperty('group')) {
            if (!groupBy) {
                return selectOptionList.map((option) => ({
                    type: 'option',
                    option,
                }));
            }
            const isGroupingValid = selectOptionList.every((option) => option[groupBy] !== undefined &&
                option[groupBy] !== null &&
                option[groupBy] !== '');
            if (!isGroupingValid) {
                return selectOptionList?.map((option) => ({
                    type: 'option',
                    option,
                }));
            }
            const groups = {};
            selectOptionList.forEach((option) => {
                const group = option[groupBy];
                groups[group] = groups[group] || [];
                groups[group].push(option);
            });
            const items = [];
            Object.entries(groups).forEach(([group, opts]) => {
                items.push({
                    type: 'group',
                    groupName: group,
                });
                opts.forEach((option) => items.push({
                    type: 'option',
                    option,
                }));
            });
            const selectedValue = moveSelectedToTopByGroup(items, selectedOption?.value, selectedOption?.group);
            return selectedValue;
        }
        else {
            const sorted = [
                ...selectOptionList?.filter((option) => getValue(option, valueAccessor) === selectedOption?.value),
                ...selectOptionList?.filter((option) => getValue(option, valueAccessor) !== selectedOption?.value),
            ];
            return sorted.map((option) => ({
                type: 'option',
                option,
            }));
        }
    }, [selectOptionList, selectedOption?.value, valueAccessor, groupBy]);
    const handleKeyDown = (e) => {
        if (!showDropdownOptions)
            return;
        switch (e.key) {
            case 'ArrowDown': {
                e.preventDefault();
                setHighlightedIndex((prev) => {
                    const next = getNextSelectableIndex(sortedOptions, prev + 1, 1);
                    return next;
                });
                break;
            }
            case 'ArrowUp': {
                e.preventDefault();
                setHighlightedIndex((prev) => {
                    const next = getNextSelectableIndex(sortedOptions, prev - 1, -1);
                    return next;
                });
                break;
            }
            case 'Enter': {
                e.preventDefault();
                e.stopPropagation();
                const selectedItem = sortedOptions[highlightedIndex];
                if (selectedItem &&
                    selectedItem.type === 'option' &&
                    !selectedItem.option?.disable) {
                    onSelectOptionSelector(selectedItem.option);
                }
                break;
            }
            case 'Escape': {
                e.preventDefault();
                e.stopPropagation();
                onSelectBlur();
                break;
            }
        }
    };
    const inputElement = (_jsxs(_Fragment, { children: [_jsx("input", { type: "text", ref: inputRef, id: "select-input-element", className: classNames('ff-select-inputField', {
                    'ff-select-inputField__disabled': disabled,
                    'ff-select-inputField__readonly': disableInput,
                    'ff-select-inputField__icon': showIcon && !checkEmpty(searchedIcon),
                    'ff-select-inputField__hasicon': hasInnerClearIcon,
                }), onKeyDown: handleKeyDown, onFocus: handleFocus, value: isTruncated ? displaySearchedText : searchedText, autoCorrect: "off", autoComplete: "off", spellCheck: "false", style: {
                    zIndex: optionZIndex,
                    color: selectedOptionColor,
                }, disabled: disabled, onChange: handleChange, readOnly: disableInput, placeholder: placeHolder }), hasInnerClearIcon && (_jsx("span", { className: "ff-select-clear-icon", children: _jsx(Tooltip, { title: "Clear", children: _jsx(Icon, { name: "close", height: 16, width: 16, onClick: handelClear, hoverEffect: true, cursorType: "pointer" }) }) }))] }));
    return (_jsxs("div", { className: `ff-select-wrapper ${className} ${showClearIcon ? 'show-clear-icon' : ''}`, ref: selectWrapperRef, style: {
            height: `${height}px`,
            width: `${selectWidth}`,
            background: `${background}`,
            borderRadius: `${borderRadius}`,
        }, children: [_jsxs("div", { className: classNames('ff-select', {
                    'ff-select__focus': showDropdownOptions,
                    'ff-select__disabled': disabled,
                    'ff-select__error': !!errorMsg,
                    'ff-select__error__focused': !!errorMsg && showDropdownOptions,
                    'ff-select__no_border': !showBorder,
                }), children: [showIcon && !checkEmpty(searchedIcon) && (_jsx(Tooltip, { placement: "bottom", title: searchedText, children: _jsx(Icon, { name: searchedIcon, color: searchedIconColor, className: "ff-select-input-icon", withPadding: !checkEmpty(searchedText) }) })), tooltip && isTruncated ? (_jsx(Tooltip, { title: searchedText, style: { width: '100%' }, children: inputElement })) : (inputElement), optionsRequired && (_jsx("div", { ref: selectArrowRef, className: classNames('ff-select-arrows-wrapper', {
                            'ff-select-arrows-wrapper__disabled': disabled,
                        }), onClick: handleIconClick, children: showArrowIcon && (_jsx(Icon, { name: "arrow_down", className: "ff-select-arrows", height: 8, width: 12, color: 'var(--brand-color)', "z-index": 9999 })) })), showLabel && (_jsx(Typography, { as: "span", className: classNames('ff-select-labels', {
                            'ff-select-labels__icon': showIcon && !checkEmpty(searchedIcon),
                            'ff-select-labels__active': searchedText,
                        }), fontSize: searchedText || showDropdownOptions ? 10 : 12, lineHeight: searchedText || showDropdownOptions ? '12px' : '16px', required: required, style: {
                            maxWidth: `calc(${selectWidth} - ${hasInnerClearIcon ? '56px' : '40px'})`,
                        }, children: label }))] }), errorMsg && (_jsx(Typography, { as: "div", lineHeight: "15px", fontSize: 10, color: "var(--error_light)", className: "ff-select-error-msg", children: errorMsg })), optionsRequired && (_jsx("div", { ref: DropdownRef, children: showDropdownOptions &&
                    createPortal(_jsx(Dropdown, { options: selectOptionList, dropdownPosition: dropdownPosition, labelAccessor: labelAccessor, optionZIndex: optionZIndex, inputRef: inputRef, selectArrowRef: selectArrowRef, onSelectBlur: onSelectBlur, onSelectOptionSelector: onSelectOptionSelector, heightFromTop: height, selectedOption: selectedOption, showIcon: showIcon, showToolTip: showToolTip, customReccurenece: customRecurrence, onSaveModal: onSaveModal, onCancelModal: () => {
                            onCancelModal();
                            setCustomRecurrence(false);
                        }, modalJSXProps: modalJSXProps, recurrence: recurrence, valueAccessor: valueAccessor, showArrowIcon: showArrowIcon, showClearIcon: showClearIcon, hasInnerClearIcon: hasInnerClearIcon, noResultsMessage: noResultsMessage, ref: dropDownRef, searchedIcon: searchedIcon, dropDownHeight: dropDownHeight, isCustomButtonDisabled: isCustomButtonDisabled, dropdownInnerIconWidth: dropdownInnerIconWidth, highlightedIndex: highlightedIndex, setHighlightedIndex: setHighlightedIndex, sortedOptions: sortedOptions }), document.body) })), showClearIcon && (_jsx(Tooltip, { title: "Cancel", style: { zIndex: 99999 }, children: _jsx(Icon, { name: "close", height: 16, width: 16, onClick: handelClear, hoverEffect: true }) }))] }));
};
export default Select;
//# sourceMappingURL=Select.js.map