import { defineVxeComponent } from '../../ui/src/comp';
import XEUtils from 'xe-utils';
import { getConfig, globalEvents, createEvent, globalMixins, renderEmptyElement } from '../../ui';
import { getEventTargetNode, updatePanelPlacement } from '../../ui/src/dom';
import { getLastZIndex, nextZIndex } from '../../ui/src/utils';
export default {
    name: 'VxePulldown',
    model: {
        prop: 'value',
        event: 'modelValue'
    },
    mixins: [
        globalMixins.sizeMixin,
        globalMixins.permissionMixin
    ],
    props: {
        value: Boolean,
        disabled: Boolean,
        placement: String,
        /**
         * 已废弃，请使用 popup-config.trigger
         * @deprecated
         */
        trigger: {
            type: String,
            default: () => getConfig().pulldown.trigger
        },
        /**
         * 已废弃，请使用 popupConfig.zIndex
         * @deprecated
         */
        zIndex: Number,
        size: {
            type: String,
            default: () => getConfig().pulldown.size || getConfig().size
        },
        options: Array,
        className: {
            type: [String, Function],
            default: () => getConfig().pulldown.className
        },
        /**
         * 已废弃，请使用 popupConfig.className
         * @deprecated
         */
        popupClassName: [String, Function],
        showPopupShadow: Boolean,
        popupConfig: Object,
        destroyOnClose: {
            type: Boolean,
            default: () => getConfig().pulldown.destroyOnClose
        },
        transfer: {
            type: Boolean,
            default: null
        }
    },
    inject: {
        $xeModal: {
            default: null
        },
        $xeDrawer: {
            default: null
        },
        $xeTable: {
            default: null
        },
        $xeForm: {
            default: null
        }
    },
    data() {
        const xID = XEUtils.uniqueId();
        const reactData = {
            initialized: false,
            panelIndex: 0,
            panelStyle: {},
            panelPlacement: null,
            visiblePanel: false,
            isAniVisible: false,
            isActivated: false
        };
        const internalData = {
            hpTimeout: undefined
        };
        return {
            xID,
            reactData,
            internalData
        };
    },
    computed: Object.assign(Object.assign({}, {}), { computeBtnTransfer() {
            const $xePulldown = this;
            const props = $xePulldown;
            const $xeModal = $xePulldown.$xeModal;
            const $xeDrawer = $xePulldown.$xeDrawer;
            const $xeTable = $xePulldown.$xeTable;
            const $xeForm = $xePulldown.$xeForm;
            const { transfer } = props;
            const popupOpts = $xePulldown.computePopupOpts;
            if (XEUtils.isBoolean(popupOpts.transfer)) {
                return popupOpts.transfer;
            }
            if (transfer === null) {
                const globalTransfer = getConfig().pulldown.transfer;
                if (XEUtils.isBoolean(globalTransfer)) {
                    return globalTransfer;
                }
                if ($xeTable || $xeModal || $xeDrawer || $xeForm) {
                    return true;
                }
            }
            return transfer;
        },
        computePopupOpts() {
            const $xePulldown = this;
            const props = $xePulldown;
            return Object.assign({}, getConfig().pulldown.popupConfig, props.popupConfig);
        } }),
    methods: {
        //
        // Method
        //
        dispatchEvent(type, params, evnt) {
            const $xePulldown = this;
            $xePulldown.$emit(type, createEvent(evnt, { $pulldown: $xePulldown }, params));
        },
        emitModel(value) {
            const $xePulldown = this;
            const { _events } = $xePulldown;
            if (_events && _events.modelValue) {
                $xePulldown.$emit('modelValue', value);
            }
            else {
                $xePulldown.$emit('model-value', value);
            }
        },
        updateZindex() {
            const $xePulldown = this;
            const props = $xePulldown;
            const reactData = $xePulldown.reactData;
            const popupOpts = $xePulldown.computePopupOpts;
            const customZIndex = popupOpts.zIndex || props.zIndex;
            if (customZIndex) {
                reactData.panelIndex = XEUtils.toNumber(customZIndex);
            }
            else if (reactData.panelIndex < getLastZIndex()) {
                reactData.panelIndex = nextZIndex();
            }
        },
        isPanelVisible() {
            const $xePulldown = this;
            const reactData = $xePulldown.reactData;
            return reactData.visiblePanel;
        },
        /**
         * 手动更新位置
         */
        updatePlacement() {
            const $xePulldown = this;
            const props = $xePulldown;
            const reactData = $xePulldown.reactData;
            const { placement } = props;
            const { panelIndex } = reactData;
            const targetElem = $xePulldown.$refs.refPulldownContent;
            const panelElem = $xePulldown.$refs.refPulldownPanel;
            const btnTransfer = $xePulldown.computeBtnTransfer;
            const popupOpts = $xePulldown.computePopupOpts;
            const handleStyle = () => {
                const ppObj = updatePanelPlacement(targetElem, panelElem, {
                    placement: popupOpts.placement || placement,
                    defaultPlacement: popupOpts.defaultPlacement,
                    teleportTo: btnTransfer
                });
                const panelStyle = Object.assign(ppObj.style, {
                    zIndex: panelIndex
                });
                reactData.panelStyle = panelStyle;
                reactData.panelPlacement = ppObj.placement;
            };
            handleStyle();
            return $xePulldown.$nextTick().then(handleStyle);
        },
        /**
         * 显示下拉面板
         */
        showPanel() {
            const $xePulldown = this;
            const props = $xePulldown;
            const reactData = $xePulldown.reactData;
            const internalData = $xePulldown.internalData;
            const btnTransfer = $xePulldown.computeBtnTransfer;
            const panelElem = $xePulldown.$refs.refPulldownPanel;
            if (!reactData.initialized) {
                reactData.initialized = true;
                if (btnTransfer) {
                    if (panelElem) {
                        document.body.appendChild(panelElem);
                    }
                }
            }
            return new Promise(resolve => {
                if (!props.disabled) {
                    if (internalData.hpTimeout) {
                        clearTimeout(internalData.hpTimeout);
                    }
                    reactData.isActivated = true;
                    reactData.isAniVisible = true;
                    setTimeout(() => {
                        reactData.visiblePanel = true;
                        $xePulldown.emitModel(true);
                        $xePulldown.updatePlacement();
                        setTimeout(() => {
                            resolve($xePulldown.updatePlacement());
                        }, 40);
                    }, 10);
                    $xePulldown.updateZindex();
                    $xePulldown.dispatchEvent('visible-change', { visible: true }, null);
                }
                else {
                    $xePulldown.$nextTick(() => {
                        resolve();
                    });
                }
            });
        },
        /**
         * 隐藏下拉面板
         */
        hidePanel() {
            const $xePulldown = this;
            return $xePulldown.hideOptionPanel();
        },
        hideOptionPanel() {
            const $xePulldown = this;
            const reactData = $xePulldown.reactData;
            const internalData = $xePulldown.internalData;
            reactData.visiblePanel = false;
            $xePulldown.dispatchEvent('visible-change', { visible: false }, null);
            $xePulldown.emitModel(false);
            return new Promise(resolve => {
                if (reactData.isAniVisible) {
                    internalData.hpTimeout = setTimeout(() => {
                        reactData.isAniVisible = false;
                        $xePulldown.$nextTick(() => {
                            resolve();
                        });
                    }, 350);
                }
                else {
                    $xePulldown.$nextTick(() => {
                        resolve();
                    });
                }
            });
        },
        /**
         * 切换下拉面板
         */
        togglePanel() {
            const $xePulldown = this;
            const reactData = $xePulldown.reactData;
            if (reactData.visiblePanel) {
                return $xePulldown.hideOptionPanel();
            }
            return $xePulldown.showPanel();
        },
        handleOptionEvent(evnt, option) {
            const $xePulldown = this;
            const reactData = $xePulldown.reactData;
            if (!option.disabled) {
                if (reactData.visiblePanel) {
                    $xePulldown.hideOptionPanel();
                    $xePulldown.dispatchEvent('hide-panel', {}, evnt);
                }
                $xePulldown.dispatchEvent('option-click', { option }, evnt);
            }
        },
        clickTargetEvent(evnt) {
            const $xePulldown = this;
            const props = $xePulldown;
            const reactData = $xePulldown.reactData;
            const { trigger } = props;
            const popupOpts = $xePulldown.computePopupOpts;
            const currTrigger = trigger || popupOpts.trigger;
            if (currTrigger === 'click') {
                if (reactData.visiblePanel) {
                    $xePulldown.hideOptionPanel();
                    $xePulldown.dispatchEvent('hide-panel', {}, evnt);
                }
                else {
                    $xePulldown.showPanel();
                    $xePulldown.dispatchEvent('show-panel', {}, evnt);
                }
            }
            $xePulldown.dispatchEvent('click', { $pulldown: $xePulldown }, evnt);
        },
        handleGlobalMousewheelEvent(evnt) {
            const $xePulldown = this;
            const props = $xePulldown;
            const reactData = $xePulldown.reactData;
            const { trigger, disabled } = props;
            const { visiblePanel } = reactData;
            const popupOpts = $xePulldown.computePopupOpts;
            const currTrigger = trigger || popupOpts.trigger;
            const panelElem = $xePulldown.$refs.refPulldownPanel;
            if (!disabled) {
                if (visiblePanel) {
                    if (getEventTargetNode(evnt, panelElem).flag) {
                        $xePulldown.updatePlacement();
                    }
                    else {
                        if (currTrigger !== 'manual') {
                            $xePulldown.hideOptionPanel();
                            $xePulldown.dispatchEvent('hide-panel', {}, evnt);
                        }
                    }
                }
            }
        },
        handleGlobalMousedownEvent(evnt) {
            const $xePulldown = this;
            const props = $xePulldown;
            const reactData = $xePulldown.reactData;
            const { trigger, disabled } = props;
            const { visiblePanel } = reactData;
            const popupOpts = $xePulldown.computePopupOpts;
            const currTrigger = trigger || popupOpts.trigger;
            const el = $xePulldown.$refs.refElem;
            const panelElem = $xePulldown.$refs.refPulldownPanel;
            if (!disabled) {
                reactData.isActivated = getEventTargetNode(evnt, el).flag || getEventTargetNode(evnt, panelElem).flag;
                if (visiblePanel && !reactData.isActivated) {
                    if (currTrigger !== 'manual') {
                        $xePulldown.hideOptionPanel();
                        $xePulldown.dispatchEvent('hide-panel', {}, evnt);
                    }
                }
            }
        },
        handleGlobalBlurEvent(evnt) {
            const $xePulldown = this;
            const props = $xePulldown;
            const reactData = $xePulldown.reactData;
            const { trigger } = props;
            const { visiblePanel, isActivated } = reactData;
            const popupOpts = $xePulldown.computePopupOpts;
            const currTrigger = trigger || popupOpts.trigger;
            if (visiblePanel) {
                if (currTrigger !== 'manual') {
                    $xePulldown.hideOptionPanel();
                    $xePulldown.dispatchEvent('hide-panel', {}, evnt);
                }
            }
            if (isActivated) {
                reactData.isActivated = false;
            }
        },
        handleGlobalResizeEvent() {
            const $xePulldown = this;
            const reactData = $xePulldown.reactData;
            const { visiblePanel } = reactData;
            if (visiblePanel) {
                $xePulldown.updatePlacement();
            }
        },
        //
        // Render
        //
        renderDefaultPanel(h, options) {
            const $xePulldown = this;
            const slots = $xePulldown.$scopedSlots;
            const optionSlot = slots.option;
            return h('div', {
                class: 'vxe-pulldown--panel-list'
            }, options
                ? options.map(item => {
                    return h('div', {
                        class: 'vxe-pulldown--panel-item',
                        on: {
                            click(evnt) {
                                $xePulldown.handleOptionEvent(evnt, item);
                            }
                        }
                    }, optionSlot ? optionSlot({ $pulldown: $xePulldown, option: item }) : `${item.label || ''}`);
                })
                : []);
        },
        renderVN(h) {
            const $xePulldown = this;
            const props = $xePulldown;
            const slots = $xePulldown.$scopedSlots;
            const reactData = $xePulldown.reactData;
            const { className, options, showPopupShadow, destroyOnClose, disabled } = props;
            const { initialized, isActivated, isAniVisible, visiblePanel, panelStyle, panelPlacement } = reactData;
            const btnTransfer = $xePulldown.computeBtnTransfer;
            const popupOpts = $xePulldown.computePopupOpts;
            const vSize = $xePulldown.computeSize;
            const defaultSlot = slots.default;
            const headerSlot = slots.header;
            const footerSlot = slots.footer;
            const dropdownSlot = slots.dropdown;
            const ppClassName = popupOpts.className || props.popupClassName;
            return h('div', {
                ref: 'refElem',
                class: ['vxe-pulldown', className ? (XEUtils.isFunction(className) ? className({ $pulldown: $xePulldown }) : className) : '', {
                        [`size--${vSize}`]: vSize,
                        'is--visible': visiblePanel,
                        'is--disabled': disabled,
                        'is--active': isActivated
                    }]
            }, [
                h('div', {
                    ref: 'refPulldownContent',
                    class: 'vxe-pulldown--content',
                    on: {
                        click: $xePulldown.clickTargetEvent
                    }
                }, defaultSlot ? defaultSlot({ options, $pulldown: $xePulldown }) : []),
                h('div', {
                    ref: 'refPulldownPanel',
                    class: ['vxe-table--ignore-clear vxe-pulldown--panel', ppClassName ? (XEUtils.isFunction(ppClassName) ? ppClassName({ $pulldown: $xePulldown }) : ppClassName) : '', {
                            [`size--${vSize}`]: vSize,
                            'is--transfer': btnTransfer,
                            'ani--leave': isAniVisible,
                            'ani--enter': visiblePanel
                        }],
                    attrs: {
                        placement: panelPlacement
                    },
                    style: panelStyle
                }, initialized
                    ? [
                        h('div', {
                            class: ['vxe-pulldown--panel-wrapper', {
                                    'is--shadow': showPopupShadow
                                }]
                        }, initialized && (destroyOnClose ? (visiblePanel || isAniVisible) : true)
                            ? [
                                headerSlot
                                    ? h('div', {
                                        class: 'vxe-pulldown--panel-header'
                                    }, headerSlot({ options, $pulldown: $xePulldown }))
                                    : renderEmptyElement($xePulldown),
                                h('div', {
                                    class: 'vxe-pulldown--panel-body'
                                }, dropdownSlot
                                    ? dropdownSlot({ options, $pulldown: $xePulldown })
                                    : [
                                        $xePulldown.renderDefaultPanel(h, options)
                                    ]),
                                footerSlot
                                    ? h('div', {
                                        class: 'vxe-pulldown--panel-footer'
                                    }, footerSlot({ options, $pulldown: $xePulldown }))
                                    : renderEmptyElement($xePulldown)
                            ]
                            : [])
                    ]
                    : [])
            ]);
        }
    },
    watch: {
        value(val) {
            const $xePulldown = this;
            const reactData = $xePulldown.reactData;
            reactData.isActivated = !!val;
            if (val) {
                $xePulldown.showPanel();
            }
            else {
                $xePulldown.hideOptionPanel();
            }
        }
    },
    created() {
        const $xePulldown = this;
        const props = $xePulldown;
        if (props.value) {
            $xePulldown.showPanel();
        }
        globalEvents.on($xePulldown, 'mousewheel', $xePulldown.handleGlobalMousewheelEvent);
        globalEvents.on($xePulldown, 'mousedown', $xePulldown.handleGlobalMousedownEvent);
        globalEvents.on($xePulldown, 'blur', $xePulldown.handleGlobalBlurEvent);
        globalEvents.on($xePulldown, 'resize', $xePulldown.handleGlobalResizeEvent);
    },
    beforeDestroy() {
        const $xePulldown = this;
        const panelElem = $xePulldown.$refs.refPulldownPanel;
        if (panelElem && panelElem.parentNode) {
            panelElem.parentNode.removeChild(panelElem);
        }
        globalEvents.off($xePulldown, 'mousewheel');
        globalEvents.off($xePulldown, 'mousedown');
        globalEvents.off($xePulldown, 'blur');
        globalEvents.off($xePulldown, 'resize');
    },
    render(h) {
        return this.renderVN(h);
    }
};
