/**
 * AIEO Category Extras — term edit screen runtime.
 *
 * Three pieces of UI on top of the panel rendered server-side:
 *   1. Tab switcher (Hero / Catalog / Related).
 *   2. WP media uploader bound to mobile + desktop image fields.
 *   3. AJAX-backed chip picker for related posts / campaigns.
 *
 * The brand multi-select stays as a native <select multiple> — bounded
 * option count, so no AJAX needed and no need to fight WP's form CSS.
 */

(function ($) {
    'use strict';

    var __ = ( window.wp && window.wp.i18n && window.wp.i18n.__ ) ? window.wp.i18n.__ : function (s) { return s; };
    var _x = ( window.wp && window.wp.i18n && window.wp.i18n._x ) ? window.wp.i18n._x : function (s) { return s; };
    var _n = ( window.wp && window.wp.i18n && window.wp.i18n._n ) ? window.wp.i18n._n : function (s, p, n) { return n === 1 ? s : p; };
    var _sprintf = ( window.wp && window.wp.i18n && window.wp.i18n.sprintf ) ? window.wp.i18n.sprintf : function (s) { return s; };

    var cfg = window.aieoCategoryExtras || {};
    if (!cfg.ajaxurl) return;

    // ── Tabs ────────────────────────────────────────────────────────────

    function initTabs(panel) {
        var tabs   = panel.querySelectorAll('.aieo-ce-tab');
        var panes  = panel.querySelectorAll('.aieo-ce-tabpanel');
        tabs.forEach(function (tab) {
            tab.addEventListener('click', function (e) {
                e.preventDefault();
                var key = tab.getAttribute('data-aieo-ce-tab');
                tabs.forEach(function (t) {
                    var on = t === tab;
                    t.classList.toggle('is-active', on);
                    t.setAttribute('aria-selected', on ? 'true' : 'false');
                });
                panes.forEach(function (p) {
                    p.classList.toggle('is-active', p.getAttribute('data-aieo-ce-pane') === key);
                });
                refreshTinyMCEInActivePane(panel);
            });
        });
    }

    /**
     * TinyMCE editors that boot inside a `display:none` tab end up with a
     * collapsed iframe + missing toolbar because their layout calc runs on
     * a 0-height parent. We trigger a repaint when the tab becomes
     * visible so the editor re-measures itself.
     */
    function refreshTinyMCEInActivePane(panel) {
        if (typeof window.tinymce === 'undefined' || !window.tinymce.editors) return;
        var active = panel.querySelector('.aieo-ce-tabpanel.is-active');
        if (!active) return;
        var areas = active.querySelectorAll('textarea.wp-editor-area');
        areas.forEach(function (ta) {
            var ed = window.tinymce.get(ta.id);
            if (!ed) return;
            try {
                ed.execCommand('mceRepaint');
                // Some skins also need a layout reflow on the body iframe.
                if (ed.getWin && ed.getWin()) ed.getWin().dispatchEvent(new Event('resize'));
            } catch (e) { /* noop */ }
        });
    }

    // ── Image uploader (WP media modal) ─────────────────────────────────

    function initImageField(field) {
        if (!window.wp || !wp.media) return;
        var hiddenInput = field.querySelector('input[type=hidden]');
        var preview     = field.querySelector('.aieo-ce-image-preview');
        var pickBtn     = field.querySelector('.aieo-ce-image-pick');
        var clearBtn    = field.querySelector('.aieo-ce-image-clear');
        var frame;

        pickBtn.addEventListener('click', function (e) {
            e.preventDefault();
            if (!frame) {
                frame = wp.media({
                    title:    cfg.i18n.pickImage,
                    button:   { text: cfg.i18n.useImage },
                    library:  { type: 'image' },
                    multiple: false
                });
                frame.on('select', function () {
                    var att = frame.state().get('selection').first().toJSON();
                    hiddenInput.value = att.id;
                    var url = (att.sizes && att.sizes.medium && att.sizes.medium.url) || att.url;
                    preview.innerHTML = '<img src="' + url + '" alt="" />';
                    preview.style.display = '';
                    clearBtn.style.display = '';
                });
            }
            frame.open();
        });
        clearBtn.addEventListener('click', function (e) {
            e.preventDefault();
            hiddenInput.value = '';
            preview.innerHTML = '';
            preview.style.display = 'none';
            clearBtn.style.display = 'none';
        });
    }

    // ── Chip picker (AJAX-backed) ───────────────────────────────────────

    function initSearchField(field) {
        var input    = field.querySelector('.aieo-ce-search-input');
        var results  = field.querySelector('.aieo-ce-search-results');
        var chips    = field.querySelector('.aieo-ce-chips');
        var name     = chips.getAttribute('data-name');
        // `data-source` is the new "kind:slug" format (post:post,
        // post:campaign, taxonomy:product_brand). Falls back to the
        // legacy `data-post-type` attribute so older renders still work.
        var source   = field.getAttribute('data-source') ||
                       ('post:' + (field.getAttribute('data-post-type') || 'post'));

        // Tracks already-picked IDs so search results hide them inline.
        function pickedIds() {
            return Array.prototype.map.call(
                chips.querySelectorAll('.aieo-ce-chip'),
                function (li) { return parseInt(li.getAttribute('data-id'), 10); }
            );
        }

        function addChip(id, label) {
            if (pickedIds().indexOf(id) !== -1) return;
            var li = document.createElement('li');
            li.className = 'aieo-ce-chip';
            li.setAttribute('data-id', id);
            li.innerHTML =
                '<span class="aieo-ce-chip-label"></span>' +
                '<button type="button" class="aieo-ce-chip-remove" aria-label="' + __( 'Remove', 'ai-eshop-optimizer' ) + '">&times;</button>' +
                '<input type="hidden" name="' + name + '" />';
            li.querySelector('.aieo-ce-chip-label').textContent = label;
            li.querySelector('input').value = id;
            chips.appendChild(li);
            li.querySelector('.aieo-ce-chip-remove').addEventListener('click', function () {
                li.parentNode.removeChild(li);
            });
        }

        // Bind X handlers for chips already in the DOM (server-rendered).
        Array.prototype.forEach.call(chips.querySelectorAll('.aieo-ce-chip-remove'), function (btn) {
            btn.addEventListener('click', function () {
                var li = btn.closest('.aieo-ce-chip');
                if (li) li.parentNode.removeChild(li);
            });
        });

        function renderResults(items) {
            results.innerHTML = '';
            if (!items.length) {
                results.innerHTML = '<li class="aieo-ce-search-empty">' + cfg.i18n.noResults + '</li>';
                results.hidden = false;
                return;
            }
            var picked = pickedIds();
            items.forEach(function (it) {
                if (picked.indexOf(it.id) !== -1) return; // already chipped
                var li = document.createElement('li');
                li.className = 'aieo-ce-search-result';
                li.textContent = it.label;
                li.setAttribute('data-id', it.id);
                li.addEventListener('mousedown', function (e) {
                    // Use mousedown so the click fires before input blur hides results.
                    e.preventDefault();
                    addChip(it.id, it.label);
                    input.value = '';
                    results.hidden = true;
                });
                results.appendChild(li);
            });
            results.hidden = false;
        }

        var debounce;
        input.addEventListener('input', function () {
            var q = input.value.trim();
            clearTimeout(debounce);
            if (q.length < 2) {
                results.hidden = true;
                return;
            }
            debounce = setTimeout(function () {
                results.innerHTML = '<li class="aieo-ce-search-empty">' + cfg.i18n.searching + '</li>';
                results.hidden = false;
                $.post(cfg.ajaxurl, {
                    action: 'aieo_dmm_category_extras_search',
                    nonce:  cfg.nonce,
                    source: source,
                    q:      q
                }).done(function (resp) {
                    if (resp && resp.success && resp.data && Array.isArray(resp.data.items)) {
                        renderResults(resp.data.items);
                    } else {
                        renderResults([]);
                    }
                }).fail(function () {
                    renderResults([]);
                });
            }, 200);
        });
        input.addEventListener('blur', function () {
            // Defer hide so click on a result still registers via mousedown.
            setTimeout(function () { results.hidden = true; }, 150);
        });
    }

    /**
     * Upgrade the WP-core Description textarea to a TinyMCE-backed rich
     * editor. Core renders this field as a hard-coded <textarea> in
     * wp-admin/edit-tag-form.php — there's no PHP hook to replace it, so
     * we convert it on the client. The wp.editor.initialize() helper
     * (available since WP 4.8) wires up TinyMCE + Quicktags + the media
     * uploader and registers a save-on-submit listener that flushes the
     * editor content back to the textarea, so the regular term-update
     * handler still receives `description` from $_POST normally.
     */
    function initDescriptionEditor() {
        if (typeof window.wp === 'undefined' || !wp.editor || typeof wp.editor.initialize !== 'function') return;
        var ta = document.getElementById('description');
        if (!ta) return;
        // Defensive: WP's terms LIST table also has a sortable column
        // header rendered as `<th id="description">`. Only upgrade the
        // actual <textarea> on the single-term edit screen.
        if (ta.tagName !== 'TEXTAREA') return;
        // If the page already booted TinyMCE on this textarea (some themes
        // do), skip — re-initialising would corrupt the toolbar.
        if (window.tinymce && window.tinymce.get('description')) return;

        wp.editor.initialize('description', {
            tinymce: {
                wpautop:  true,
                plugins:  'charmap colorpicker hr lists paste tabfocus textcolor fullscreen wordpress wpautoresize wpeditimage wpemoji wpgallery wplink wptextpattern',
                toolbar1: 'formatselect bold italic bullist numlist blockquote alignleft aligncenter alignright link wp_more fullscreen wp_adv',
                toolbar2: 'strikethrough hr forecolor pastetext removeformat charmap outdent indent undo redo wp_help'
            },
            mediaButtons: true,
            quicktags:    true
        });
    }

    // ── Marketplace Taxonomy picker ──────────────────────────────────────
    //
    // Two pickers in the Marketplace tab — one Google, one Facebook. Each
    // is a self-contained .aieo-ce-marketplace-tax wrapper carrying its
    // current id+path in data-* attrs, a hidden id input, a hidden path
    // input, a search input, a results list, and a cascade row that
    // grows as the operator drills down. Server endpoints expose the
    // taxonomy tree one level at a time so we never ship the whole list
    // to the browser.

    function mtSetPicked(wrap, id, path) {
        wrap.querySelector('.aieo-ce-mt-id').value   = id || 0;
        wrap.querySelector('.aieo-ce-mt-path').value = path || '';
        var span  = wrap.querySelector('.aieo-ce-mt-current-path');
        var clear = wrap.querySelector('.aieo-ce-mt-clear');
        if (span) span.textContent = path || ((cfg.i18n && cfg.i18n.notSet) || '(not set)');
        if (clear) clear.style.display = id ? '' : 'none';
    }

    function mtPostBrowse(wrap, parentId, onResult) {
        var source = wrap.getAttribute('data-source');
        var fd = new FormData();
        fd.append('action',    (cfg.mt && cfg.mt.actionBrowse) || 'aieo_dmm_marketplace_tax_browse');
        fd.append('nonce', cfg.nonce);
        fd.append('source',    source);
        fd.append('parent_id', String(parentId || 0));
        fetch(cfg.ajaxurl, { method: 'POST', body: fd, credentials: 'same-origin' })
            .then(function (r) { return r.json(); })
            .then(function (j) {
                if (!j || !j.success) { onResult([]); return; }
                onResult((j.data && j.data.nodes) || []);
            })
            .catch(function () { onResult([]); });
    }

    function mtMakeSelect(wrap, parentId, depth, nodes) {
        var sel = document.createElement('select');
        sel.className = 'aieo-ce-mt-select';
        sel.setAttribute('data-depth', String(depth));
        sel.style.minWidth = '180px';
        var opt0 = document.createElement('option');
        opt0.value = '';
        opt0.textContent = (cfg.i18n && cfg.i18n.pickPrompt) || '— pick —';
        sel.appendChild(opt0);
        nodes.forEach(function (n) {
            var o = document.createElement('option');
            o.value = String(n.id);
            o.textContent = n.name + (n.has_children ? ' ›' : '');
            o.setAttribute('data-path', n.path);
            o.setAttribute('data-has-children', n.has_children ? '1' : '0');
            sel.appendChild(o);
        });
        sel.addEventListener('change', function () {
            // Trim later cascades when the operator changes a higher level.
            var cascade = wrap.querySelector('.aieo-ce-mt-cascade');
            var sels    = Array.prototype.slice.call(cascade.querySelectorAll('select'));
            sels.forEach(function (s) {
                if (Number(s.getAttribute('data-depth')) > depth) s.parentNode.removeChild(s);
            });
            if (!sel.value) {
                // Cleared — fall back to whichever was picked at the parent depth.
                // If depth > 1, the parent select's selected option is the pick.
                if (depth > 1) {
                    var parentSel = cascade.querySelector('select[data-depth="' + (depth - 1) + '"]');
                    if (parentSel && parentSel.value) {
                        var po = parentSel.options[parentSel.selectedIndex];
                        mtSetPicked(wrap, parentSel.value, po.getAttribute('data-path') || '');
                    } else {
                        mtSetPicked(wrap, 0, '');
                    }
                } else {
                    mtSetPicked(wrap, 0, '');
                }
                return;
            }
            var picked = sel.options[sel.selectedIndex];
            mtSetPicked(wrap, sel.value, picked.getAttribute('data-path') || '');
            if (picked.getAttribute('data-has-children') === '1') {
                mtPostBrowse(wrap, Number(sel.value), function (children) {
                    if (children.length) {
                        cascade.appendChild(mtMakeSelect(wrap, Number(sel.value), depth + 1, children));
                    }
                });
            }
        });
        return sel;
    }

    function mtRenderSearchResults(wrap, hits) {
        var box = wrap.querySelector('.aieo-ce-mt-results');
        box.innerHTML = '';
        // Make the dropdown unmistakable — bordered panel that sits
        // directly under the search input.
        box.style.position       = 'relative';
        box.style.background     = '#fff';
        box.style.border         = '1px solid #c3c4c7';
        box.style.borderTop      = 'none';
        box.style.borderRadius   = '0 0 4px 4px';
        box.style.maxHeight      = '320px';
        box.style.overflowY      = 'auto';
        box.style.boxShadow      = '0 4px 10px rgba(0,0,0,.06)';
        box.style.marginTop      = '0';
        if (!hits.length) {
            var empty = document.createElement('div');
            empty.style.padding = '10px 12px';
            empty.style.color = '#646970';
            empty.style.fontSize = '13px';
            empty.textContent = (cfg.i18n && cfg.i18n.noResults) || 'No matches.';
            box.appendChild(empty);
            return;
        }
        var ul = document.createElement('ul');
        ul.style.margin = '0';
        ul.style.padding = '0';
        ul.style.listStyle = 'none';
        hits.forEach(function (h) {
            var li = document.createElement('li');
            li.style.padding = '8px 12px';
            li.style.borderBottom = '1px solid #f0f0f1';
            li.style.cursor = 'pointer';
            // Primary line: the matched-locale display (so the
            // operator's typed text visually aligns with what they see).
            var primary = document.createElement('div');
            primary.style.fontSize = '13px';
            primary.style.color = '#1d2327';
            primary.textContent = h.path;
            li.appendChild(primary);
            // Subtitle: when the matched-locale differs from the
            // site-locale rendering, show what we'll save. Quietly hidden
            // when both are identical (e.g. en-US site matching English).
            if (h.site_path && h.site_path !== h.path) {
                var sub = document.createElement('div');
                sub.style.fontSize = '11px';
                sub.style.color = '#646970';
                sub.style.marginTop = '2px';
                sub.textContent = '↳ ' + h.site_path;
                li.appendChild(sub);
            }
            li.addEventListener('click', function () {
                // Persist the site-locale path so cascading dropdowns,
                // the "Current:" line, and the feed output all align
                // with the operator's display language — even if they
                // matched on a different locale.
                mtSetPicked(wrap, h.id, h.site_path || h.path);
                wrap.querySelector('.aieo-ce-mt-results').innerHTML = '';
                wrap.querySelector('.aieo-ce-mt-search').value = '';
                // Reset the cascade so the operator can drill from the
                // top if they want to fine-tune. Cleared in site locale.
                wrap.querySelector('.aieo-ce-mt-cascade').innerHTML = '';
                mtPostBrowse(wrap, 0, function (roots) {
                    if (roots.length) {
                        wrap.querySelector('.aieo-ce-mt-cascade').appendChild(
                            mtMakeSelect(wrap, 0, 1, roots)
                        );
                    }
                });
            });
            li.addEventListener('mouseenter', function () { li.style.background = '#f6f7f7'; });
            li.addEventListener('mouseleave', function () { li.style.background = ''; });
            ul.appendChild(li);
        });
        box.appendChild(ul);
    }

    function initMarketplaceTaxPicker(wrap) {
        // Initial cascade: load root level.
        var cascade = wrap.querySelector('.aieo-ce-mt-cascade');
        mtPostBrowse(wrap, 0, function (roots) {
            if (!roots.length) return;
            cascade.appendChild(mtMakeSelect(wrap, 0, 1, roots));
        });

        // Search box (debounced).
        var search = wrap.querySelector('.aieo-ce-mt-search');
        var timer  = null;
        search.addEventListener('input', function () {
            if (timer) clearTimeout(timer);
            var q = search.value.trim();
            if (q.length < 2) {
                wrap.querySelector('.aieo-ce-mt-results').innerHTML = '';
                return;
            }
            timer = setTimeout(function () {
                var fd = new FormData();
                fd.append('action',      (cfg.mt && cfg.mt.actionSearch) || 'aieo_dmm_marketplace_tax_search');
                fd.append('nonce', cfg.nonce);
                fd.append('source',      wrap.getAttribute('data-source'));
                fd.append('q',           q);
                fetch(cfg.ajaxurl, { method: 'POST', body: fd, credentials: 'same-origin' })
                    .then(function (r) { return r.json(); })
                    .then(function (j) {
                        if (!j || !j.success) { mtRenderSearchResults(wrap, []); return; }
                        mtRenderSearchResults(wrap, (j.data && j.data.hits) || []);
                    })
                    .catch(function () { mtRenderSearchResults(wrap, []); });
            }, 200);
        });

        // Clear button.
        var clear = wrap.querySelector('.aieo-ce-mt-clear');
        if (clear) {
            clear.addEventListener('click', function () {
                mtSetPicked(wrap, 0, '');
                wrap.querySelector('.aieo-ce-mt-cascade').innerHTML = '';
                wrap.querySelector('.aieo-ce-mt-results').innerHTML = '';
                wrap.querySelector('.aieo-ce-mt-search').value = '';
                mtPostBrowse(wrap, 0, function (roots) {
                    if (roots.length) {
                        wrap.querySelector('.aieo-ce-mt-cascade').appendChild(
                            mtMakeSelect(wrap, 0, 1, roots)
                        );
                    }
                });
            });
        }
    }

    // ── Boot ────────────────────────────────────────────────────────────

    document.addEventListener('DOMContentLoaded', function () {
        initDescriptionEditor();
        document.querySelectorAll('[data-aieo-ce-panel]').forEach(function (panel) {
            initTabs(panel);
            panel.querySelectorAll('.aieo-ce-image-field').forEach(initImageField);
            panel.querySelectorAll('.aieo-ce-search-field').forEach(initSearchField);
            panel.querySelectorAll('.aieo-ce-marketplace-tax').forEach(initMarketplaceTaxPicker);
        });
    });

})(jQuery);
