<script lang="ts" setup>
import { Icon } from '@bagelink/vue'
import { computed, inject, ref, watch } from 'vue'

const props = defineProps<{
	label?: string
	id?: string
	open?: boolean
	iconType?: 'expand_more' | 'plus_minus'
	iconPosition?: 'start' | 'end'
	flat?: boolean
	iconClass?: string
}>()

const emit = defineEmits(['update:open'])

const openVal = ref(!!props.open)

const isOpen = computed({
	get: () => openVal.value,
	set: (value: boolean) => {
		openVal.value = value
		emit('update:open', value)
	},
})

interface AccordionState {
	openItem?: string
}

const accordionState = inject<AccordionState | undefined>('accordionState', undefined)
const id = props.id || Math.random().toString(36).slice(7)

const computedIcon = computed(() => {
	return props.iconType === 'plus_minus'
		? (isOpen.value ? 'remove' : 'add')
		: 'expand_more'
})
const iconPosition = computed(() => props.iconPosition || 'end')

watch(() => props.open, () => isOpen.value = props.open, { immediate: true })

if (accordionState) {
	watch(
		() => accordionState.openItem,
		(currentOpenId) => {
			if (currentOpenId !== id) { isOpen.value = false }
		},
		{ immediate: true }
	)
}

function toggle() {
	isOpen.value = !isOpen.value
	if (accordionState) {
		if (isOpen.value) {
			accordionState.openItem = id
		} else if (accordionState.openItem !== undefined && accordionState.openItem === id) {
			accordionState.openItem = undefined
		}
	}
}
</script>

<template>
	<div class="accordion-item txt-start" :class="[{ flat }]">
		<button
			:aria-expanded="isOpen ? 'true' : 'false'" class="accordion-head"
			:aria-controls="`accordion-body-${id}`" @click="toggle()"
		>
			<span
				v-if="iconPosition === 'start'" class="accordion-icon"
				:class="[iconClass, { open: isOpen && iconType === 'expand_more' }]"
			>
				<Icon :icon="computedIcon" />
			</span>

			<slot name="head">
				<span class="accordion-label">
					{{ label }}
				</span>
			</slot>

			<span
				v-if="iconPosition === 'end'" class="accordion-icon"
				:class="[iconClass, { open: isOpen && iconType === 'expand_more' }]"
			>
				<Icon :icon="computedIcon" />
			</span>
		</button>
		<Transition name="expand">
			<div
				v-if="isOpen" :id="`accordion-body-${id}`" class="accordion-body"
				:aria-hidden="isOpen ? 'false' : 'true'"
			>
				<slot />
			</div>
		</Transition>
	</div>
</template>

<style scoped>
.accordion-item {
	border-bottom: 1px solid var(--border-color);
	transition: all 0.2s;
	overflow: hidden;
}

.accordion-item button {
	cursor: pointer;
}

.accordion-head {
	height: var(--input-height);
	background: transparent;
	display: flex;
	width: 100%;
	align-items: center;
	justify-content: space-between;
	border: none;
	color: inherit !important;
}

.accordion-icon {
	transition: all 0.2s ease;
	display: flex;
	align-items: center;
	flex-shrink: 0;
	width: calc(var(--btn-height) / 1.5);
	height: calc(var(--btn-height) / 1.5);
	padding-inline: calc(var(--btn-padding) / 3);
	justify-content: center;
}

[aria-expanded="true"] .accordion-icon {
	transform: rotate(180deg);
}

.accordion-label {
	font-weight: bold;
}

.flat.accordion-item {
	border-bottom: none
}

.accordion-head:hover .accordion-label {
	text-decoration: underline;
}
</style>

<style>
.expand-enter-active,
.expand-leave-active {
	transition: all 0.2s;
	transition-delay: 0ms;
}

.expand-enter-from,
.expand-leave-to {
	max-height: 0;
}

.expand-enter-to,
.expand-leave-from {
	max-height: 300px;
}
</style>
