<script setup lang="ts">
import { Check, ChevronDown, Search } from 'lucide-vue-next';
import { computed, nextTick, onBeforeUnmount, onMounted, ref } from 'vue';

const props = withDefaults(
    defineProps<{
        modelValue: string | number | null;
        options: Array<any>;
        placeholder?: string;
        valueKey?: string;
        labelKey?: string;
        error?: string;
        disabled?: boolean;
        class?: string;
    }>(),
    {
        placeholder: 'Select...',
        valueKey: 'id',
        labelKey: 'name',
        disabled: false,
    },
);

const emit = defineEmits(['update:modelValue']);

const isOpen = ref(false);
const searchQuery = ref('');
const searchInput = ref<HTMLInputElement | null>(null);
const containerRef = ref<HTMLDivElement | null>(null);

// Close dropdown when clicking outside
const handleClickOutside = (event: MouseEvent) => {
    if (containerRef.value && !containerRef.value.contains(event.target as Node)) {
        isOpen.value = false;
    }
};

onMounted(() => {
    document.addEventListener('mousedown', handleClickOutside);
});

onBeforeUnmount(() => {
    document.removeEventListener('mousedown', handleClickOutside);
});

// Toggle dropdown
const toggleDropdown = () => {
    if (props.disabled) return;
    isOpen.value = !isOpen.value;
    if (isOpen.value) {
        searchQuery.value = '';
        nextTick(() => {
            searchInput.value?.focus();
        });
    }
};

// Filter options based on search
const filteredOptions = computed(() => {
    if (!props.options) return [];
    if (!searchQuery.value) return props.options;

    const query = searchQuery.value.toLowerCase();
    return props.options.filter((option) => {
        const label = String(option[props.labelKey] || '').toLowerCase();
        return label.includes(query);
    });
});

// Get label for current selected value
const selectedLabel = computed(() => {
    if (props.modelValue === null || props.modelValue === '') return '';
    const selected = props.options?.find((opt) => String(opt[props.valueKey]) === String(props.modelValue));
    return selected ? selected[props.labelKey] : '';
});

// Check if option is selected safely
const isSelected = (option: any) => {
    if (props.modelValue === null || props.modelValue === undefined || props.modelValue === '') return false;
    return String(option[props.valueKey]) === String(props.modelValue);
};

// Select an option
const selectOption = (option: any) => {
    emit('update:modelValue', option[props.valueKey]);
    isOpen.value = false;
};
</script>

<template>
    <div class="relative" ref="containerRef" :class="props.class">
        <!-- Trigger Button -->
        <button
            type="button"
            @click="toggleDropdown"
            :disabled="disabled"
            class="relative flex w-full items-center justify-between rounded-xl border bg-white px-4 py-2 text-left text-sm shadow-sm transition-all focus:border-primary-500 focus:ring-2 focus:ring-primary-500 focus:outline-none dark:bg-slate-900"
            :class="[
                error ? 'border-red-400 focus:ring-red-500' : 'border-slate-200 dark:border-slate-700',
                disabled
                    ? 'cursor-not-allowed bg-slate-50 opacity-50 dark:bg-slate-800'
                    : 'cursor-pointer hover:bg-slate-50 dark:hover:bg-slate-800/50',
            ]"
        >
            <span class="block truncate" :class="selectedLabel ? 'text-slate-900 dark:text-white' : 'text-slate-400'">
                {{ selectedLabel || placeholder }}
            </span>
            <ChevronDown class="ml-2 h-4 w-4 text-slate-400 transition-transform duration-200" :class="isOpen ? 'rotate-180' : ''" />
        </button>

        <!-- Error Message -->
        <div v-if="error" class="mt-1 text-[10px] text-red-500">{{ error }}</div>

        <!-- Dropdown Menu -->
        <transition
            enter-active-class="transition ease-out duration-100"
            enter-from-class="transform opacity-0 scale-95"
            enter-to-class="transform opacity-100 scale-100"
            leave-active-class="transition ease-in duration-75"
            leave-from-class="transform opacity-100 scale-100"
            leave-to-class="transform opacity-0 scale-95"
        >
            <div
                v-if="isOpen"
                class="absolute z-50 mt-1 flex max-h-60 w-full flex-col overflow-hidden rounded-xl border border-slate-200 bg-white shadow-xl dark:border-slate-700 dark:bg-slate-800"
            >
                <!-- Search Input -->
                <div class="shrink-0 border-b border-slate-100 p-2 dark:border-slate-700">
                    <div class="relative">
                        <Search class="absolute top-1/2 left-2.5 h-4 w-4 -translate-y-1/2 text-slate-400" />
                        <input
                            ref="searchInput"
                            v-model="searchQuery"
                            type="text"
                            class="w-full rounded-lg border border-slate-200 bg-slate-50 py-1.5 pr-3 pl-9 text-sm focus:ring-2 focus:ring-primary-500 focus:outline-none dark:border-slate-600 dark:bg-slate-900 dark:text-white"
                            placeholder="Search..."
                            @keydown.esc="isOpen = false"
                        />
                    </div>
                </div>

                <!-- Options List -->
                <ul class="overflow-y-auto py-1 text-sm text-slate-700 dark:text-slate-300">
                    <li
                        v-for="option in filteredOptions"
                        :key="option[valueKey]"
                        @click="selectOption(option)"
                        class="relative cursor-pointer py-2 pr-4 pl-9 select-none hover:bg-slate-100 dark:hover:bg-slate-700/50"
                        :class="isSelected(option) ? 'font-medium text-primary-600 dark:text-primary-400' : ''"
                    >
                        <span class="block truncate">{{ option[labelKey] }}</span>
                        <!-- Checkmark for selected -->
                        <span
                            v-if="isSelected(option)"
                            class="absolute inset-y-0 left-0 flex items-center pl-3 text-primary-600 dark:text-primary-400"
                        >
                            <Check class="h-4 w-4" />
                        </span>
                    </li>

                    <!-- No Results -->
                    <li v-if="filteredOptions.length === 0" class="cursor-default px-4 py-3 text-center text-sm text-slate-400">No results found</li>
                </ul>
            </div>
        </transition>
    </div>
</template>
