import { h, ref, toRef, computed, defineComponent, provide, inject } from 'vue';
import { createTreeMate } from 'treemate';
import { useCompitable, useMergedState } from 'vooks';
import { useConfig, useTheme } from '../../_mixins';
import { call, warn } from '../../_utils';
import { itemRenderer } from './utils';
import { menuLight } from '../styles';
import style from './styles/index.cssr';
import { layoutSiderInjectionKey } from '../../layout/src/interface';
const menuProps = Object.assign(Object.assign({}, useTheme.props), { options: {
        type: Array,
        default: () => []
    }, items: {
        type: Array,
        validator: () => {
            if (process.env.NODE_ENV !== 'production') {
                warn('menu', '`items` is deprecated, please use `options` instead.');
            }
            return true;
        },
        default: undefined
    }, collapsed: {
        type: Boolean,
        default: undefined
    }, collapsedWidth: {
        type: Number,
        default: 48
    }, iconSize: {
        type: Number,
        default: 20
    }, collapsedIconSize: {
        type: Number,
        default: 24
    }, rootIndent: Number, indent: {
        type: Number,
        default: 32
    }, defaultExpandAll: Boolean, defaultExpandedKeys: {
        type: Array,
        default: () => []
    }, expandedKeys: {
        type: Array,
        default: undefined
    }, value: [String, Number], defaultValue: {
        type: [String, Number],
        default: null
    }, mode: {
        type: String,
        default: 'vertical'
    }, disabled: Boolean, inverted: Boolean, 'onUpdate:expandedKeys': [Function, Array], onUpdateExpandedKeys: [Function, Array], onUpdateValue: [Function, Array], 'onUpdate:value': [Function, Array], 
    // deprecated
    onOpenNamesChange: {
        type: [Function, Array],
        validator: () => {
            warn('menu', '`on-open-names-change` is deprecated, please use `on-update:expanded-keys` instead.');
            return true;
        },
        default: undefined
    }, onSelect: {
        type: [Function, Array],
        validator: () => {
            warn('menu', '`on-select` is deprecated, please use `on-update:value` instead.');
            return true;
        },
        default: undefined
    }, onExpandedNamesChange: {
        type: [Function, Array],
        validator: () => {
            warn('menu', '`on-expanded-names-change` is deprecated, please use `on-update:expanded-keys` instead.');
            return true;
        },
        default: undefined
    }, expandedNames: {
        type: Array,
        validator: () => {
            warn('menu', '`expanded-names` is deprecated, please use `expanded-keys` instead.');
            return true;
        },
        default: undefined
    }, defaultExpandedNames: {
        type: Array,
        validator: () => {
            warn('menu', '`default-expanded-names` is deprecated, please use `default-expanded-keys` instead.');
            return true;
        },
        default: undefined
    } });
export const menuInjectionKey = Symbol('menu');
export default defineComponent({
    name: 'Menu',
    props: menuProps,
    setup(props) {
        const { mergedClsPrefixRef } = useConfig(props);
        const themeRef = useTheme('Menu', 'Menu', style, menuLight, props, mergedClsPrefixRef);
        const layoutSider = inject(layoutSiderInjectionKey, null);
        const mergedCollapsedRef = computed(() => {
            var _a;
            const { collapsed } = props;
            if (collapsed !== undefined)
                return collapsed;
            if (layoutSider) {
                const { collapseModeRef, collapsedRef } = layoutSider;
                if (collapseModeRef.value === 'width') {
                    return (_a = collapsedRef.value) !== null && _a !== void 0 ? _a : false;
                }
            }
            return false;
        });
        const treeMateRef = computed(() => createTreeMate(props.items || props.options, {
            getKey(node) {
                var _a;
                return (_a = node.key) !== null && _a !== void 0 ? _a : node.name;
            }
        }));
        const uncontrolledExpandedKeysRef = ref(props.defaultExpandAll
            ? treeMateRef.value.getNonLeafKeys()
            : props.defaultExpandedNames || props.defaultExpandedKeys);
        const controlledExpandedKeysRef = useCompitable(props, [
            'expandedNames',
            'expandedKeys'
        ]);
        const mergedExpandedKeysRef = useMergedState(controlledExpandedKeysRef, uncontrolledExpandedKeysRef);
        const uncontrolledValueRef = ref(props.defaultValue);
        const controlledValueRef = toRef(props, 'value');
        const mergedValueRef = useMergedState(controlledValueRef, uncontrolledValueRef);
        const tmNodesRef = computed(() => treeMateRef.value.treeNodes);
        const activePathRef = computed(() => {
            return treeMateRef.value.getPath(mergedValueRef.value).keyPath;
        });
        provide(menuInjectionKey, {
            props,
            mergedCollapsedRef,
            mergedThemeRef: themeRef,
            mergedValueRef,
            mergedExpandedKeysRef,
            activePathRef,
            mergedClsPrefixRef,
            isHorizontalRef: computed(() => props.mode === 'horizontal'),
            invertedRef: toRef(props, 'inverted'),
            doSelect,
            toggleExpand
        });
        function doSelect(value, item) {
            const { 'onUpdate:value': _onUpdateValue, onUpdateValue, onSelect } = props;
            if (onUpdateValue) {
                call(onUpdateValue, value, item);
            }
            if (_onUpdateValue) {
                call(_onUpdateValue, value, item);
            }
            if (onSelect) {
                call(onSelect, value, item);
            }
            uncontrolledValueRef.value = value;
        }
        function doUpdateExpandedKeys(value) {
            const { 'onUpdate:expandedKeys': _onUpdateExpandedKeys, onUpdateExpandedKeys, onExpandedNamesChange, onOpenNamesChange } = props;
            if (_onUpdateExpandedKeys) {
                call(_onUpdateExpandedKeys, value);
            }
            if (onUpdateExpandedKeys) {
                call(onUpdateExpandedKeys, value);
            }
            // deprecated
            if (onExpandedNamesChange) {
                call(onExpandedNamesChange, value);
            }
            if (onOpenNamesChange) {
                call(onOpenNamesChange, value);
            }
            uncontrolledExpandedKeysRef.value = value;
        }
        function toggleExpand(key) {
            const currentExpandedKeys = Array.from(mergedExpandedKeysRef.value);
            const index = currentExpandedKeys.findIndex((expanededKey) => expanededKey === key);
            if (~index) {
                currentExpandedKeys.splice(index, 1);
            }
            else {
                currentExpandedKeys.push(key);
            }
            doUpdateExpandedKeys(currentExpandedKeys);
        }
        return {
            mergedClsPrefix: mergedClsPrefixRef,
            controlledExpandedKeys: controlledExpandedKeysRef,
            uncontrolledExpanededKeys: uncontrolledExpandedKeysRef,
            mergedExpandedKeys: mergedExpandedKeysRef,
            uncontrolledValue: uncontrolledValueRef,
            mergedValue: mergedValueRef,
            activePath: activePathRef,
            tmNodes: tmNodesRef,
            mergedTheme: themeRef,
            mergedCollapsed: mergedCollapsedRef,
            cssVars: computed(() => {
                const { inverted } = props;
                const { common: { cubicBezierEaseInOut }, self } = themeRef.value;
                const { borderRadius, borderColorHorizontal, fontSize } = self;
                const vars = {
                    '--bezier': cubicBezierEaseInOut,
                    '--font-size': fontSize,
                    '--border-color-horizontal': borderColorHorizontal,
                    '--border-radius': borderRadius
                };
                if (inverted) {
                    vars['--group-text-color'] = self.groupTextColorInverted;
                    vars['--color'] = self.colorInverted;
                    vars['--item-text-color'] = self.itemTextColorInverted;
                    vars['--arrow-color'] = self.arrowColorInverted;
                    vars['--arrow-color-hover'] = self.arrowColorHoverInverted;
                    vars['--arrow-color-active'] = self.arrowColorActiveInverted;
                    vars['--arrow-color-child-active'] =
                        self.arrowColorChildActiveInverted;
                    vars['--item-icon-color'] = self.itemIconColorInverted;
                    vars['--item-text-color-hover'] = self.itemTextColorHoverInverted;
                    vars['--item-icon-color-hover'] = self.itemIconColorHoverInverted;
                    vars['--item-text-color-active'] = self.itemTextColorActiveInverted;
                    vars['--item-icon-color-active'] = self.itemIconColorActiveInverted;
                    vars['--item-icon-color-collapsed'] =
                        self.itemIconColorCollapsedInverted;
                    vars['--item-color-active'] = self.itemColorActiveInverted;
                    vars['--item-color-active-collapsed'] =
                        self.itemColorActiveCollapsedInverted;
                    vars['--item-text-color-child-active'] =
                        self.itemTextColorChildActiveInverted;
                    vars['--item-icon-color-child-active'] =
                        self.itemIconColorChildActiveInverted;
                }
                else {
                    vars['--group-text-color'] = self.groupTextColor;
                    vars['--color'] = self.color;
                    vars['--item-text-color'] = self.itemTextColor;
                    vars['--arrow-color'] = self.arrowColor;
                    vars['--arrow-color-hover'] = self.arrowColorHover;
                    vars['--arrow-color-active'] = self.arrowColorActive;
                    vars['--arrow-color-child-active'] = self.arrowColorChildActive;
                    vars['--item-icon-color'] = self.itemIconColor;
                    vars['--item-text-color-hover'] = self.itemTextColorHover;
                    vars['--item-icon-color-hover'] = self.itemIconColorHover;
                    vars['--item-text-color-active'] = self.itemTextColorActive;
                    vars['--item-icon-color-active'] = self.itemIconColorActive;
                    vars['--item-icon-color-collapsed'] = self.itemIconColorCollapsed;
                    vars['--item-color-active'] = self.itemColorActive;
                    vars['--item-color-active-collapsed'] = self.itemColorActiveCollapsed;
                    vars['--item-text-color-child-active'] = self.itemTextColorChildActive;
                    vars['--item-icon-color-child-active'] = self.itemIconColorChildActive;
                }
                return vars;
            })
        };
    },
    render() {
        const { mergedClsPrefix, mode } = this;
        return (h("div", { role: mode === 'horizontal' ? 'menubar' : 'menu', class: [
                `${mergedClsPrefix}-menu`,
                `${mergedClsPrefix}-menu--${mode}`,
                this.mergedCollapsed && `${mergedClsPrefix}-menu--collapsed`
            ], style: this.cssVars }, this.tmNodes.map((tmNode) => itemRenderer(tmNode))));
    }
});
