<template>
    <Tooltip
        v-if="unref(visibility) !== Visibility.None"
        v-bind="tooltipToBind && gatherTooltipProps(tooltipToBind)"
        :display="tooltipDisplay"
        :force="forceTooltip"
        :style="{ visibility: unref(visibility) === Visibility.Hidden ? 'hidden' : undefined }"
        :class="{
            treeNode: true,
            can: unref(canClick),
            small: unref(small),
            ...unref(classes)
        }"
    >
        <button
            @click="click"
            @mousedown="start"
            @mouseleave="stop"
            @mouseup="stop"
            @touchstart="start"
            @touchend="stop"
            @touchcancel="stop"
            :style="[
                {
                    backgroundColor: unref(color),
                    boxShadow: `-4px -4px 4px rgba(0, 0, 0, 0.25) inset, 0 0 20px ${unref(
                        glowColor
                    )}`
                },
                unref(style) ?? []
            ]"
            :disabled="!unref(canClick)"
        >
            <component :is="unref(comp)" />
        </button>
        <MarkNode :mark="unref(mark)" />
        <LinkNode :id="id" />
    </Tooltip>
</template>

<script lang="ts">
import LinkNode from "@/components/links/LinkNode.vue";
import MarkNode from "@/components/MarkNode.vue";
import TooltipVue from "@/components/Tooltip.vue";
import { CoercableComponent, StyleValue, Visibility } from "@/features/feature";
import { gatherTooltipProps, Tooltip } from "@/features/tooltip";
import { ProcessedComputable } from "@/util/computed";
import {
    computeOptionalComponent,
    isCoercableComponent,
    processedPropType,
    setupHoldToClick,
    unwrapRef
} from "@/util/vue";
import {
    computed,
    defineComponent,
    PropType,
    Ref,
    shallowRef,
    toRefs,
    unref,
    watchEffect
} from "vue";

export default defineComponent({
    props: {
        display: processedPropType<CoercableComponent>(Object, String, Function),
        visibility: {
            type: processedPropType<Visibility>(Number),
            required: true
        },
        style: processedPropType<StyleValue>(String, Object, Array),
        classes: processedPropType<Record<string, boolean>>(Object),
        tooltip: processedPropType<CoercableComponent | Tooltip>(Object, String, Function),
        onClick: Function as PropType<VoidFunction>,
        onHold: Function as PropType<VoidFunction>,
        color: processedPropType<string>(String),
        glowColor: processedPropType<string>(String),
        forceTooltip: {
            type: Object as PropType<Ref<boolean>>,
            required: true
        },
        canClick: {
            type: processedPropType<boolean>(Boolean),
            required: true
        },
        mark: processedPropType<boolean | string>(Boolean, String),
        id: {
            type: String,
            required: true
        },
        small: processedPropType<boolean>(Boolean)
    },
    components: {
        Tooltip: TooltipVue,
        MarkNode,
        LinkNode
    },
    setup(props) {
        const { tooltip, forceTooltip, onClick, onHold, display } = toRefs(props);

        function click(e: MouseEvent) {
            if (e.shiftKey && tooltip) {
                forceTooltip.value = !forceTooltip.value;
            } else {
                unref(onClick)?.();
            }
        }

        const comp = computeOptionalComponent(display);
        const tooltipDisplay = shallowRef<ProcessedComputable<CoercableComponent> | undefined>(
            undefined
        );
        watchEffect(() => {
            const currTooltip = unwrapRef(tooltip);

            if (typeof currTooltip === "object" && !isCoercableComponent(currTooltip)) {
                tooltipDisplay.value = currTooltip.display;
                return;
            }
            tooltipDisplay.value = currTooltip;
        });
        const tooltipToBind = computed(() => {
            const currTooltip = unwrapRef(tooltip);

            if (typeof currTooltip === "object" && !isCoercableComponent(currTooltip)) {
                return currTooltip;
            }
            return null;
        });

        const { start, stop } = setupHoldToClick(onClick, onHold);

        return {
            click,
            start,
            stop,
            comp,
            tooltipDisplay,
            tooltipToBind,
            unref,
            Visibility,
            gatherTooltipProps,
            isCoercableComponent
        };
    }
});
</script>

<style scoped>
.treeNode {
    height: 100px;
    width: 100px;
    border-radius: 50%;
    padding: 0;
    margin: 0 10px 0 10px;
}

.treeNode button {
    width: 100%;
    height: 100%;
    border: 2px solid rgba(0, 0, 0, 0.125);
    border-radius: inherit;
    font-size: 40px;
    color: rgba(0, 0, 0, 0.5);
    text-shadow: 2px 2px 4px rgba(0, 0, 0, 0.25);
    box-shadow: -4px -4px 4px rgba(0, 0, 0, 0.25) inset, 0px 0px 20px var(--background);
    text-transform: capitalize;
}

.treeNode.small {
    height: 60px;
    width: 60px;
}

.treeNode.small button {
    font-size: 30px;
}

.ghost {
    visibility: hidden;
    pointer-events: none;
}
</style>