// static/shared/js/entity-selector.js
/**
 * Shared Entity Selector Module
 * ==============================
 * A configurable Tom Select-based autocomplete for any entity type.
 * Generalizes store-selector.js to work with stores, merchants, platforms, etc.
 *
 * Usage:
 *   const selector = initEntitySelector(this.$refs.merchantSelect, {
 *       apiEndpoint: '/admin/merchants',
 *       responseKey: 'merchants',
 *       searchFields: ['name'],
 *       valueField: 'id',
 *       labelField: 'name',
 *       codeField: null,
 *       onSelect: (entity) => this.onMerchantSelected(entity),
 *       onClear: () => this.onMerchantCleared()
 *   });
 *
 *   selector.setValue(merchantId, merchantData);
 *   selector.clear();
 */

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

/**
 * Wait for Tom Select to be available
 */
function waitForTomSelectReady(callback, maxRetries = 20, retryDelay = 100) {
    let retries = 0;

    function check() {
        if (typeof TomSelect !== 'undefined') {
            callback();
        } else if (retries < maxRetries) {
            retries++;
            setTimeout(check, retryDelay);
        } else {
            entitySelectorLog.error('TomSelect not available after maximum retries');
        }
    }

    check();
}

/**
 * Initialize an entity selector on the given element
 * @param {HTMLElement} selectElement - The select element to enhance
 * @param {Object} options - Configuration options
 * @param {string} options.apiEndpoint - API endpoint for search (e.g. '/admin/merchants')
 * @param {string} options.responseKey - Key in API response containing the array (e.g. 'merchants')
 * @param {string} options.valueField - Field used as option value (default: 'id')
 * @param {string} options.labelField - Field used as display label (default: 'name')
 * @param {string[]} options.searchFields - Fields to search on (default: ['name'])
 * @param {string|null} options.codeField - Optional secondary code field for display (e.g. 'store_code')
 * @param {Function} options.onSelect - Callback when entity is selected (receives entity 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.noResultsText - Text when no results (default: 'No results found')
 * @returns {Object} Controller object with setValue(), clear(), getInstance(), destroy()
 */
function initEntitySelector(selectElement, options = {}) {
    if (!selectElement) {
        entitySelectorLog.error('Entity selector element not provided');
        return null;
    }

    const config = {
        apiEndpoint: options.apiEndpoint || '/admin/stores',
        responseKey: options.responseKey || 'stores',
        valueField: options.valueField || 'id',
        labelField: options.labelField || 'name',
        searchFields: options.searchFields || ['name'],
        codeField: options.codeField || null,
        minChars: options.minChars || 2,
        maxOptions: options.maxOptions || 50,
        placeholder: options.placeholder || selectElement.getAttribute('placeholder') || 'Search...',
        noResultsText: options.noResultsText || 'No results found',
        onSelect: options.onSelect || (() => {}),
        onClear: options.onClear || (() => {})
    };

    let tomSelectInstance = null;

    const controller = {
        /**
         * Set the selected entity by ID
         * @param {*} entityId - Entity ID to select
         * @param {Object} entityData - Optional entity data to avoid API call
         */
        setValue: async function(entityId, entityData = null) {
            if (!tomSelectInstance) return;

            if (entityData) {
                const optionData = {};
                optionData[config.valueField] = entityData[config.valueField] || entityId;
                optionData[config.labelField] = entityData[config.labelField];
                if (config.codeField) {
                    optionData[config.codeField] = entityData[config.codeField];
                }
                tomSelectInstance.addOption(optionData);
                tomSelectInstance.setValue(optionData[config.valueField], true);
            } else if (entityId) {
                try {
                    const response = await apiClient.get(`${config.apiEndpoint}/${entityId}`);
                    const optionData = {};
                    optionData[config.valueField] = response[config.valueField] || entityId;
                    optionData[config.labelField] = response[config.labelField];
                    if (config.codeField) {
                        optionData[config.codeField] = response[config.codeField];
                    }
                    tomSelectInstance.addOption(optionData);
                    tomSelectInstance.setValue(optionData[config.valueField], true);
                } catch (error) {
                    entitySelectorLog.error('Failed to load entity:', error);
                }
            }
        },

        clear: function() {
            if (tomSelectInstance) {
                tomSelectInstance.clear();
            }
        },

        getInstance: function() {
            return tomSelectInstance;
        },

        destroy: function() {
            if (tomSelectInstance) {
                tomSelectInstance.destroy();
                tomSelectInstance = null;
            }
        }
    };

    // Initialize Tom Select when available
    waitForTomSelectReady(() => {
        entitySelectorLog.info(`Initializing entity selector (${config.responseKey})`);

        // Build render functions
        const render = {
            option: function(data, escape) {
                if (config.codeField && data[config.codeField]) {
                    return `<div class="flex justify-between items-center py-1">
                        <span class="font-medium">${escape(data[config.labelField])}</span>
                        <span class="text-xs text-gray-400 dark:text-gray-500 ml-2 font-mono">${escape(data[config.codeField])}</span>
                    </div>`;
                }
                return `<div class="py-1"><span class="font-medium">${escape(data[config.labelField])}</span></div>`;
            },
            item: function(data, escape) {
                if (config.codeField && data[config.codeField]) {
                    return `<div class="flex items-center gap-2">
                        <span>${escape(data[config.labelField])}</span>
                        <span class="text-xs text-gray-400 font-mono">(${escape(data[config.codeField])})</span>
                    </div>`;
                }
                return `<div>${escape(data[config.labelField])}</div>`;
            },
            no_results: function() {
                return `<div class="no-results py-2 px-3 text-gray-500 dark:text-gray-400">${config.noResultsText}</div>`;
            },
            loading: function() {
                return '<div class="loading py-2 px-3 text-gray-500 dark:text-gray-400">Searching...</div>';
            }
        };

        tomSelectInstance = new TomSelect(selectElement, {
            valueField: config.valueField,
            labelField: config.labelField,
            searchField: config.searchFields,
            maxOptions: config.maxOptions,
            placeholder: config.placeholder,

            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 items = (response[config.responseKey] || []).map(v => {
                        const item = {};
                        item[config.valueField] = v[config.valueField];
                        item[config.labelField] = v[config.labelField];
                        if (config.codeField) {
                            item[config.codeField] = v[config.codeField];
                        }
                        return item;
                    });

                    entitySelectorLog.info(`Found ${items.length} ${config.responseKey} for "${query}"`);
                    callback(items);
                } catch (error) {
                    entitySelectorLog.error(`${config.responseKey} search failed:`, error);
                    callback([]);
                }
            },

            render: render,

            onChange: function(value) {
                if (value) {
                    const selectedOption = this.options[value];
                    if (selectedOption) {
                        entitySelectorLog.info(`${config.responseKey} selected:`, selectedOption);
                        const entity = {};
                        entity[config.valueField] = config.valueField === 'id' ? parseInt(value) : value;
                        entity[config.labelField] = selectedOption[config.labelField];
                        if (config.codeField) {
                            entity[config.codeField] = selectedOption[config.codeField];
                        }
                        config.onSelect(entity);
                    }
                } else {
                    entitySelectorLog.info(`${config.responseKey} selection cleared`);
                    config.onClear();
                }
            },

            loadThrottle: 150,
            closeAfterSelect: true,
            hideSelected: false,
            persist: true,
            createOnBlur: false,
            create: false
        });

        entitySelectorLog.info(`Entity selector (${config.responseKey}) initialized`);
    });

    return controller;
}

// Convenience wrapper for store selector (backward compatible)
function initStoreSelectorFromEntity(selectElement, options = {}) {
    return initEntitySelector(selectElement, {
        apiEndpoint: options.apiEndpoint || '/admin/stores',
        responseKey: 'stores',
        valueField: 'id',
        labelField: 'name',
        searchFields: ['name', 'store_code'],
        codeField: 'store_code',
        placeholder: options.placeholder || 'Search store by name or code...',
        noResultsText: 'No stores found',
        ...options
    });
}

// Export to window
window.initEntitySelector = initEntitySelector;
