<template>
    <component v-if="!asChild" :is="as" :class="cx('root')" v-bind="attrs">
        <slot />
    </component>
    <slot v-else :a11yAttrs="a11yAttrs" :class="cx('root')" />
</template>

<script>
import { mergeProps } from 'vue';
import BaseSidebar from './BaseSidebar.vue';

export default {
    name: 'Sidebar',
    extends: BaseSidebar,
    inheritAttrs: false,
    emits: ['update:open'],
    inject: {
        $pcSidebarLayout: { default: null }
    },
    data() {
        return {
            d_open: this.open !== undefined ? this.open : true
        };
    },
    watch: {
        open(newValue) {
            if (newValue === undefined) return;
            this.d_open = newValue;
        },
        id(newValue, oldValue) {
            if (oldValue) {
                this.unregisterFromLayout(oldValue);
            }

            if (newValue) {
                this.registerInLayout(newValue);
            }
        }
    },
    mounted() {
        this.registerInLayout(this.id);
    },
    beforeUnmount() {
        this.clearHoverTimer();
        this.unregisterFromLayout(this.id);
    },
    methods: {
        registerInLayout(id) {
            if (!this.$pcSidebarLayout || !id) return;

            const self = this;

            this.$pcSidebarLayout.registerSidebar(id, {
                toggle: (event) => self.toggle(event),
                get open() {
                    return self.d_open;
                },
                get state() {
                    return self.displayState;
                },
                get dismissable() {
                    return self.dismissable;
                },
                get overlay() {
                    return self.overlay;
                },
                get hideOnOutsideClick() {
                    return self.hideOnOutsideClick;
                }
            });
        },
        unregisterFromLayout(id) {
            if (this.$pcSidebarLayout && id) {
                this.$pcSidebarLayout.unregisterSidebar(id);
            }
        },
        clearHoverTimer() {
            if (this.hoverTimer) {
                clearTimeout(this.hoverTimer);
                this.hoverTimer = null;
            }
        },
        updateOpen(value, event) {
            const next = !!value;

            if (this.open === undefined) {
                this.d_open = next;
            }

            this.$emit('update:open', next);
        },
        toggle(event) {
            if (this.collapsible === 'none') return;
            this.updateOpen(!this.d_open, event);
        },
        expand(event) {
            this.updateOpen(true, event);
        },
        collapse(event) {
            if (this.collapsible === 'none') return;
            this.updateOpen(false, event);
        },
        onPointerEnter(event) {
            if (!this.openOnHover) return;
            this.clearHoverTimer();
            this.hoverTimer = setTimeout(() => this.expand(event), this.hoverOpenDelay);
        },
        onPointerLeave(event) {
            if (!this.openOnHover) return;
            this.clearHoverTimer();
            this.hoverTimer = setTimeout(() => this.collapse(event), this.hoverCloseDelay);
        },
        getSectionAttrs(section) {
            return {
                'data-pc-name': 'sidebar',
                'data-pc-section': section,
                'data-state': this.displayState,
                'data-collapsible': this.displayState === 'collapsed' ? this.collapsible : undefined,
                'data-collapsible-mode': this.collapsible,
                'data-variant': this.variant,
                'data-side': this.side,
                'data-overlay': this.overlay ? '' : undefined
            };
        }
    },
    computed: {
        displayState() {
            return this.d_open ? 'expanded' : 'collapsed';
        },
        a11yAttrs() {
            const hover = this.openOnHover
                ? {
                      onPointerenter: this.onPointerEnter,
                      onPointerleave: this.onPointerLeave
                  }
                : {};

            return {
                ...this.getSectionAttrs('root'),
                style: {
                    '--px-sidebar-width': this.width,
                    '--px-sidebar-width-icon': this.iconWidth
                },
                ...hover
            };
        },
        attrs() {
            return mergeProps(this.a11yAttrs, this.ptmi('root'));
        }
    }
};
</script>
