/**
 * Ecom Ofuscar - Frontend JS
 * Intercepta enlaces, forms, pushState y peticiones AJAX de facetas/paginacion/sort
 * y las transforma en URLs ofuscadas en tiempo real.
 */
(function () {
    'use strict';

    if (typeof window.ecomOfuscar === 'undefined' || !window.ecomOfuscar.enabled) {
        return;
    }

    var cfg = window.ecomOfuscar;
    var cache = {};
    var pending = {};

    function isSameOrigin(url) {
        try {
            var a = document.createElement('a');
            a.href = url;
            return a.host === window.location.host;
        } catch (e) { return false; }
    }

    function detectContext(url, el) {
        var lower = (url || '').toLowerCase() + ' ' + (el ? (el.className || '') + ' ' + (el.getAttribute && el.getAttribute('data-search-url') || '') : '');
        if (el && el.tagName === 'IMG') {
            if (lower.indexOf('/img/p/') !== -1 || /\/\d+-[a-z0-9_]+\//.test(lower)) {
                return 'images';
            }
            return null;
        }
        if (lower.indexOf('controller=search') !== -1 || lower.indexOf('/search?') !== -1 || lower.indexOf('search_query=') !== -1) return 'search';
        if (lower.indexOf('orderby=') !== -1 || lower.indexOf('orderway=') !== -1) return 'sort';
        if (lower.indexOf('page=') !== -1 || lower.indexOf('data-page') !== -1) return 'pagination';
        if (lower.indexOf('submitlayered') !== -1 || lower.indexOf('q=') !== -1 || lower.indexOf('facet') !== -1) return 'faceted';
        if (lower.indexOf('id_manufacturer') !== -1 || lower.indexOf('/brand') !== -1) return 'manufacturer';
        if (lower.indexOf('id_supplier') !== -1) return 'supplier';
        if (lower.indexOf('/tag/') !== -1) return 'tag';
        if (lower.indexOf('id_currency') !== -1) return 'currency';
        if (lower.indexOf('id_lang') !== -1) return 'lang';
        if (lower.indexOf('cart?') !== -1) return 'cart';
        if (lower.indexOf('newsletter') !== -1) return 'newsletter';
        if (lower.indexOf('id_product=') !== -1) return 'product_id';
        if (lower.indexOf('facebook.com/sharer') !== -1 || lower.indexOf('twitter.com/share') !== -1) return 'social';
        if (!isSameOrigin(url)) return 'affiliate';
        return null;
    }

    function contextEnabled(ctx) {
        return ctx && cfg.targets && cfg.targets.indexOf(ctx) !== -1;
    }

    function obfuscateAsync(url, ctx, cb) {
        var key = ctx + '|' + url;
        if (cache[key]) { cb(cache[key]); return; }
        if (pending[key]) { pending[key].push(cb); return; }
        pending[key] = [cb];
        var body = 'action=encode&url=' + encodeURIComponent(url) + '&context=' + encodeURIComponent(ctx);
        fetch(cfg.resolveUrl, {
            method: 'POST',
            headers: { 'Content-Type': 'application/x-www-form-urlencoded', 'X-Requested-With': 'XMLHttpRequest' },
            body: body,
            credentials: 'same-origin'
        }).then(function (r) { return r.json(); }).then(function (data) {
            var out = (data && data.success) ? data.url : url;
            cache[key] = out;
            (pending[key] || []).forEach(function (c) { try { c(out); } catch (e) {} });
            delete pending[key];
        }).catch(function () {
            (pending[key] || []).forEach(function (c) { try { c(url); } catch (e) {} });
            delete pending[key];
        });
    }

    function batchObfuscate(urls, cb) {
        var unique = [];
        var seen = {};
        urls.forEach(function (u) { if (!seen[u]) { seen[u] = 1; unique.push(u); } });
        var body = 'action=batch&urls=' + encodeURIComponent(JSON.stringify(unique));
        fetch(cfg.resolveUrl, {
            method: 'POST',
            headers: { 'Content-Type': 'application/x-www-form-urlencoded', 'X-Requested-With': 'XMLHttpRequest' },
            body: body,
            credentials: 'same-origin'
        }).then(function (r) { return r.json(); }).then(function (data) {
            cb(data && data.success ? data.map : {});
        }).catch(function () { cb({}); });
    }

    function rewriteAnchors(root) {
        root = root || document;
        var anchors = root.querySelectorAll('a[href]:not([data-ecomo-done])');
        var batchList = [];
        var map = [];
        anchors.forEach(function (a) {
            var href = a.getAttribute('href');
            if (!href || href.charAt(0) === '#' || href.indexOf('javascript:') === 0 || href.indexOf('mailto:') === 0) return;
            var ctx = detectContext(href, a);
            if (!contextEnabled(ctx)) return;
            a.setAttribute('data-ecomo-done', '1');
            a.setAttribute('data-ecomo-ctx', ctx);
            batchList.push(href);
            map.push({ a: a, href: href });
        });
        if (!batchList.length) return;
        batchObfuscate(batchList, function (resultMap) {
            map.forEach(function (item) {
                if (resultMap[item.href]) {
                    if (cfg.useJsFrontend) {
                        var span = document.createElement('span');
                        span.innerHTML = item.a.innerHTML;
                        for (var i = 0; i < item.a.attributes.length; i++) {
                            var attr = item.a.attributes[i];
                            if (attr.name !== 'href' && attr.name !== 'data-ecomo-done' && attr.name !== 'data-ecomo-ctx') {
                                span.setAttribute(attr.name, attr.value);
                            }
                        }
                        span.setAttribute('data-ecomo-done', '1');
                        span.setAttribute('data-ecomo-ctx', item.a.getAttribute('data-ecomo-ctx'));
                        span.setAttribute('data-go', btoa(resultMap[item.href]));
                        if (!span.classList.contains('goto')) {
                            span.classList.add('goto');
                        }
                        if (!span.style.cursor) {
                            span.style.cursor = 'pointer';
                        }
                        if (!span.getAttribute('rel')) {
                            span.setAttribute('rel', 'nofollow');
                        }
                        if (item.a.parentNode) {
                            item.a.parentNode.replaceChild(span, item.a);
                        }
                    } else {
                        item.a.setAttribute('href', resultMap[item.href]);
                        if (!item.a.getAttribute('rel')) {
                            item.a.setAttribute('rel', 'nofollow');
                        }
                    }
                }
            });
        });
    }

    function rewriteForms(root) {
        root = root || document;
        var forms = root.querySelectorAll('form[action]:not([data-ecomo-done])');
        forms.forEach(function (f) {
            var action = f.getAttribute('action');
            if (!action) return;
            var ctx = detectContext(action, f);
            if (!contextEnabled(ctx)) return;
            f.setAttribute('data-ecomo-done', '1');
            obfuscateAsync(action, ctx, function (o) { f.setAttribute('action', o); });
        });
    }

    function processImages(root) {
        root = root || document;
        var imgs = root.querySelectorAll('img.goto-img[data-go]:not([data-ecomo-loaded])');
        imgs.forEach(function (img) {
            try {
                img.setAttribute('src', atob(img.getAttribute('data-go')));
                img.setAttribute('data-ecomo-loaded', '1');
            } catch(e) {}
        });

        var freshImgs = root.querySelectorAll('img[src]:not([data-ecomo-done]):not([data-ecomo-loaded])');
        var batchList = [];
        var map = [];
        freshImgs.forEach(function (img) {
            var src = img.getAttribute('src');
            if (!src || src.indexOf('data:') === 0) return;
            var ctx = detectContext(src, img);
            if (!contextEnabled(ctx)) return;
            img.setAttribute('data-ecomo-done', '1');
            batchList.push(src);
            map.push({ img: img, src: src });
        });
        if (!batchList.length) return;
        batchObfuscate(batchList, function (resultMap) {
            map.forEach(function (item) {
                if (resultMap[item.src]) {
                    if (cfg.useJsFrontend) {
                        item.img.setAttribute('data-go', btoa(resultMap[item.src]));
                        if (!item.img.classList.contains('goto-img')) {
                            item.img.classList.add('goto-img');
                        }
                    }
                    item.img.setAttribute('src', resultMap[item.src]);
                    item.img.setAttribute('data-ecomo-loaded', '1');
                }
            });
        });
    }

    function observeDom() {
        if (!window.MutationObserver) return;
        var obs = new MutationObserver(function (mutations) {
            mutations.forEach(function (m) {
                if (m.addedNodes && m.addedNodes.length) {
                    m.addedNodes.forEach(function (n) {
                        if (n.nodeType === 1) {
                            rewriteAnchors(n);
                            rewriteForms(n);
                            processImages(n);
                        }
                    });
                }
            });
        });
        obs.observe(document.documentElement, { childList: true, subtree: true });
    }

    function patchHistory() {
        var origPush = history.pushState;
        var origReplace = history.replaceState;
        history.pushState = function (state, title, url) {
            if (url && typeof url === 'string') {
                var ctx = detectContext(url, null);
                if (contextEnabled(ctx)) {
                    obfuscateAsync(url, ctx, function (o) {
                        origPush.call(history, state, title, o);
                    });
                    return;
                }
            }
            return origPush.apply(history, arguments);
        };
        history.replaceState = function (state, title, url) {
            if (url && typeof url === 'string') {
                var ctx = detectContext(url, null);
                if (contextEnabled(ctx)) {
                    obfuscateAsync(url, ctx, function (o) {
                        origReplace.call(history, state, title, o);
                    });
                    return;
                }
            }
            return origReplace.apply(history, arguments);
        };
    }

    function patchFetch() {
        if (typeof window.fetch !== 'function') return;
        var orig = window.fetch.bind(window);
        window.fetch = function (input, init) {
            var url = typeof input === 'string' ? input : (input && input.url);
            if (url && url.indexOf(cfg.resolveUrl) === -1) {
                var ctx = detectContext(url, null);
                if (contextEnabled(ctx)) {
                    return new Promise(function (resolve, reject) {
                        obfuscateAsync(url, ctx, function (o) {
                            var newInput = typeof input === 'string' ? o : new Request(o, input);
                            orig(newInput, init).then(resolve, reject);
                        });
                    });
                }
            }
            return orig(input, init);
        };
    }

    function patchXhr() {
        var OrigXhr = window.XMLHttpRequest;
        if (!OrigXhr) return;
        var origOpen = OrigXhr.prototype.open;
        OrigXhr.prototype.open = function (method, url) {
            try {
                if (typeof url === 'string' && url.indexOf(cfg.resolveUrl) === -1) {
                    var ctx = detectContext(url, null);
                    if (contextEnabled(ctx) && cache[ctx + '|' + url]) {
                        arguments[1] = cache[ctx + '|' + url];
                    }
                }
            } catch (e) {}
            return origOpen.apply(this, arguments);
        };
    }

    function init() {
        rewriteAnchors(document);
        rewriteForms(document);
        processImages(document);
        observeDom();
        patchHistory();
        patchFetch();
        patchXhr();
        
        document.addEventListener('click', function(e) {
            var el = e.target;
            while (el && el !== document) {
                if (el.classList && el.classList.contains('goto')) {
                    var go = el.getAttribute('data-go');
                    if (go) {
                        try {
                            var decoded = atob(go);
                            window.location.href = decoded;
                            e.preventDefault();
                            e.stopPropagation();
                        } catch(err) {}
                    }
                    break;
                }
                el = el.parentNode;
            }
        });
        
        document.dispatchEvent(new CustomEvent('ecomOfuscar:ready'));
    }

    if (document.readyState === 'loading') {
        document.addEventListener('DOMContentLoaded', init);
    } else {
        init();
    }
})();
