import { h, Teleport, ref, inject, watch, computed, provide, onBeforeUnmount, reactive, nextTick, onMounted } from 'vue';
import { defineVxeComponent } from '../../ui/src/comp';
import XEUtils from 'xe-utils';
import { getConfig, getIcon, getI18n, globalEvents, createEvent, renderer, useSize, GLOBAL_EVENT_KEYS, renderEmptyElement } from '../../ui';
import { getEventTargetNode, getPopupContainer, toCssUnit, updatePanelPlacement } from '../../ui/src/dom';
import { getLastZIndex, nextZIndex, getFuncText } from '../../ui/src/utils';
import { getSlotVNs } from '../../ui/src/vn';
import VxeInputComponent from '../../input/src/input';
function createReactData() {
    return {
        initialized: false,
        selectIcon: '',
        panelIndex: 0,
        panelStyle: {},
        panelPlacement: null,
        visiblePanel: false,
        isAniVisible: false,
        isActivated: false,
        searchValue: '',
        iconList: []
    };
}
function createInternalData() {
    return {
        fullList: []
        // hpTimeout: undefined
    };
}
export default defineVxeComponent({
    name: 'VxeIconPicker',
    props: {
        modelValue: String,
        placeholder: String,
        clearable: Boolean,
        size: {
            type: String,
            default: () => getConfig().iconPicker.size || getConfig().size
        },
        className: [String, Function],
        /**
         * 已废弃，请使用 popupConfig.className
         * @deprecated
         */
        popupClassName: [String, Function],
        showIconTitle: {
            type: Boolean,
            default: () => getConfig().iconPicker.showIconTitle
        },
        readonly: {
            type: Boolean,
            default: null
        },
        disabled: {
            type: Boolean,
            default: null
        },
        filterable: {
            type: Boolean,
            default: () => getConfig().iconPicker.filterable
        },
        filterConfig: Object,
        icons: Array,
        placement: String,
        popupConfig: Object,
        transfer: {
            type: Boolean,
            default: null
        }
    },
    emits: [
        'update:modelValue',
        'change',
        'clear',
        'click'
    ],
    setup(props, context) {
        const { emit } = context;
        const $xeModal = inject('$xeModal', null);
        const $xeDrawer = inject('$xeDrawer', null);
        const $xeTable = inject('$xeTable', null);
        const $xeForm = inject('$xeForm', null);
        const formItemInfo = inject('xeFormItemInfo', null);
        const xID = XEUtils.uniqueId();
        const { computeSize } = useSize(props);
        const reactData = reactive(createReactData());
        const internalData = createInternalData();
        const refElem = ref();
        const refInput = ref();
        const refOptionPanel = ref();
        const refInpSearch = ref();
        const refMaps = {
            refElem
        };
        const $xeIconPicker = {
            xID,
            props,
            context,
            reactData,
            getRefMaps: () => refMaps
        };
        let iconPickerMethods = {};
        const computeFormReadonly = computed(() => {
            const { readonly } = props;
            if (readonly === null) {
                if ($xeForm) {
                    return $xeForm.props.readonly;
                }
                return false;
            }
            return readonly;
        });
        const computeIsDisabled = computed(() => {
            const { disabled } = props;
            if (disabled === null) {
                if ($xeForm) {
                    return $xeForm.props.disabled;
                }
                return false;
            }
            return disabled;
        });
        const computeBtnTransfer = computed(() => {
            const { transfer } = props;
            const popupOpts = computePopupOpts.value;
            if (XEUtils.isBoolean(popupOpts.transfer)) {
                return popupOpts.transfer;
            }
            if (transfer === null) {
                const globalTransfer = getConfig().iconPicker.transfer;
                if (XEUtils.isBoolean(globalTransfer)) {
                    return globalTransfer;
                }
                if ($xeTable || $xeModal || $xeDrawer || $xeForm) {
                    return true;
                }
            }
            return transfer;
        });
        const computeInpPlaceholder = computed(() => {
            const { placeholder } = props;
            if (placeholder) {
                return getFuncText(placeholder);
            }
            const globalPlaceholder = getConfig().select.placeholder;
            if (globalPlaceholder) {
                return getFuncText(globalPlaceholder);
            }
            return getI18n('vxe.base.pleaseSelect');
        });
        const computeWrapperStyle = computed(() => {
            const popupOpts = computePopupOpts.value;
            const { chunkSize, height, chunkWidth, maxHeight } = popupOpts;
            const stys = {
                '--vxe-ui-icon-picker-item-width': chunkWidth ? toCssUnit(chunkWidth) : `${100 / (chunkSize || 4)}%`
            };
            if (height) {
                stys['--vxe-ui-icon-picker-panel-height'] = toCssUnit(height);
            }
            if (maxHeight) {
                stys['--vxe-ui-icon-picker-panel-max-height'] = toCssUnit(maxHeight);
            }
            return stys;
        });
        const computeIconList = computed(() => {
            let { icons } = props;
            if (!icons || !icons.length) {
                icons = getConfig().iconPicker.icons || [];
            }
            return icons.map(item => {
                if (XEUtils.isString(item)) {
                    return {
                        title: item,
                        icon: `vxe-icon-${`${item || ''}`.replace(/^vxe-icon-/, '')}`
                    };
                }
                return {
                    title: `${item.title || ''}`,
                    icon: item.icon || '',
                    iconRender: item.iconRender
                };
            });
        });
        const computeFilterOpts = computed(() => {
            return Object.assign({}, getConfig().iconPicker.filterConfig, props.filterConfig);
        });
        const computePopupOpts = computed(() => {
            return Object.assign({}, getConfig().iconPicker.popupConfig, props.popupConfig);
        });
        const computeSelectIconItem = computed(() => {
            const { selectIcon } = reactData;
            const iconList = computeIconList.value;
            return selectIcon ? iconList.find(item => item.icon === selectIcon) : null;
        });
        const updateZindex = () => {
            if (reactData.panelIndex < getLastZIndex()) {
                reactData.panelIndex = nextZIndex();
            }
        };
        const updatePlacement = () => {
            const { placement } = props;
            const { panelIndex } = reactData;
            const targetElem = refElem.value;
            const panelElem = refOptionPanel.value;
            const btnTransfer = computeBtnTransfer.value;
            const popupOpts = computePopupOpts.value;
            const { width } = popupOpts;
            const handleStyle = () => {
                const ppObj = updatePanelPlacement(targetElem, panelElem, {
                    placement: popupOpts.placement || placement,
                    defaultPlacement: popupOpts.defaultPlacement,
                    teleportTo: btnTransfer
                });
                const panelStyle = Object.assign(ppObj.style, {
                    zIndex: panelIndex,
                    minWidth: undefined
                });
                if (width) {
                    Object.assign(panelStyle, {
                        width: toCssUnit(width)
                    });
                }
                reactData.panelStyle = panelStyle;
                reactData.panelPlacement = ppObj.placement;
            };
            handleStyle();
            return nextTick().then(handleStyle);
        };
        const showOptionPanel = () => {
            const { hpTimeout } = internalData;
            const isDisabled = computeIsDisabled.value;
            if (!isDisabled) {
                if (hpTimeout) {
                    clearTimeout(hpTimeout);
                    internalData.hpTimeout = undefined;
                }
                if (!reactData.initialized) {
                    reactData.initialized = true;
                }
                reactData.isActivated = true;
                reactData.isAniVisible = true;
                setTimeout(() => {
                    reactData.visiblePanel = true;
                    handleFocusSearch();
                    updatePlacement();
                }, 10);
                updateZindex();
                updatePlacement();
            }
        };
        const hideOptionPanel = () => {
            reactData.visiblePanel = false;
            internalData.hpTimeout = setTimeout(() => {
                reactData.isAniVisible = false;
            }, 350);
        };
        const handleFocusSearch = () => {
            if (props.filterable) {
                nextTick(() => {
                    const inpSearch = refInpSearch.value;
                    if (inpSearch) {
                        inpSearch.focus();
                    }
                });
            }
        };
        const handleData = () => {
            const { modelValue } = props;
            const { searchValue } = reactData;
            const filterOpts = computeFilterOpts.value;
            const { filterMethod } = filterOpts;
            const iconList = computeIconList.value;
            let visibleList = iconList;
            if (searchValue) {
                const searchTxt = `${searchValue}`.toLowerCase();
                visibleList = iconList.filter(item => {
                    if (filterMethod) {
                        return filterMethod({ option: item, value: modelValue, searchValue: searchTxt, $iconPicker: $xeIconPicker });
                    }
                    return (item.title && `${item.title}`.toLowerCase().indexOf(searchTxt) > -1) || (item.icon && `${item.icon}`.indexOf(searchTxt) > -1);
                });
            }
            reactData.iconList = visibleList;
        };
        const changeEvent = (evnt, selectValue) => {
            reactData.selectIcon = selectValue;
            if (selectValue !== props.modelValue) {
                emit('update:modelValue', selectValue);
                dispatchEvent('change', { value: selectValue }, evnt);
                // 自动更新校验状态
                if ($xeForm && formItemInfo) {
                    $xeForm.triggerItemEvent(evnt, formItemInfo.itemConfig.field, selectValue);
                }
            }
        };
        const focusEvent = () => {
            const isDisabled = computeIsDisabled.value;
            if (!isDisabled) {
                if (!reactData.visiblePanel) {
                    showOptionPanel();
                }
            }
        };
        const blurEvent = () => {
            reactData.isActivated = false;
        };
        const clearValueEvent = (evnt, selectValue) => {
            changeEvent(evnt, selectValue);
            dispatchEvent('clear', { value: selectValue }, evnt);
        };
        const clearEvent = (params, evnt) => {
            clearValueEvent(evnt, null);
            hideOptionPanel();
        };
        const togglePanelEvent = (evnt) => {
            evnt.preventDefault();
            if (reactData.visiblePanel) {
                hideOptionPanel();
            }
            else {
                showOptionPanel();
            }
        };
        const clickEvent = (evnt) => {
            togglePanelEvent(evnt);
            dispatchEvent('click', {}, evnt);
        };
        const handleGlobalMousewheelEvent = (evnt) => {
            const { visiblePanel } = reactData;
            const isDisabled = computeIsDisabled.value;
            if (!isDisabled) {
                if (visiblePanel) {
                    const panelElem = refOptionPanel.value;
                    if (getEventTargetNode(evnt, panelElem).flag) {
                        updatePlacement();
                    }
                    else {
                        hideOptionPanel();
                    }
                }
            }
        };
        const handleGlobalMousedownEvent = (evnt) => {
            const { visiblePanel } = reactData;
            const isDisabled = computeIsDisabled.value;
            if (!isDisabled) {
                const el = refElem.value;
                const panelElem = refOptionPanel.value;
                reactData.isActivated = getEventTargetNode(evnt, el).flag || getEventTargetNode(evnt, panelElem).flag;
                if (visiblePanel && !reactData.isActivated) {
                    hideOptionPanel();
                }
            }
        };
        const handleGlobalKeydownEvent = (evnt) => {
            const { clearable } = props;
            const { visiblePanel } = reactData;
            const isDisabled = computeIsDisabled.value;
            if (!isDisabled) {
                const isTab = globalEvents.hasKey(evnt, GLOBAL_EVENT_KEYS.TAB);
                const isEnter = globalEvents.hasKey(evnt, GLOBAL_EVENT_KEYS.ENTER);
                const isEsc = globalEvents.hasKey(evnt, GLOBAL_EVENT_KEYS.ESCAPE);
                const isUpArrow = globalEvents.hasKey(evnt, GLOBAL_EVENT_KEYS.ARROW_UP);
                const isDwArrow = globalEvents.hasKey(evnt, GLOBAL_EVENT_KEYS.ARROW_DOWN);
                const isDel = globalEvents.hasKey(evnt, GLOBAL_EVENT_KEYS.DELETE);
                const isSpacebar = globalEvents.hasKey(evnt, GLOBAL_EVENT_KEYS.SPACEBAR);
                if (isTab) {
                    reactData.isActivated = false;
                }
                if (visiblePanel) {
                    if (isEsc || isTab) {
                        hideOptionPanel();
                    }
                    else if (isEnter) {
                        evnt.preventDefault();
                        evnt.stopPropagation();
                        // changeOptionEvent(evnt, currentValue, currentOption)
                    }
                    else if (isUpArrow || isDwArrow) {
                        evnt.preventDefault();
                        // let { firstOption, offsetOption } = findOffsetOption(currentValue, isUpArrow)
                        // if (!offsetOption && !findVisibleOption(currentValue)) {
                        //   offsetOption = firstOption
                        // }
                        // setCurrentOption(offsetOption)
                        // scrollToOption(offsetOption, isDwArrow)
                    }
                    else if (isSpacebar) {
                        evnt.preventDefault();
                    }
                }
                else if ((isUpArrow || isDwArrow || isEnter || isSpacebar) && reactData.isActivated) {
                    evnt.preventDefault();
                    showOptionPanel();
                }
                if (reactData.isActivated) {
                    if (isDel && clearable) {
                        clearValueEvent(evnt, null);
                    }
                }
            }
        };
        const handleGlobalBlurEvent = () => {
            const { visiblePanel, isActivated } = reactData;
            if (visiblePanel) {
                hideOptionPanel();
            }
            if (isActivated) {
                reactData.isActivated = false;
            }
            if (visiblePanel || isActivated) {
                const $input = refInput.value;
                if ($input) {
                    $input.blur();
                }
            }
        };
        const dispatchEvent = (type, params, evnt) => {
            emit(type, createEvent(evnt, { $iconPicker: $xeIconPicker }, params));
        };
        iconPickerMethods = {
            dispatchEvent,
            isPanelVisible() {
                return reactData.visiblePanel;
            },
            togglePanel() {
                if (reactData.visiblePanel) {
                    hideOptionPanel();
                }
                else {
                    showOptionPanel();
                }
                return nextTick();
            },
            hidePanel() {
                if (reactData.visiblePanel) {
                    hideOptionPanel();
                }
                return nextTick();
            },
            showPanel() {
                if (!reactData.visiblePanel) {
                    showOptionPanel();
                }
                return nextTick();
            },
            focus() {
                const $input = refInput.value;
                reactData.isActivated = true;
                if ($input) {
                    $input.blur();
                }
                return nextTick();
            },
            blur() {
                const $input = refInput.value;
                if ($input) {
                    $input.blur();
                }
                reactData.isActivated = false;
                return nextTick();
            }
        };
        const handleClickIconEvent = (evnt, item) => {
            const value = item.icon;
            changeEvent(evnt, value);
            hideOptionPanel();
        };
        const modelSearchEvent = (value) => {
            reactData.searchValue = value;
        };
        const focusSearchEvent = () => {
            reactData.isActivated = true;
        };
        const handleSearchEvent = () => {
            handleData();
        };
        const triggerSearchEvent = XEUtils.debounce(handleSearchEvent, 350, { trailing: true });
        Object.assign($xeIconPicker, iconPickerMethods);
        const renderIconWrapper = () => {
            const { showIconTitle } = props;
            const { selectIcon, iconList } = reactData;
            if (!iconList.length) {
                return h('div', {
                    class: 'vxe-ico-picker--empty-placeholder'
                }, getI18n('vxe.iconPicker.emptyText'));
            }
            return h('div', {
                class: 'vxe-ico-picker--list-wrapper'
            }, [
                h('div', {
                    class: 'vxe-ico-picker--list'
                }, iconList.map(item => {
                    const { iconRender } = item;
                    const compConf = iconRender ? renderer.get(iconRender.name) : null;
                    const iconMethod = compConf ? compConf.renderIconPickerOptionIcon : null;
                    return h('div', {
                        class: ['vxe-ico-picker--item', {
                                'is--selected': selectIcon === item.icon
                            }]
                    }, [
                        h('div', {
                            class: 'vxe-ico-picker--item-inner',
                            onClick(evnt) {
                                const isDisabled = computeIsDisabled.value;
                                if (!isDisabled) {
                                    handleClickIconEvent(evnt, item);
                                }
                            }
                        }, [
                            h('div', {
                                class: 'vxe-ico-picker--item-icon'
                            }, iconMethod && iconRender
                                ? getSlotVNs(iconMethod(iconRender, { $iconPicker: $xeIconPicker, option: item }))
                                : [
                                    h('i', {
                                        class: item.icon || ''
                                    })
                                ]),
                            showIconTitle
                                ? h('div', {
                                    class: 'vxe-ico-picker--item-title'
                                }, `${item.title || ''}`)
                                : renderEmptyElement($xeIconPicker)
                        ])
                    ]);
                }))
            ]);
        };
        const renderIconView = () => {
            const { selectIcon } = reactData;
            const selectIconItem = computeSelectIconItem.value;
            if (selectIconItem) {
                const { iconRender } = selectIconItem;
                const compConf = iconRender ? renderer.get(iconRender.name) : null;
                const oIconMethod = compConf ? compConf.renderIconPickerOptionIcon : null;
                if (oIconMethod && iconRender) {
                    return h('div', {
                        key: 'inc',
                        class: 'vxe-ico-picker--icon'
                    }, getSlotVNs(oIconMethod(iconRender, { $iconPicker: $xeIconPicker, option: selectIconItem })));
                }
            }
            return h('div', {
                key: 'ind',
                class: 'vxe-ico-picker--icon'
            }, [
                h('i', {
                    class: selectIcon
                })
            ]);
        };
        const renderVN = () => {
            const { className, clearable, filterable } = props;
            const { initialized, isActivated, isAniVisible, visiblePanel, selectIcon } = reactData;
            const vSize = computeSize.value;
            const isDisabled = computeIsDisabled.value;
            const btnTransfer = computeBtnTransfer.value;
            const formReadonly = computeFormReadonly.value;
            const inpPlaceholder = computeInpPlaceholder.value;
            const wrapperStyle = computeWrapperStyle.value;
            const popupOpts = computePopupOpts.value;
            const { appendTo } = popupOpts;
            const ppClassName = popupOpts.className || props.popupClassName;
            if (formReadonly) {
                return h('div', {
                    ref: refElem,
                    class: ['vxe-ico-picker--readonly', className]
                }, [
                    h('i', {
                        class: selectIcon
                    })
                ]);
            }
            return h('div', {
                ref: refElem,
                class: ['vxe-ico-picker', className ? (XEUtils.isFunction(className) ? className({ $iconPicker: $xeIconPicker }) : className) : '', {
                        [`size--${vSize}`]: vSize,
                        'show--clear': clearable && !isDisabled && !!selectIcon,
                        'is--visible': visiblePanel,
                        'is--disabled': isDisabled,
                        'is--active': isActivated
                    }]
            }, [
                h('div', {
                    class: 'vxe-ico-picker--inner',
                    onClick: clickEvent
                }, [
                    h('input', {
                        ref: refInput,
                        class: 'vxe-ico-picker--input',
                        onFocus: focusEvent,
                        onBlur: blurEvent
                    }),
                    selectIcon
                        ? renderIconView()
                        : h('div', {
                            class: 'vxe-ico-picker--placeholder'
                        }, inpPlaceholder),
                    h('div', {
                        class: 'vxe-ico-picker--suffix'
                    }, [
                        h('div', {
                            class: 'vxe-ico-picker--clear-icon',
                            onClick: clearEvent
                        }, [
                            h('i', {
                                class: getIcon().INPUT_CLEAR
                            })
                        ]),
                        h('div', {
                            class: 'vxe-ico-picker--suffix-icon'
                        }, [
                            h('i', {
                                class: visiblePanel ? getIcon().ICON_PICKER_OPEN : getIcon().ICON_PICKER_CLOSE
                            })
                        ])
                    ])
                ]),
                h(Teleport, {
                    to: getPopupContainer(appendTo),
                    disabled: btnTransfer ? !initialized : true
                }, [
                    h('div', {
                        ref: refOptionPanel,
                        class: ['vxe-table--ignore-clear vxe-ico-picker--panel', ppClassName ? (XEUtils.isFunction(ppClassName) ? ppClassName({ $iconPicker: $xeIconPicker }) : ppClassName) : '', {
                                [`size--${vSize}`]: vSize,
                                'is--transfer': btnTransfer,
                                'ani--leave': isAniVisible,
                                'ani--enter': visiblePanel
                            }],
                        placement: reactData.panelPlacement,
                        style: reactData.panelStyle
                    }, [
                        initialized && (visiblePanel || isAniVisible)
                            ? h('div', {
                                class: 'vxe-ico-picker--panel-wrapper',
                                style: wrapperStyle
                            }, [
                                filterable
                                    ? h('div', {
                                        class: 'vxe-ico-picker--panel-search'
                                    }, [
                                        h(VxeInputComponent, {
                                            ref: refInpSearch,
                                            class: 'vxe-ico-picker-search--input',
                                            modelValue: reactData.searchValue,
                                            type: 'text',
                                            clearable: true,
                                            disabled: false,
                                            readonly: false,
                                            placeholder: getI18n('vxe.iconPicker.search'),
                                            prefixIcon: getIcon().INPUT_SEARCH,
                                            'onUpdate:modelValue': modelSearchEvent,
                                            onFocus: focusSearchEvent,
                                            onChange: triggerSearchEvent,
                                            onSearch: triggerSearchEvent
                                        })
                                    ])
                                    : renderEmptyElement($xeIconPicker),
                                renderIconWrapper()
                            ])
                            : renderEmptyElement($xeIconPicker)
                    ])
                ])
            ]);
        };
        reactData.selectIcon = `${props.modelValue || ''}`;
        handleData();
        watch(() => props.modelValue, (val) => {
            reactData.selectIcon = `${val || ''}`;
        });
        watch(computeIconList, () => {
            handleData();
        });
        onMounted(() => {
            globalEvents.on($xeIconPicker, 'mousewheel', handleGlobalMousewheelEvent);
            globalEvents.on($xeIconPicker, 'mousedown', handleGlobalMousedownEvent);
            globalEvents.on($xeIconPicker, 'keydown', handleGlobalKeydownEvent);
            globalEvents.on($xeIconPicker, 'blur', handleGlobalBlurEvent);
        });
        onBeforeUnmount(() => {
            globalEvents.off($xeIconPicker, 'mousewheel');
            globalEvents.off($xeIconPicker, 'mousedown');
            globalEvents.off($xeIconPicker, 'keydown');
            globalEvents.off($xeIconPicker, 'blur');
            XEUtils.assign(reactData, createReactData());
            XEUtils.assign(internalData, createInternalData());
        });
        provide('$xeIconPicker', $xeIconPicker);
        $xeIconPicker.renderVN = renderVN;
        return $xeIconPicker;
    },
    render() {
        return this.renderVN();
    }
});
