<script lang="ts">
    import { createEventDispatcher } from 'svelte';
    import type { HTMLAttributes } from 'svelte/elements';
    import { onMount } from 'svelte';
    import { on } from 'svelte/events';

    interface Props extends HTMLAttributes<HTMLDivElement> {
        options?: { value: any; label:string }[];
        selected?: any;
        placeholder?: string;
        searchPlaceholder?: string;
        disabled?: boolean;
        class?: string;
        onChange?: (value: any) => void;
    }

    let {
        id = 'select-searchable',
        options = [],
        selected = $bindable(null),
        placeholder = 'Select an option...',
        searchPlaceholder = 'Search...',
        disabled = false,
        class: className = '',
        ...restProps
    }: Props = $props();

    const dispatch = createEventDispatcher<{ change: any }>();

    let isOpen = $state(false);
    let searchTerm = $state('');
    let dropdownElement = $state<HTMLElement>();
    let selectElement = $state<HTMLElement>();
    let dropdownStyle = $state('');

    let filteredOptions = $derived(
        options.filter(option =>
            option.label.toLowerCase().includes(searchTerm.toLowerCase())
        )
    );

    let selectedLabel = $derived(
        options.find(opt => opt.value === selected)?.label || ''
    );

    onMount(() => {
        // Update dropdown position on mount
        updateDropdownPosition();
    });

    function updateDropdownPosition() {
        if (!selectElement) return;
        const rect = selectElement.getBoundingClientRect();
        dropdownStyle = `
            position: fixed;
            top: ${rect.bottom}px;
            left: ${rect.left}px;
            min-width: ${rect.width}px;
        `;
    }

    function toggleDropdown() {
        if (!disabled) {
            isOpen = !isOpen;
            if (isOpen) {
                searchTerm = '';
                // Use next tick to ensure the element is rendered before getting its position
                Promise.resolve().then(updateDropdownPosition);
            }
        }
    }

    function selectOption(option: { value: any; label: string }) {
        selected = option.value;
        isOpen = false;
        searchTerm = '';
        dispatch('change', selected);
        if (restProps.onChange) {
            restProps.onChange(selected);
        }
    }

    function handleClickOutside(event: MouseEvent) {
        if (selectElement && !selectElement.contains(event.target as Node)) {
            isOpen = false;
        }
    }

    $effect(() => {
        if (isOpen) {
            window.addEventListener('scroll', updateDropdownPosition, true);
            window.addEventListener('resize', updateDropdownPosition);
        }
        return () => {
            window.removeEventListener('scroll', updateDropdownPosition, true);
            window.removeEventListener('resize', updateDropdownPosition);
        };
    });
</script>

<svelte:window onclick={handleClickOutside} />

<div
    bind:this={selectElement}
    {id}
    class="form-control form-select select-container {className}"
    class:disabled
    class:show={isOpen}
    onclick={toggleDropdown}
    onkeydown={(e) => e.key === 'Enter' && toggleDropdown()}
    role="combobox"
    aria-haspopup="listbox"
    aria-expanded={isOpen}
    tabindex={disabled ? -1 : 0}
    {...restProps}
>
    <span class:text-muted={!selected}>{selectedLabel || placeholder}</span>

    {#if isOpen}
        <div class="pt-0 dropdown-menu show" bind:this={dropdownElement} style={dropdownStyle}>
            <div class="p-2">
                <input
                    type="text"
                    class="form-control form-control-sm"
                    placeholder={searchPlaceholder}
                    bind:value={searchTerm}
                    onclick={(e) => e.stopPropagation()}
                    autofocus
                />
            </div>
            
            <div class="options-list">
                {#each filteredOptions as option}
                    <button
                        type="button"
                        class="dropdown-item small"
                        class:active={option.value === selected}
                        onclick={(e) => {
                            e.stopPropagation();
                            selectOption(option);
                        }}
                        onkeydown={(e) => e.key === 'Enter' && selectOption(option)}
                        role="option"
                        aria-selected={option.value === selected}
                    >
                        {option.label}
                    </button>
                {/each}
                {#if filteredOptions.length === 0}
                    <div class="dropdown-item text-muted disabled">No options found</div>
                {/if}
            </div>
        </div>
    {/if}
</div>

<style>
    .select-container {
        position: relative;
        cursor: default;
    }

    .dropdown-menu {
        /* position is now set dynamically */
        z-index: 1000;
        width: max-content; /* Allow dropdown to grow with its content */
    }

    .options-list {
        max-height: 40vh;
        overflow-y: auto;
    }
</style>
