<template>
    <ul :key="collapse"
        role="menubar"
        :class="menuClass">
        <slot></slot>
    </ul>
</template>
<script>
import {
    prefix,
    prefixMixins,
    addClass,
    removeClass,
    hasClass,
    mixColor
} from 'jdd-design/utils';

export default {
    name: `${prefix}-menu`,
    componentName: `${prefix}-menu`,
    provide() {
        return {
            jddMenu: this
        };
    },
    props: {
        layout: {
            type: String,
            default: 'vertical'
        },
        defaultActive: {
            type: String,
            default: ''
        },
        defaultOpeneds: Array,
        uniqueOpened: Boolean,
        router: Boolean,
        collapse: Boolean,
        theme: {
            type: [Object, String],
            default: 'light'
        }
    },
    data() {
        return {
            activeIndex: this.defaultActive,
            openedMenus:
                this.defaultOpeneds && !this.collapse
                    ? this.defaultOpeneds.slice(0)
                    : [],
            items: {},
            submenus: {},
            themes: {
                light: {},
                dark: {}
            }
        };
    },
    computed: {
        menuClass() {
            let clsNames = [`${prefix}-menu`, `${prefix}-menu--${this.theme}`];
            this.layout && clsNames.push(`${prefix}-menu--${this.layout}`);
            this.collapse && clsNames.push(`${prefix}-menu--collapse`);
            return clsNames;
        },
        menuTheme() {
            let theme = this.themes.light;
            if (this.theme) {
                if (typeof this.theme === 'string') {
                    theme = this.themes[this.theme];
                } else {
                    theme = this.theme;
                }
            }
            return {
                ...theme,
                hoverBackground: theme.backgroundColor
                    ? mixColor(theme.backgroundColor, 0.2)
                    : ''
            };
        },
        isMenuPopup() {
            return (
                this.layout === 'horizontal' ||
                (this.layout === 'vertical' && this.collapse)
            );
        }
    },
    watch: {
        defaultActive(value) {
            if (!this.items[value]) {
                this.activeIndex = null;
            }
            this.updateActiveIndex(value);
        },
        defaultOpeneds(value) {
            if (!this.collapse) {
                this.openedMenus = value;
            }
        },
        collapse(value) {
            if (value) this.openedMenus = [];
            Object.values(this.submenus).forEach(m =>
                m.$emit('toogle-collapse', value)
            );
        }
    },
    methods: {
        updateActiveIndex(val) {
            const item =
                this.items[val] ||
                this.items[this.activeIndex] ||
                this.items[this.defaultActive];
            if (item) {
                this.activeIndex = item.index;
                this.initOpenedMenu();
            } else {
                this.activeIndex = null;
            }
        },

        addItem(item) {
            this.$set(this.items, item.index, item);
        },
        removeItem(item) {
            delete this.items[item.index];
        },
        addSubmenu(item) {
            this.$set(this.submenus, item.index, item);
        },
        removeSubmenu(item) {
            delete this.submenus[item.index];
        },
        openMenu(index, indexPath) {
            let openedMenus = this.openedMenus;
            if (openedMenus.indexOf(index) !== -1) return;
            // 将其余菜单收起
            if (this.uniqueOpened) {
                this.openedMenus = openedMenus.filter(index => {
                    return indexPath.indexOf(index) !== -1;
                });
            }
            this.openedMenus.push(index);
        },
        closeMenu(index) {
            const i = this.openedMenus.indexOf(index);
            if (i !== -1) {
                this.openedMenus.splice(i, 1);
            }
        },
        handleSubmenuClick(submenu) {
            const { index, indexPath } = submenu;
            let isOpened = this.openedMenus.indexOf(index) !== -1;

            if (isOpened) {
                this.closeMenu(index);
                this.$emit('close', index, indexPath);
            } else {
                this.openMenu(index, indexPath);
                this.$emit('open', index, indexPath);
            }
        },
        handleItemClick(item) {
            const { index, indexPath } = item;
            const oldActiveIndex = this.activeIndex;
            const hasIndex = item.index !== null;

            if (hasIndex) {
                this.activeIndex = item.index;
            }

            this.$emit('select', index, indexPath, item);

            if (this.layout === 'horizontal' || this.collapse) {
                this.openedMenus = [];
            }

            if (this.router && hasIndex) {
                this.routeToItem(item, error => {
                    this.activeIndex = oldActiveIndex;
                    if (error) console.error(error);
                });
            }
        },
        // 初始化展开菜单
        // initialize opened menu
        initOpenedMenu() {
            const index = this.activeIndex;
            const activeItem = this.items[index];
            if (!activeItem || this.layout === 'horizontal' || this.collapse)
                return;

            let indexPath = activeItem.indexPath;

            // 展开该菜单项的路径上所有子菜单
            // expand all submenus of the menu item
            indexPath.forEach(index => {
                let submenu = this.submenus[index];
                submenu && this.openMenu(index, submenu.indexPath);
            });
        },
        routeToItem(item, onError) {
            let route = item.route || { name: item.index };
            try {
                this.$router.push(route, () => {}, onError);
            } catch (e) {
                console.error(e);
            }
        },
        open(index) {
            const { indexPath } = this.submenus[index.toString()];
            indexPath.forEach(i => this.openMenu(i, indexPath));
        },
        close(index) {
            this.closeMenu(index);
        }
    },
    mounted() {
        this.initOpenedMenu();
        this.$on('item-click', this.handleItemClick);
        this.$on('submenu-click', this.handleSubmenuClick);
        this.$watch('items', this.updateActiveIndex);
    }
};
</script>
