<template>
	<transition name="fade">
		<div
			v-show="shown"
			ref="contextMenu"
			class="context-menu"
			:style="{
				left: left,
				top: top,
			}"
		>
			<div v-for="(option, index) in options" :key="index" @click.stop="optionClicked(option.name)">
				<hr v-if="option.type === 'divider'" class="divider" />
				<div
					v-else-if="!(isLinkedData(item) && option.name === `add_content`)"
					class="item clickable"
					:class="[option.color ?? 'base']"
				>
					<slot :name="option.name" />
				</div>
			</div>
		</div>
	</transition>
</template>

<script setup>
import { onBeforeUnmount, onMounted, ref } from 'vue'

const emit = defineEmits(['menu-closed', 'option-clicked'])

const item = ref(null)
const contextMenu = ref(null)
const options = ref([])
const left = ref('0px')
const top = ref('0px')
const shown = ref(false)

defineExpose({
	showMenu: (event, passedItem, passedOptions) => {
		item.value = passedItem
		options.value = passedOptions

		const menuWidth = contextMenu.value.clientWidth
		const menuHeight = contextMenu.value.clientHeight

		if (menuWidth + event.pageX >= window.innerWidth) {
			left.value = event.pageX - menuWidth + 2 + 'px'
		} else {
			left.value = event.pageX - 2 + 'px'
		}

		if (menuHeight + event.pageY >= window.innerHeight) {
			top.value = event.pageY - menuHeight + 2 + 'px'
		} else {
			top.value = event.pageY - 2 + 'px'
		}

		shown.value = true
	},
})

const isLinkedData = (item) => {
	if (item.instance != undefined && item.instance.linked_data) {
		return true
	} else if (item != undefined && item.linked_data) {
		return true
	}
	return false
}

const hideContextMenu = () => {
	shown.value = false
	emit('menu-closed')
}

const optionClicked = (option) => {
	emit('option-clicked', {
		item: item.value,
		option: option,
	})
	hideContextMenu()
}

const onEscKeyRelease = (event) => {
	if (event.keyCode === 27) {
		hideContextMenu()
	}
}

const handleClickOutside = (event) => {
	const elements = document.elementsFromPoint(event.clientX, event.clientY)
	if (
		contextMenu.value &&
		contextMenu.value.$el !== event.target &&
		!elements.includes(contextMenu.value.$el)
	) {
		hideContextMenu()
	}
}

onMounted(() => {
	window.addEventListener('click', handleClickOutside)
	document.body.addEventListener('keyup', onEscKeyRelease)
})

onBeforeUnmount(() => {
	window.removeEventListener('click', handleClickOutside)
	document.removeEventListener('keyup', onEscKeyRelease)
})
</script>

<style lang="scss" scoped>
.context-menu {
	background-color: var(--color-raised-bg);
	border-radius: var(--radius-md);
	box-shadow: var(--shadow-floating);
	border: 1px solid var(--color-button-bg);
	margin: 0;
	position: fixed;
	z-index: 1000000;
	overflow: hidden;
	padding: var(--gap-sm);

	.item {
		align-items: center;
		color: var(--color-base);
		cursor: pointer;
		display: flex;
		gap: var(--gap-sm);
		padding: var(--gap-sm);
		border-radius: var(--radius-sm);

		&:hover,
		&:active {
			&.base {
				background-color: var(--color-button-bg);
				color: var(--color-contrast);
			}

			&.primary {
				background-color: var(--color-brand);
				color: var(--color-accent-contrast);
				font-weight: bold;
			}

			&.danger {
				background-color: var(--color-red);
				color: var(--color-accent-contrast);
				font-weight: bold;
			}

			&.contrast {
				background-color: var(--color-orange);
				color: var(--color-accent-contrast);
				font-weight: bold;
			}
		}
	}

	.divider {
		border: 1px solid var(--color-button-bg);
		margin: var(--gap-sm);
		pointer-events: none;
	}
}

.fade-enter-active,
.fade-leave-active {
	transition: opacity 0.2s ease-in-out;
}

.fade-enter-from,
.fade-leave-to {
	opacity: 0;
}
</style>
