// static/shared/js/store-selector.js
/**
 * Shared Store Selector Module
 * =============================
 * Provides a reusable Tom Select-based store autocomplete component.
 *
 * Features:
 * - Async search with debouncing (150ms)
 * - Searches by store 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.storeSelector = initStoreSelector(this.$refs.storeSelect, {
 *           onSelect: (store) => this.handleStoreSelect(store),
 *           onClear: () => this.handleStoreClear(),
 *           minChars: 2,
 *           maxOptions: 50
 *       });
 *   });
 *
 *   // To programmatically set a value:
 *   this.storeSelector.setValue(storeId);
 *
 *   // To clear:
 *   this.storeSelector.clear();
 */

const storeSelectorLog = window.LogConfig?.loggers?.storeSelector ||
    window.LogConfig?.createLogger?.('storeSelector', 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++;
            storeSelectorLog.info(`Waiting for TomSelect... (attempt ${retries}/${maxRetries})`);
            setTimeout(check, retryDelay);
        } else {
            storeSelectorLog.error('TomSelect not available after maximum retries');
        }
    }

    check();
}

/**
 * Initialize a store selector on the given element
 * @param {HTMLElement} selectElement - The select element to enhance
 * @param {Object} options - Configuration options
 * @param {Function} options.onSelect - Callback when store is selected (receives store 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/stores')
 * @returns {Object} Controller object with setValue() and clear() methods
 */
function initStoreSelector(selectElement, options = {}) {
    if (!selectElement) {
        storeSelectorLog.error('Store selector element not provided');
        return null;
    }

    const config = {
        minChars: options.minChars || 2,
        maxOptions: options.maxOptions || 50,
        placeholder: options.placeholder || selectElement.getAttribute('placeholder') || 'Search store by name or code...',
        apiEndpoint: options.apiEndpoint || '/admin/stores',  // 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 store by ID
         * @param {number} storeId - Store ID to select
         * @param {Object} storeData - Optional store data to avoid API call
         */
        setValue: async function(storeId, storeData = null) {
            if (!tomSelectInstance) return;

            if (storeData) {
                // Add option and set value
                tomSelectInstance.addOption({
                    id: storeData.id,
                    name: storeData.name,
                    store_code: storeData.store_code
                });
                tomSelectInstance.setValue(storeData.id, true);
            } else if (storeId) {
                // Fetch store data and set
                try {
                    const response = await apiClient.get(`${config.apiEndpoint}/${storeId}`);
                    tomSelectInstance.addOption({
                        id: response.id,
                        name: response.name,
                        store_code: response.store_code
                    });
                    tomSelectInstance.setValue(response.id, true);
                } catch (error) {
                    storeSelectorLog.error('Failed to load store:', 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(() => {
        storeSelectorLog.info('Initializing store selector');

        tomSelectInstance = new TomSelect(selectElement, {
            valueField: 'id',
            labelField: 'name',
            searchField: ['name', 'store_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 sep = config.apiEndpoint.includes('?') ? '&' : '?';
                    const response = await apiClient.get(
                        `${config.apiEndpoint}${sep}search=${encodeURIComponent(query)}&limit=${config.maxOptions}`
                    );

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

                    storeSelectorLog.info(`Found ${stores.length} stores for "${query}"`);
                    callback(stores);
                } catch (error) {
                    storeSelectorLog.error('Store 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.store_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.store_code)})</span>
                    </div>`;
                },
                no_results: function() {
                    return '<div class="no-results py-2 px-3 text-gray-500 dark:text-gray-400">No stores 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) {
                        storeSelectorLog.info('Store selected:', selectedOption);
                        config.onSelect({
                            id: parseInt(value),
                            name: selectedOption.name,
                            store_code: selectedOption.store_code
                        });
                    }
                } else {
                    storeSelectorLog.info('Store selection cleared');
                    config.onClear();
                }
            },

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

        storeSelectorLog.info('Store selector initialized');
    });

    return controller;
}

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