<script setup>
import {computed, nextTick, onBeforeUnmount, onMounted, ref} from 'vue'
import Icon from './Icon.vue'

// Generisches Custom-Dropdown, das je Option ein Icon + Label anzeigt (ein natives <select> kann
// keine SVG-Icons rendern). Die Options-Liste wird per <Teleport> an <body> gehängt und fixed
// positioniert, damit sie nicht von einem Eltern-Container mit overflow (z. B. .tab-content in
// TabbedPage) abgeschnitten wird. Wiederverwendbar für Icon-/Rich-Selects.
const props = defineProps({
    // Ausgewählter Wert (value einer Option).
    modelValue: {type: String, default: ''},
    // [{ value, label, icon? }]
    options: {type: Array, default: () => []},
    placeholder: {type: String, default: 'Auswählen…'},
})
const emit = defineEmits(['update:modelValue'])

const open = ref(false)
const root = ref(null)
const listRef = ref(null)
const pos = ref({top: 0, left: 0, width: 0})

const selected = computed(() => props.options.find(o => o.value === props.modelValue) ?? null)

function updatePosition() {
    if (!root.value) return
    const rect = root.value.getBoundingClientRect()
    pos.value = {top: rect.bottom + 4, left: rect.left, width: rect.width}
}

async function toggle() {
    open.value = !open.value
    if (open.value) {
        await nextTick()
        updatePosition()
    }
}

function select(option) {
    emit('update:modelValue', option.value)
    open.value = false
}

function onClickOutside(event) {
    const inRoot = root.value && root.value.contains(event.target)
    const inList = listRef.value && listRef.value.contains(event.target)
    if (!inRoot && !inList) {
        open.value = false
    }
}

function onKeydown(event) {
    if (event.key === 'Escape' || event.key === 'Esc') {
        open.value = false
    }
}

function onReposition() {
    if (open.value) updatePosition()
}

onMounted(() => {
    document.addEventListener('click', onClickOutside)
    document.addEventListener('keydown', onKeydown)
    window.addEventListener('resize', onReposition)
    // capture=true, damit auch Scrollen in inneren Containern die Position aktualisiert
    window.addEventListener('scroll', onReposition, true)
})
onBeforeUnmount(() => {
    document.removeEventListener('click', onClickOutside)
    document.removeEventListener('keydown', onKeydown)
    window.removeEventListener('resize', onReposition)
    window.removeEventListener('scroll', onReposition, true)
})
</script>

<template>
    <div ref="root" class="rich-select">
        <button
            type="button"
            class="rich-select__trigger"
            :aria-expanded="open"
            @click="toggle"
        >
            <span class="rich-select__value">
                <template v-if="selected">
                    <Icon v-if="selected.icon" :key="selected.value" :name="selected.icon"/>
                    <span>{{ selected.label }}</span>
                </template>
                <span v-else class="rich-select__placeholder">{{ placeholder }}</span>
            </span>
            <span class="rich-select__caret" aria-hidden="true">▾</span>
        </button>

        <Teleport to="body">
            <ul
                v-if="open"
                ref="listRef"
                class="rich-select__list"
                role="listbox"
                :style="{ top: pos.top + 'px', left: pos.left + 'px', width: pos.width + 'px' }"
            >
                <li
                    v-for="option in options"
                    :key="option.value"
                    class="rich-select__option"
                    :class="{ 'rich-select__option--active': option.value === modelValue }"
                    role="option"
                    :aria-selected="option.value === modelValue"
                    @click="select(option)"
                >
                    <Icon v-if="option.icon" :name="option.icon"/>
                    <span>{{ option.label }}</span>
                </li>
            </ul>
        </Teleport>
    </div>
</template>

<style scoped>
.rich-select {
    position: relative;
    width: 100%;
}

.rich-select__trigger {
    display: flex;
    align-items: center;
    justify-content: space-between;
    width: 100%;
    gap: 10px;
    padding: 6px 10px;
    border: 1px solid #d1d5db;
    border-radius: 6px;
    background: #fff;
    cursor: pointer;
    font-size: 0.95rem;
    box-sizing: border-box;
}

.rich-select__trigger:hover {
    border-color: #2563eb;
}

.rich-select__value {
    display: flex;
    align-items: center;
    gap: 10px;
    min-width: 0;
}

.rich-select__placeholder {
    color: #9ca3af;
}

.rich-select__caret {
    color: #6b7280;
    font-size: 0.8rem;
}

.rich-select__list {
    position: fixed;
    z-index: 1000;
    margin: 0;
    padding: 4px;
    list-style: none;
    background: #fff;
    border: 1px solid #d1d5db;
    border-radius: 8px;
    box-shadow: 0 8px 24px rgba(0, 0, 0, 0.12);
    max-height: 260px;
    overflow: auto;
    box-sizing: border-box;
}

.rich-select__option {
    display: flex;
    align-items: center;
    gap: 10px;
    padding: 8px 10px;
    border-radius: 6px;
    cursor: pointer;
}

.rich-select__option:hover {
    background: #eff6ff;
}

.rich-select__option--active {
    background: #dbeafe;
    font-weight: 600;
}
</style>
