<template>
    <div class="hy-tabbar hy-hide-scrollbars" :class="[{ disabled, initialState }, variant, sizeParsed]" ref="tabbar">
        <slot />
    </div>
</template>

<script>
import { useResizeObserver } from "@vueuse/core";

export default {
    name: "HyTabbar",
    data() {
        return {
            targetWidth: "0px", // initial values to make first transition after initialState less janky
            targetHeight: "43px",
            targetPosition: "0px",
            initialState: true,
        };
    },
    props: {
        modelValue: {
            type: String,
            required: true,
        },
        disabled: {
            type: Boolean,
            default: false,
        },
        variant: {
            type: String,
            default: "gray",
            validator(value) {
                return ["gray", "primary"].includes(value);
            },
        },
        size: {
            type: String,
            default: null,
        },
    },
    watch: {
        modelValue(newValue, previousValue) {
            this.updateClassLists();
            this.updateGhostTarget(newValue, previousValue);
        },
    },
    computed: {
        sizeParsed() {
            let size = this.size ?? this.hy_defaults.size;
            let allowed = ["lg", "md", "sm"];

            if (allowed.includes(size)) return `size-${size}`;
            else return "size-lg";
        },
    },
    methods: {
        updateValue(event) {
            let value = event.target.dataset.value;
            this.$emit("update:modelValue", value);
        },
        updateClassLists() {
            let options = Array.from(this.$refs.tabbar.children);

            options.forEach((el) => {
                if (el.dataset.value == this.modelValue) {
                    el.classList.add("selected");
                } else {
                    el.classList.remove("selected");
                }
            });
        },
        updateGhostTarget(newTarget, previousTarget) {
            // NOTE: This function is not called until the user first interacts with the component

            let options = Array.from(this.$refs.tabbar.children);

            // If first time interaction => move ghost to the previous selected element (note: animation is still disabled)
            if (this.initialState) {
                let previousElement = options.find((el) => el.dataset.value == previousTarget);

                this.targetWidth = `${previousElement.offsetWidth}px`;
                this.targetHeight = `${previousElement.offsetHeight}px`;
                this.targetPosition = `${previousElement.offsetLeft}px`;
            }

            // After that has been processed
            this.$nextTick(() => {
                this.initialState = false; // This enables the animation

                // Move ghost to the new selected element
                let newElement = options.find((el) => el.dataset.value == newTarget);

                this.targetWidth = `${newElement.offsetWidth}px`;
                this.targetHeight = `${newElement.offsetHeight}px`;
                this.targetPosition = `${newElement.offsetLeft}px`;
            });
        },
        addClickListeners() {
            // Iterate over all options and add click listeners
            let options = Array.from(this.$refs.tabbar.children);

            options.forEach((el) => {
                el.removeEventListener("click", this.updateValue); // First clear all event listeners
                el.addEventListener("click", this.updateValue); // Then add them one click listener
            });
        },
    },
    mounted() {
        this.addClickListeners();
        this.updateClassLists();

        // Update ghost position/size on resize of body element
        useResizeObserver(document.body, () => {
            this.updateGhostTarget(this.modelValue, this.modelValue);
        });
    },
    updated() {
        this.addClickListeners();
        this.updateClassLists();
    },
};
</script>

<style lang="scss">
.hy-tabbar {
    margin: var(--hy-element-margin);
    position: relative;
    border-radius: var(--hy-element-border-radius);
    transition: var(--hy-element-transition);
    transition-property: filter;
    display: flex;
    justify-content: space-between;
    align-items: center;
    gap: var(--hy-flex-gap);
    overflow-x: auto;
    min-width: auto;

    &.disabled {
        cursor: not-allowed;
        filter: opacity(50%);

        p[data-value] {
            pointer-events: none;
        }
    }

    // GHOST
    &::before {
        content: "";
        display: block;
        position: absolute;
        left: 0px;
        transform: translateX(v-bind(targetPosition));
        height: v-bind(targetHeight);
        width: v-bind(targetWidth);
        border-radius: calc(var(--hy-element-border-radius) * 0.6);
        transition: var(--hy-tabbar-transition);
    }

    &:not(.initialState)::before {
        transition-property: transform, width, height;
    }

    // OPTION CHILDREN
    // In order to increase css specificity over the ones in globals.scss
    p[data-value] {
        z-index: 5;
        border: none;
        margin: 0;
        flex: 1;
        text-align: center;
        border-radius: calc(var(--hy-element-border-radius) * 0.6);
        cursor: pointer;
        transition: var(--hy-element-transition);
        transition-property: color;
        min-width: max-content; // Prevent line breaks

        // Disable click on all child nodes
        // To fix https://github.com/Jaaahn/HyperUI/issues/23
        * {
            pointer-events: none;
        }
    }

    // SIZE
    &.size-lg {
        &.primary > p[data-value] {
            padding: calc(var(--hy-element-padding) - 3px); // 3px for outer padding
        }

        &.gray {
            padding: 6px;

            & > p[data-value] {
                padding: calc(var(--hy-element-padding) - 4px);
            }
        }
    }

    &.size-md {
        &.primary > p[data-value] {
            padding: calc(var(--hy-element-padding-md) - 3px); // 3px for outer padding
        }

        &.gray > p[data-value] {
            padding: calc(var(--hy-element-padding-md) - 2px);
        }
    }

    &.size-sm {
        &.primary > p[data-value] {
            padding: calc(var(--hy-element-padding-sm) - 3px) var(--hy-element-padding-sm); // 3px for outer padding | make left and right padding slightly larger
        }

        &.gray > p[data-value] {
            padding: calc(var(--hy-element-padding-sm) - 2px) var(--hy-element-padding-sm);
        }
    }

    // COLOR THEME
    &.primary {
        padding: 3px;
        background-color: var(--hy-variant-secondary-bg-color);
        border: var(--hy-element-border-secondary);
        box-shadow: var(--hy-element-shadow);

        &::before {
            background-color: var(--hy-variant-primary-bg-color);
        }

        p[data-value] {
            &.selected {
                color: var(--hy-variant-primary-font-color);
            }

            &:not(.selected) {
                color: var(--hy-font-color-gray);
            }
        }

        &.initialState > p[data-value].selected {
            background-color: var(--hy-variant-primary-bg-color);
        }
    }

    // COLOR THEME
    &.gray {
        padding: 4px;
        background-color: var(--hy-gray-tabbar-bg-color);

        &::before {
            background-color: var(--hy-gray-tabbar-ghost-color);
        }

        p[data-value] {
            &:not(.selected) {
                color: var(--hy-font-color-gray);
            }
        }

        &.initialState > p[data-value].selected {
            background-color: var(--hy-gray-tabbar-ghost-color);
        }
    }
}

@media (prefers-color-scheme: light) {
    .hy-tabbar.gray {
        &.initialState > p[data-value].selected,
        &::before {
            box-shadow: var(--hy-element-shadow);
        }
    }
}
</style>
