/**
 * Entity Selector - Utilities Module
 * Helper functions: escape, validation, icons, search history
 * @partial _utils.js (must be loaded first)
 *
 * EXTRACTION SOURCE: assets/js/admin/entity-selector.js
 * Lines: 7552-7570 (escapeHtml, escapeAttr)
 *        7577-7590 (getEntityTypeLabel)
 *        6289-6350 (validate, showValidationError, clearValidationError)
 *        7115-7137 (showRangeInputError)
 *        7728-7745 (getBlockMode, isBlockSingleMode)
 *        7707-7723 (getCurrentSingleSelection)
 *        5411-5467 (search history methods)
 */

(function($) {
    'use strict';

    // Create mixin namespace
    window._EntitySelectorMixins = window._EntitySelectorMixins || {};

    // ---------------------------------------------------------------
    // Icon framework detection & FA4 mapping (module-level singleton)
    // ---------------------------------------------------------------
    var _iconMode = null;

    /**
     * Material Icons → FontAwesome 4 class mapping.
     * FA4 uses class-based icons (icon-name), Material uses text content.
     */
    var FA4_MAP = {
        'account_tree':             'icon-sitemap',
        'add':                      'icon-plus',
        'add_box':                  'icon-plus-square',
        'arrow_downward':           'icon-sort-desc',
        'arrow_drop_down':          'icon-caret-down',
        'arrow_right':              'icon-chevron-right',
        'arrow_upward':             'icon-sort-asc',
        'block':                    'icon-ban',
        'brush':                    'icon-paint-brush',
        'business':                 'icon-building',
        'check':                    'icon-check',
        'check_box':                'icon-check-square',
        'check_box_outline_blank':  'icon-square-o',
        'check_circle':             'icon-check-circle',
        'close':                    'icon-times',
        'delete':                   'icon-trash',
        'description':              'icon-file-text',
        'error':                    'icon-exclamation-circle',
        'event':                    'icon-calendar',
        'event_busy':               'icon-calendar-times-o',
        'expand_less':              'icon-chevron-up',
        'expand_more':              'icon-chevron-down',
        'filter_list':              'icon-filter',
        'flag':                     'icon-flag',
        'folder':                   'icon-folder',
        'folder_open':              'icon-folder-open',
        'indeterminate_check_box':  'icon-minus-square',
        'info':                     'icon-info-circle',
        'inventory_2':              'icon-archive',
        'label':                    'icon-tag',
        'language':                 'icon-globe',
        'lightbulb':                'icon-lightbulb-o',
        'list':                     'icon-list',
        'list_alt':                 'icon-list-alt',
        'local_shipping':           'icon-truck',
        'lock':                     'icon-lock',
        'my_location':              'icon-crosshairs',
        'open_in_full':             'icon-expand',
        'payments':                 'icon-credit-card',
        'progress_activity':        'icon-circle-o-notch',
        'schedule':                 'icon-clock-o',
        'search':                   'icon-search',
        'shopping_cart':            'icon-shopping-cart',
        'shuffle':                  'icon-random',
        'sort':                     'icon-sort',
        'sort_by_alpha':            'icon-sort-alpha-asc',
        'star':                     'icon-star',
        'sync':                     'icon-refresh',
        'tune':                     'icon-sliders',
        'visibility':               'icon-eye',
        'warning':                  'icon-warning',
        'widgets':                  'icon-th-large'
    };

    /**
     * Reverse map: FontAwesome 4 class → Material Icons name.
     * Built once lazily from FA4_MAP + extra mappings for FA4 names
     * that don't appear as values in FA4_MAP.
     */
    var _REVERSE_FA4_MAP = null;

    var EXTRA_REVERSE_MAPPINGS = {
        'icon-cube':          'inventory',
        'icon-folder-o':      'folder',
        'icon-file-text-o':   'description',
        'icon-briefcase':     'work',
        'icon-user':          'person',
        'icon-users':         'group',
        'icon-money':         'payments',
        'icon-tasks':         'checklist',
        'icon-calculator':    'calculate',
        'icon-asterisk':      'star',
        'icon-bar-chart':     'bar_chart',
        'icon-cogs':          'settings',
        'icon-cog':           'settings',
        'icon-tags':          'label',
        'icon-list-ul':       'list',
        'icon-th':            'grid_view',
        'icon-certificate':   'verified',
        'icon-power-off':     'power_settings_new',
        'icon-circle-o':      'radio_button_unchecked'
    };

    function getReverseFa4Map() {
        if (_REVERSE_FA4_MAP !== null) return _REVERSE_FA4_MAP;
        _REVERSE_FA4_MAP = {};
        // Invert FA4_MAP: value → key
        for (var material in FA4_MAP) {
            if (FA4_MAP.hasOwnProperty(material)) {
                var fa4Class = FA4_MAP[material];
                if (!_REVERSE_FA4_MAP[fa4Class]) {
                    _REVERSE_FA4_MAP[fa4Class] = material;
                }
            }
        }
        // Merge extras
        for (var fa4 in EXTRA_REVERSE_MAPPINGS) {
            if (EXTRA_REVERSE_MAPPINGS.hasOwnProperty(fa4) && !_REVERSE_FA4_MAP[fa4]) {
                _REVERSE_FA4_MAP[fa4] = EXTRA_REVERSE_MAPPINGS[fa4];
            }
        }
        return _REVERSE_FA4_MAP;
    }

    /**
     * Normalize an icon name — handles both Material and FA4 class names.
     * @param {string} name - Icon name (Material or FA4 format)
     * @param {string} mode - 'material' or 'fa4'
     * @returns {object} { name: string, extra: string, rawFa4: boolean }
     */
    function normalizeIconName(name, mode) {
        var extra = '';
        var rawFa4 = false;

        if (name.indexOf('icon-') === 0) {
            // FA4 class name input — may have extra classes (e.g. "icon-power-off text-success")
            var spaceIdx = name.indexOf(' ');
            var fa4Class = (spaceIdx !== -1) ? name.substring(0, spaceIdx) : name;
            if (spaceIdx !== -1) extra = name.substring(spaceIdx + 1);

            if (mode === 'material') {
                var reverseMap = getReverseFa4Map();
                var materialName = reverseMap[fa4Class];
                if (materialName) {
                    return { name: materialName, extra: extra, rawFa4: false };
                }
                // Fallback: strip 'icon-' and convert hyphens to underscores
                var fallback = fa4Class.substring(5).replace(/-/g, '_');
                return { name: fallback, extra: extra, rawFa4: false };
            }

            // FA4 mode + FA4 input — use as-is
            return { name: fa4Class, extra: extra, rawFa4: true };
        }

        // Material Icons name — pass through
        return { name: name, extra: extra, rawFa4: false };
    }

    /**
     * Detect icon framework: 'material' (PS 8+/9+) or 'fa4' (PS 1.6/1.7).
     * Checks PHP-set data attribute first, falls back to font detection.
     */
    function detectIconMode() {
        if (_iconMode !== null) return _iconMode;

        // 1. PHP sets data-icon-mode on the wrapper
        var $w = $('.entity-selector-trait[data-icon-mode], .target-conditions-trait[data-icon-mode]').first();
        if ($w.length && $w.data('icon-mode')) {
            _iconMode = $w.data('icon-mode');
            return _iconMode;
        }

        // 2. Fallback: probe whether Material Icons font is loaded
        var test = document.createElement('i');
        test.className = 'material-icons';
        test.style.cssText = 'position:absolute;left:-9999px;top:-9999px;font-size:16px;pointer-events:none';
        test.textContent = 'check';
        (document.body || document.documentElement).appendChild(test);
        var family = (window.getComputedStyle(test).fontFamily || '').toLowerCase();
        test.parentNode.removeChild(test);

        _iconMode = (family.indexOf('material') !== -1) ? 'material' : 'fa4';
        return _iconMode;
    }

    // Utility functions mixin
    window._EntitySelectorMixins.utils = {

        /**
         * Debounce function - delays execution until after wait milliseconds
         * @param {Function} func - Function to debounce
         * @param {number} wait - Milliseconds to wait
         * @returns {Function} Debounced function
         */
        debounce: function(func, wait) {
            var timeout;
            return function() {
                var context = this;
                var args = arguments;
                clearTimeout(timeout);
                timeout = setTimeout(function() {
                    func.apply(context, args);
                }, wait);
            };
        },

        escapeHtml: function(str) {
            if (str === null || str === undefined) return '';
            return String(str)
                .replace(/&/g, '&amp;')
                .replace(/</g, '&lt;')
                .replace(/>/g, '&gt;')
                .replace(/"/g, '&quot;')
                .replace(/'/g, '&#039;');
        },

        escapeAttr: function(str) {
            if (str === null || str === undefined) return '';
            return String(str)
                .replace(/&/g, '&amp;')
                .replace(/</g, '&lt;')
                .replace(/>/g, '&gt;')
                .replace(/"/g, '&quot;')
                .replace(/'/g, '&#039;');
        },

        /**
         * Icon helper — returns HTML for an icon that works on PS 1.6 through 9.x.
         * Accepts both Material Icons names and FA4 class names as input.
         * Automatically uses Material Icons (PS 8+/9+) or FontAwesome 4 (PS 1.6/1.7).
         *
         * @param {string} name - Icon name (Material or FA4 format, e.g. 'search', 'icon-cube')
         * @param {string} [extraClass] - Additional CSS class(es) (e.g. 'es-spin', 'method-trigger-icon')
         * @returns {string} HTML string for an <i> element
         */
        esIcon: function(name, extraClass) {
            var mode = detectIconMode();
            var normalized = normalizeIconName(name, mode);
            var iconName = normalized.name;
            // Merge extra classes from normalization
            if (normalized.extra) {
                extraClass = extraClass ? extraClass + ' ' + normalized.extra : normalized.extra;
            }

            if (mode === 'material') {
                var cls = 'material-icons es-icon';
                if (extraClass) cls += ' ' + extraClass;
                return '<i class="' + cls + '">' + iconName + '</i>';
            }
            // FA4 mode
            if (normalized.rawFa4) {
                // Input was already an FA4 class — use directly
                var cls = iconName + ' es-icon';
            } else {
                // Input was Material — map to FA4
                var cls = (FA4_MAP[iconName] || 'icon-circle') + ' es-icon';
            }
            if (extraClass) cls += ' ' + extraClass;
            return '<i class="' + cls + '"></i>';
        },

        /**
         * Update an existing <i> icon element to show a different icon.
         * Handles both Material Icons and FA4 modes.
         * Accepts both Material Icons names and FA4 class names as input.
         *
         * @param {jQuery} $el - The <i> element to update
         * @param {string} name - Icon name (Material or FA4 format)
         * @param {string} [extraClass] - Additional CSS class(es) to preserve
         */
        esIconUpdate: function($el, name, extraClass) {
            var mode = detectIconMode();
            var normalized = normalizeIconName(name, mode);
            var iconName = normalized.name;
            if (normalized.extra) {
                extraClass = extraClass ? extraClass + ' ' + normalized.extra : normalized.extra;
            }

            if (mode === 'material') {
                var cls = 'material-icons es-icon';
                if (extraClass) cls += ' ' + extraClass;
                $el.attr('class', cls).text(iconName);
            } else {
                if (normalized.rawFa4) {
                    var cls = iconName + ' es-icon';
                } else {
                    var cls = (FA4_MAP[iconName] || 'icon-circle') + ' es-icon';
                }
                if (extraClass) cls += ' ' + extraClass;
                $el.attr('class', cls).text('');
            }
        },

        getEntityTypeIcon: function(entityType) {
            var icons = {
                'products': 'shopping_cart',
                'categories': 'folder_open',
                'manufacturers': 'business',
                'suppliers': 'local_shipping',
                'attributes': 'list_alt',
                'features': 'label',
                'cms': 'description',
                'cms_categories': 'folder'
            };
            return icons[entityType] || 'widgets';
        },

        getEntityTypeLabel: function(entityType) {
            var trans = this.config.trans || {};
            var labels = {
                'products': trans.product || 'Product',
                'categories': trans.category || 'Category',
                'manufacturers': trans.manufacturer || 'Manufacturer',
                'suppliers': trans.supplier || 'Supplier',
                'attributes': trans.attribute || 'Attribute',
                'features': trans.feature || 'Feature',
                'cms': trans.cms_page || 'CMS Page',
                'cms_categories': trans.cms_category || 'CMS Category'
            };
            return labels[entityType] || entityType;
        },

        validate: function() {
            var isRequired = this.$wrapper.data('required') === 1 || this.$wrapper.data('required') === '1';
            if (!isRequired) return true;

            var hasData = false;
            this.$wrapper.find('.target-block').each(function() {
                if ($(this).find('.selection-group').length > 0) {
                    hasData = true;
                    return false;
                }
            });

            if (!hasData) {
                this.showValidationError();
                return false;
            }

            this.clearValidationError();
            return true;
        },

        showValidationError: function() {
            this.$wrapper.addClass('has-validation-error');
            var message = this.$wrapper.data('required-message') || 'Please select at least one item';
            this.$wrapper.find('.trait-validation-error').remove();
            var $error = $('<div>', {
                class: 'trait-validation-error',
                html: this.esIcon('warning') + ' ' + message
            });
            this.$wrapper.find('.condition-trait-header').after($error);
            $('html, body').animate({ scrollTop: this.$wrapper.offset().top - 100 }, 300);
            if (!this.$wrapper.find('.condition-trait-body').is(':visible')) {
                this.$wrapper.find('.condition-trait-body').slideDown(200);
                this.$wrapper.removeClass('collapsed');
            }
        },

        clearValidationError: function() {
            this.$wrapper.removeClass('has-validation-error');
            this.$wrapper.find('.trait-validation-error').remove();
        },

        getBlockMode: function(blockType) {
            var blockDef = this.config.blocks[blockType];
            return (blockDef && blockDef.mode) ? blockDef.mode : 'multi';
        },

        isBlockSingleMode: function(blockType) {
            return this.getBlockMode(blockType) === 'single';
        },

        getCurrentSingleSelection: function() {
            if ((this.config.mode || 'multi') !== 'single') return null;
            var $chip = this.$wrapper.find('.entity-chips .entity-chip').first();
            if ($chip.length) {
                var $block = $chip.closest('.target-block');
                return {
                    name: $chip.find('.chip-name').text() || $chip.data('id'),
                    entityType: $block.data('block-type') || 'item'
                };
            }
            return null;
        },

        /**
         * Check if entity type supports tree browsing
         */
        supportsTreeBrowsing: function(entityType) {
            return entityType === 'categories' || entityType === 'cms_categories';
        }
    };

})(jQuery);
