/**
 * Custom Dropdown Component
 *
 * This module provides functionality for custom dropdown menus with filtering and keyboard navigation.
 * It can be used across the application for consistent dropdown behavior.
 */
(function() {
    'use strict';

    // Make the setupCustomDropdown function available globally
    window.setupCustomDropdown = setupCustomDropdown;

    // Also export the updateDropdownOptions function
    window.updateDropdownOptions = updateDropdownOptions;

    // Keep a registry of inputs and their associated options functions
    const dropdownRegistry = {};

    /**
     * Update the options for an existing dropdown without destroying it
     * @param {HTMLElement} input - The input element
     * @param {Array} newOptions - New options array to use [{value: string, label: string}]
     */
    function updateDropdownOptions(input, newOptions) {
        if (!input || !input.id) {
            console.warn('Cannot update dropdown: Invalid input element');
            return;
        }

        // Check if dropdown is registered
        if (!dropdownRegistry[input.id]) {
            console.warn(`Dropdown ${input.id} not found in registry, unable to update options`);
            return;
        }

        const dropdownInfo = dropdownRegistry[input.id];

        // Update the options getter function to return new options
        dropdownInfo.getOptions = () => newOptions;

        // If dropdown is currently open, update its content
        const dropdownList = document.getElementById(`${dropdownInfo.dropdownId}-list`);
        if (dropdownList && window.getComputedStyle(dropdownList).display !== 'none') {
            console.log(`Dropdown ${input.id} is open, updating content in place`);

            // Save scroll position
            const scrollPos = dropdownList.scrollTop;

            // Update dropdown content
            const filteredData = dropdownInfo.getOptions();
            // Clear dropdown list using safe DOM methods
            while (dropdownList.firstChild) {
                dropdownList.removeChild(dropdownList.firstChild);
            }

            if (filteredData.length === 0) {
                // Create no results message using safe DOM methods
                const noResultsDiv = document.createElement('div');
                noResultsDiv.className = 'ldr-custom-dropdown-no-results';
                noResultsDiv.textContent = dropdownInfo.noResultsText;
                dropdownList.appendChild(noResultsDiv);
                return;
            }

            filteredData.forEach((item, index) => {
                const div = document.createElement('div');
                div.className = 'ldr-custom-dropdown-item';

                // Use safe text content instead of innerHTML to prevent XSS
                window.safeSetTextContent(div, item.label);
                div.setAttribute('data-value', item.value);
                div.addEventListener('click', () => {
                    // Set display value
                    input.value = item.label;
                    // Update hidden input if exists
                    const hiddenInput = document.getElementById(`${input.id}_hidden`);
                    if (hiddenInput) {
                        hiddenInput.value = item.value;
                        hiddenInput.dispatchEvent(new Event('change', { bubbles: true }));
                    }
                    // Call original onSelect callback
                    if (dropdownInfo.onSelect) {
                        dropdownInfo.onSelect(item.value, item);
                    }
                    // Hide dropdown
                    dropdownList.style.display = 'none';
                });

                dropdownList.appendChild(div);
            });

            // Restore scroll position
            dropdownList.scrollTop = scrollPos;
        } else {
            console.log(`Dropdown ${input.id} is closed, options will update when opened`);
        }

        return true;
    }

    /**
     * Setup a custom dropdown component
     * @param {HTMLElement} input - The input element
     * @param {HTMLElement} dropdownList - The dropdown list element
     * @param {Function} getOptions - Function that returns the current options array [{value: string, label: string}]
     * @param {Function} onSelect - Callback when an item is selected (value, item) => {}
     * @param {boolean} allowCustomValues - Whether to allow values not in the options list
     * @param {string} noResultsText - Text to show when no results are found
     */
    function setupCustomDropdown(input, dropdownList, getOptions, onSelect, allowCustomValues = false, noResultsText = 'No results found.') {
        let selectedIndex = -1;
        let isOpen = false;
        let showAllOptions = false; // Flag to track if we should show all options
        let isClickingDropdown = false; // Flag to track clicks inside dropdown
        let justSelected = false; // Flag to prevent immediate reopening after selection

        // Find the associated hidden input field
        const hiddenInput = document.getElementById(`${input.id}_hidden`);

        // Function to update hidden field
        function updateHiddenField(value) {
            if (hiddenInput) {
                hiddenInput.value = value;
                // Also dispatch a change event on the hidden input to trigger form handling
                hiddenInput.dispatchEvent(new Event('change', { bubbles: true }));
            }
        }

        // Function to filter options
        function filterOptions(searchText, showAll = false) {
            const options = getOptions();
            if (showAll || !searchText.trim()) return options;

            return options.filter(item =>
                item.label.toLowerCase().includes(searchText.toLowerCase()) ||
                item.value.toLowerCase().includes(searchText.toLowerCase())
            );
        }

        // Function to highlight matched text
        function highlightText(text, search) {
            if (!search.trim() || showAllOptions) return text;
            const regex = new RegExp(`(${search.replace(/[.*+?^${}()|[\]\\]/g, '\\$&')})`, 'gi');
            return text.replace(regex, '<span class="highlight">$1</span>');
        }

        // Function to show the dropdown
        function showDropdown() {
            const inputRect = input.getBoundingClientRect();

            // Debug logging
            console.log('Dropdown positioning:', {
                inputLeft: inputRect.left,
                inputBottom: inputRect.bottom,
                scrollY: window.scrollY,
                inputWidth: inputRect.width,
                windowWidth: window.innerWidth,
                windowHeight: window.innerHeight
            });

            // Store original parent for when we close
            if (!dropdownList._originalParent) {
                dropdownList._originalParent = dropdownList.parentNode;
            }

            // Remove from current parent
            if (dropdownList.parentNode) {
                dropdownList.parentNode.removeChild(dropdownList);
            }

            // Append directly to body
            document.body.appendChild(dropdownList);

            // Make dropdown visible
            dropdownList.style.display = 'block';

            // Add active class for dropdown.
            dropdownList.classList.add('ldr-dropdown-active');

            // Add ldr-dropdown-active class to body
            document.body.classList.add('ldr-dropdown-active');

            // Add a small offset (6px) to ensure it's visibly separated from the input
            const verticalOffset = 6;

            // Calculate position relative to viewport
            const left = Math.min(inputRect.left, window.innerWidth - inputRect.width - 10);
            const top = inputRect.bottom + window.scrollY + verticalOffset;

            // Apply the calculated position
            dropdownList.style.left = `${left}px`;
            dropdownList.style.top = `${top}px`;
            dropdownList.style.width = `${inputRect.width}px`;

            // Force DOM reflow to ensure styles are applied
            dropdownList.getBoundingClientRect();

            // Additional styling to ensure visibility
            dropdownList.style.visibility = 'visible';
            dropdownList.style.opacity = '1';

            // Ensure dropdown is visible by bringing it to front
            dropdownList.style.zIndex = '999999';

            input.setAttribute('aria-expanded', 'true');
            isOpen = true;
        }

        // Function to hide the dropdown
        function hideDropdown() {
            // Get current parent
            const currentParent = dropdownList.parentNode;

            // Hide first
            dropdownList.style.display = 'none';
            // Remove active class
            dropdownList.classList.remove('ldr-dropdown-active');

            // Remove ldr-dropdown-active class from body
            document.body.classList.remove('ldr-dropdown-active');

            // Reset position styles
            dropdownList.style.left = '';
            dropdownList.style.top = '';
            dropdownList.style.width = '';

            // Move back to original parent if it exists and we're not already there
            if (dropdownList._originalParent && currentParent !== dropdownList._originalParent) {
                currentParent.removeChild(dropdownList);
                dropdownList._originalParent.appendChild(dropdownList);
            }

            input.setAttribute('aria-expanded', 'false');
            selectedIndex = -1;
            isOpen = false;
            showAllOptions = false; // Reset the flag when closing dropdown
        }

        // Function to update the dropdown
        function updateDropdown() {
            const searchText = input.value;
            const filteredData = filterOptions(searchText, showAllOptions);

            // Clear dropdown list using safe DOM methods
            while (dropdownList.firstChild) {
                dropdownList.removeChild(dropdownList.firstChild);
            }

            if (filteredData.length === 0) {
                // Create no results message using safe DOM methods
                const noResultsDiv = document.createElement('div');
                noResultsDiv.className = 'ldr-custom-dropdown-no-results';
                noResultsDiv.textContent = noResultsText;
                dropdownList.appendChild(noResultsDiv);

                if (allowCustomValues && searchText.trim()) {
                    const customOption = document.createElement('div');
                    customOption.className = 'ldr-custom-dropdown-footer';
                    customOption.textContent = `Press Enter to use "${searchText}"`;
                    dropdownList.appendChild(customOption);
                }

                return;
            }

            filteredData.forEach((item, index) => {
                const div = document.createElement('div');
                div.className = 'ldr-custom-dropdown-item';

                // Sanitize highlighted text to prevent XSS
                const highlightedText = highlightText(item.label, searchText);
                // Allow basic HTML tags for highlighting but escape dangerous content
                window.safeSetInnerHTML(div, highlightedText, true);
                div.setAttribute('data-value', item.value);
                div.addEventListener('click', (e) => {
                    e.preventDefault();
                    e.stopPropagation();
                    // Set display value
                    input.value = item.label;
                    // Update hidden input value
                    updateHiddenField(item.value);
                    // Call onSelect callback
                    onSelect(item.value, item);
                    // Set flag to prevent immediate reopening
                    justSelected = true;
                    // Hide dropdown
                    hideDropdown();
                    // Reset the clicking flag
                    isClickingDropdown = false;
                    // Clear the justSelected flag after a delay
                    setTimeout(() => {
                        justSelected = false;
                    }, 300);
                });

                if (index === selectedIndex) {
                    div.classList.add('active');
                }

                dropdownList.appendChild(div);
            });
        }

        // Input event - filter as user types
        input.addEventListener('input', () => {
            showAllOptions = false; // Reset when typing
            showDropdown();
            updateDropdown();
            selectedIndex = -1;
        });

        // Click event - show all options when clicking in the input
        input.addEventListener('click', (e) => {
            e.stopPropagation();
            // Don't reopen immediately after selection
            if (!justSelected) {
                showAllOptions = true;
                showDropdown();
                updateDropdown();
            }
        });

        // Focus event - show dropdown when input is focused
        input.addEventListener('focus', () => {
            // Don't reopen immediately after selection
            if (!isOpen && !justSelected) {
                showAllOptions = true; // Show all options on focus
                showDropdown();
                updateDropdown();
            }
        });

        // Blur event - close dropdown when tabbing away
        input.addEventListener('blur', (e) => {
            // Small delay to allow click events on dropdown items to fire first
            setTimeout(() => {
                // Don't close if we're clicking inside the dropdown
                if (isClickingDropdown) {
                    return;
                }
                // Check if focus has moved to an element inside the dropdown
                const activeElement = document.activeElement;
                if (!dropdownList.contains(activeElement) && activeElement !== input) {
                    hideDropdown();
                }
            }, 150);
        });

        // Keyboard navigation for dropdown
        input.addEventListener('keydown', (e) => {
            const items = dropdownList.querySelectorAll('.ldr-custom-dropdown-item');

            if (e.key === 'ArrowDown') {
                e.preventDefault();
                if (!isOpen) {
                    showAllOptions = true;
                    showDropdown();
                    updateDropdown();
                    selectedIndex = 0;
                } else {
                    selectedIndex = (selectedIndex + 1) % items.length;
                }
            } else if (e.key === 'ArrowUp') {
                e.preventDefault();
                if (!isOpen) {
                    showAllOptions = true;
                    showDropdown();
                    updateDropdown();
                    selectedIndex = items.length - 1;
                } else {
                    selectedIndex = (selectedIndex - 1 + items.length) % items.length;
                }
            } else if (e.key === 'Enter') {
                e.preventDefault();

                if (selectedIndex >= 0 && selectedIndex < items.length) {
                    // Select the highlighted item
                    const selectedItem = items[selectedIndex];
                    const value = selectedItem.getAttribute('data-value');
                    const item = getOptions().find(o => o.value === value);
                    // Update display value
                    input.value = item.label;
                    // Update hidden input
                    updateHiddenField(value);
                    // Call callback
                    onSelect(value, item);
                } else if (items.length > 0 && selectedIndex === -1) {
                    // No item explicitly selected, but there are filtered results
                    // Auto-select the first item in the filtered list
                    const firstItem = items[0];
                    const value = firstItem.getAttribute('data-value');
                    const item = getOptions().find(o => o.value === value);
                    if (item) {
                        // Update display value
                        input.value = item.label;
                        // Update hidden input
                        updateHiddenField(value);
                        // Call callback
                        onSelect(value, item);
                    }
                } else if (allowCustomValues && input.value.trim()) {
                    // Use the custom value
                    const customValue = input.value.trim();
                    // Update hidden input with custom value
                    updateHiddenField(customValue);
                    onSelect(customValue, null);
                }
                hideDropdown();
            } else if (e.key === 'Escape') {
                e.preventDefault();
                hideDropdown();
            }

            // Update selected item styling
            items.forEach((item, index) => {
                if (index === selectedIndex) {
                    item.classList.add('active');
                    // Scroll into view if necessary
                    if (item.offsetTop < dropdownList.scrollTop) {
                        dropdownList.scrollTop = item.offsetTop;
                    } else if (item.offsetTop + item.offsetHeight > dropdownList.scrollTop + dropdownList.offsetHeight) {
                        dropdownList.scrollTop = item.offsetTop + item.offsetHeight - dropdownList.offsetHeight;
                    }
                } else {
                    item.classList.remove('active');
                }
            });
        });

        // Close dropdown when clicking outside
        document.addEventListener('click', () => {
            if (isOpen) {
                hideDropdown();
            }
        });

        // Track mouse events in the dropdown to prevent premature closing
        dropdownList.addEventListener('mousedown', (e) => {
            isClickingDropdown = true;
        });

        dropdownList.addEventListener('mouseup', (e) => {
            // Reset flag after a small delay to ensure click event fires
            setTimeout(() => {
                isClickingDropdown = false;
            }, 200);
        });

        // Prevent clicks in the dropdown from closing it
        dropdownList.addEventListener('click', (e) => {
            e.stopPropagation();
        });

        // Register this dropdown for future updates
        if (input && input.id && dropdownList && dropdownList.id) {
            const dropdownId = dropdownList.id.replace('-list', '');
            console.log(`Registering dropdown: ${input.id} with list ${dropdownId}`);

            dropdownRegistry[input.id] = {
                getOptions: getOptions,
                onSelect: onSelect,
                dropdownId: dropdownId,
                allowCustomValues: allowCustomValues,
                noResultsText: noResultsText
            };
        } else {
            console.warn('Cannot register dropdown: Missing input ID or dropdown list ID');
        }

        // Initial state
        hideDropdown();

        // Return functions that might be needed externally
        return {
            updateDropdown,
            showDropdown,
            hideDropdown,
            setValue: (value, triggerChange = true) => {
                const options = getOptions();
                const matchedOption = options.find(opt => opt.value === value);

                if (matchedOption) {
                    input.value = matchedOption.label;
                } else if (allowCustomValues && value) {
                    input.value = value;
                } else {
                    input.value = '';
                }

                if (triggerChange) {
                    updateHiddenField(value);
                    // Also call onSelect if triggerChange is true
                    if (matchedOption) {
                        onSelect(value, matchedOption);
                    } else {
                        onSelect(value, { value, label: value });
                    }
                } else {
                    // Even if we don't trigger events, we should update the hidden field
                    if (hiddenInput) {
                        hiddenInput.value = value;
                    }
                }
            }
        };
    }
})();
