// static/shared/js/vendor-selector.js
/**
 * Shared Vendor Selector Module
 * =============================
 * Provides a reusable Tom Select-based vendor autocomplete component.
 *
 * Features:
 * - Async search with debouncing (150ms)
 * - Searches by vendor name and code
 * - Dark mode support
 * - Caches recent searches
 * - Graceful fallback if Tom Select not available
 *
 * Usage:
 *   // In Alpine.js component init():
 *   this.$nextTick(() => {
 *       this.vendorSelector = initVendorSelector(this.$refs.vendorSelect, {
 *           onSelect: (vendor) => this.handleVendorSelect(vendor),
 *           onClear: () => this.handleVendorClear(),
 *           minChars: 2,
 *           maxOptions: 50
 *       });
 *   });
 *
 *   // To programmatically set a value:
 *   this.vendorSelector.setValue(vendorId);
 *
 *   // To clear:
 *   this.vendorSelector.clear();
 */

const vendorSelectorLog = window.LogConfig?.loggers?.vendorSelector ||
    window.LogConfig?.createLogger?.('vendorSelector', false) ||
    { info: console.log, warn: console.warn, error: console.error };  // noqa: js-001 - fallback if logger not ready

/**
 * Check if Tom Select is available, with retry logic
 * @param {Function} callback - Called when Tom Select is available
 * @param {number} maxRetries - Maximum retry attempts
 * @param {number} retryDelay - Delay between retries in ms
 */
function waitForTomSelect(callback, maxRetries = 20, retryDelay = 100) {
    let retries = 0;

    function check() {
        if (typeof TomSelect !== 'undefined') {
            callback();
        } else if (retries < maxRetries) {
            retries++;
            vendorSelectorLog.info(`Waiting for TomSelect... (attempt ${retries}/${maxRetries})`);
            setTimeout(check, retryDelay);
        } else {
            vendorSelectorLog.error('TomSelect not available after maximum retries');
        }
    }

    check();
}

/**
 * Initialize a vendor selector on the given element
 * @param {HTMLElement} selectElement - The select element to enhance
 * @param {Object} options - Configuration options
 * @param {Function} options.onSelect - Callback when vendor is selected (receives vendor object)
 * @param {Function} options.onClear - Callback when selection is cleared
 * @param {number} options.minChars - Minimum characters before search (default: 2)
 * @param {number} options.maxOptions - Maximum options to show (default: 50)
 * @param {string} options.placeholder - Placeholder text
 * @param {string} options.apiEndpoint - API endpoint for search (default: '/admin/vendors')
 * @returns {Object} Controller object with setValue() and clear() methods
 */
function initVendorSelector(selectElement, options = {}) {
    if (!selectElement) {
        vendorSelectorLog.error('Vendor selector element not provided');
        return null;
    }

    const config = {
        minChars: options.minChars || 2,
        maxOptions: options.maxOptions || 50,
        placeholder: options.placeholder || selectElement.getAttribute('placeholder') || 'Search vendor by name or code...',
        apiEndpoint: options.apiEndpoint || '/admin/vendors',  // Note: apiClient adds /api/v1 prefix
        onSelect: options.onSelect || (() => {}),
        onClear: options.onClear || (() => {})
    };

    let tomSelectInstance = null;

    // Controller object returned to caller
    const controller = {
        /**
         * Set the selected vendor by ID
         * @param {number} vendorId - Vendor ID to select
         * @param {Object} vendorData - Optional vendor data to avoid API call
         */
        setValue: async function(vendorId, vendorData = null) {
            if (!tomSelectInstance) return;

            if (vendorData) {
                // Add option and set value
                tomSelectInstance.addOption({
                    id: vendorData.id,
                    name: vendorData.name,
                    vendor_code: vendorData.vendor_code
                });
                tomSelectInstance.setValue(vendorData.id, true);
            } else if (vendorId) {
                // Fetch vendor data and set
                try {
                    const response = await apiClient.get(`${config.apiEndpoint}/${vendorId}`);
                    tomSelectInstance.addOption({
                        id: response.id,
                        name: response.name,
                        vendor_code: response.vendor_code
                    });
                    tomSelectInstance.setValue(response.id, true);
                } catch (error) {
                    vendorSelectorLog.error('Failed to load vendor:', error);
                }
            }
        },

        /**
         * Clear the selection
         */
        clear: function() {
            if (tomSelectInstance) {
                tomSelectInstance.clear();
            }
        },

        /**
         * Get the Tom Select instance
         */
        getInstance: function() {
            return tomSelectInstance;
        },

        /**
         * Destroy the Tom Select instance
         */
        destroy: function() {
            if (tomSelectInstance) {
                tomSelectInstance.destroy();
                tomSelectInstance = null;
            }
        }
    };

    // Initialize Tom Select when available
    waitForTomSelect(() => {
        vendorSelectorLog.info('Initializing vendor selector');

        tomSelectInstance = new TomSelect(selectElement, {
            valueField: 'id',
            labelField: 'name',
            searchField: ['name', 'vendor_code'],
            maxOptions: config.maxOptions,
            placeholder: config.placeholder,

            // Async search with debouncing
            load: async function(query, callback) {
                if (query.length < config.minChars) {
                    callback([]);
                    return;
                }

                try {
                    const response = await apiClient.get(
                        `${config.apiEndpoint}?search=${encodeURIComponent(query)}&limit=${config.maxOptions}`
                    );

                    const vendors = (response.vendors || []).map(v => ({
                        id: v.id,
                        name: v.name,
                        vendor_code: v.vendor_code
                    }));

                    vendorSelectorLog.info(`Found ${vendors.length} vendors for "${query}"`);
                    callback(vendors);
                } catch (error) {
                    vendorSelectorLog.error('Vendor search failed:', error);
                    callback([]);
                }
            },

            // Custom rendering
            render: {
                option: function(data, escape) {
                    return `<div class="flex justify-between items-center py-1">
                        <span class="font-medium">${escape(data.name)}</span>
                        <span class="text-xs text-gray-400 dark:text-gray-500 ml-2 font-mono">${escape(data.vendor_code)}</span>
                    </div>`;
                },
                item: function(data, escape) {
                    return `<div class="flex items-center gap-2">
                        <span>${escape(data.name)}</span>
                        <span class="text-xs text-gray-400 font-mono">(${escape(data.vendor_code)})</span>
                    </div>`;
                },
                no_results: function() {
                    return '<div class="no-results py-2 px-3 text-gray-500 dark:text-gray-400">No vendors found</div>';
                },
                loading: function() {
                    return '<div class="loading py-2 px-3 text-gray-500 dark:text-gray-400">Searching...</div>';
                }
            },

            // Event handlers
            onChange: function(value) {
                if (value) {
                    const selectedOption = this.options[value];
                    if (selectedOption) {
                        vendorSelectorLog.info('Vendor selected:', selectedOption);
                        config.onSelect({
                            id: parseInt(value),
                            name: selectedOption.name,
                            vendor_code: selectedOption.vendor_code
                        });
                    }
                } else {
                    vendorSelectorLog.info('Vendor selection cleared');
                    config.onClear();
                }
            },

            // Performance settings
            loadThrottle: 150,  // Debounce search requests
            closeAfterSelect: true,
            hideSelected: false,
            persist: true,  // Cache options
            createOnBlur: false,
            create: false
        });

        vendorSelectorLog.info('Vendor selector initialized');
    });

    return controller;
}

// Export to window for global access
window.initVendorSelector = initVendorSelector;
