(function (global, doc, $, $$) {

    function on(element, name, delegate, fn) {

        if (!fn) {
            element.addEventListener(name, arguments[2]);
        } else {
            element.addEventListener(name, function (e) {

                let target = e.target;

                while (target !== element) {
                    if (!target) break;
                    if (target.matches(delegate)) return fn.apply(target, arguments);
                    target = target.parentNode;
                }
            }, true);
        }
        return element;
    }

    const baseUrl = "<?=trim($this->module('system')->spaceUrl('/'), '/')?>";
    const storefrontAssetsBaseUrl = "<?=trim($this->pathToUrl('pages:assets/storefront', true), '/')?>";

    let uId = 0;

    const addTrigger = () => {

        setTimeout(() => {

            document.body.insertAdjacentHTML('afterend', '<div class="pages-storefront"><div class="pages-storefront-trigger"></div></div>');

            $('.pages-storefront-trigger').addEventListener('click', () => {
                location.href = `${baseUrl}/pages/storefront/frame?src=${encodeURI(location.href)}`;
            });

        }, 300);
    };

    let Lib = {

        isInIframe: false,

        data: null,

        init() {

            this.isInIframe = (window.location !== window.parent.location) && window.parent.location.href.indexOf(baseUrl) !== -1;

            let link = document.createElement('link');

            Object.assign(link, {
                rel: 'stylesheet',
                type: 'text/css',
                href: `${storefrontAssetsBaseUrl}/storefront.css?nc=${Math.random().toString(36).slice(1)}`,
            });

            document.head.appendChild(link);

            if (!this.isInIframe) {
                return addTrigger();
            }

            window.addEventListener('beforeunload', () => {
                this.send('storefront:unload', {});
            });

            this.update();
        },

        update() {

            const storefront = window.STORE_FRONT || {};
            const modules = storefront.modules || {};

            $$('[data-sf-module]').forEach((r) => {

                let module = r.getAttribute('data-sf-module');
                let context = r.getAttribute('data-sf-context');
                let data = r.getAttribute('data-sf-data');

                if (!module || !context || !data) {
                    return;
                }

                try {
                    data = JSON.parse(data);
                } catch (e) {
                    data = { value: data };
                }

                if (!modules[module]) {
                    modules[module] = {};
                }

                if (!modules[module][context]) {
                    modules[module][context] = [];
                }

                modules[module][context].push(data);

                let spotId = r.getAttribute('data-sf-id');

                if (!spotId) {
                    spotId = `spot-${++uId}`;
                    r.setAttribute('data-sf-id', spotId);
                }

                data.spotId = spotId;
            });

            storefront.modules = modules;
            this.data = storefront;

            this.send('storefront:load', {
                src: location.href,
                title: document.head.querySelector('title').innerText,
                locale: document.documentElement.lang || 'default',
                storefront
            });
        },

        send(event, data) {
            window.parent.postMessage({ event, data }, '*');
        },

        notify(message, status, timeout) {
            this.send('storefront:notify', { message, status, timeout });
        }
    }

    window.addEventListener('message', (e) => {

        if (!e.data.event) return;

        let event = e.data.event;
        let data = e.data.data || {};

        switch (event) {
            case 'storefront:highlight':

                let ele;

                if (data.spotId) {
                    ele = $(`[data-sf-id="${data.spotId}"]`);
                }

                if (ele) {

                    ele.scrollIntoView({
                        behavior: 'smooth',
                        block: 'center',
                        inline: 'center'
                    });

                    setTimeout(() => {
                        const highlight = document.querySelector('storefront-highlight');
                        if (highlight) highlight.show(ele);
                    }, 100);
                }

                break;
        }

    }, false);

    customElements.define('storefront-highlight', class extends HTMLElement {

        constructor() {
            super();
            this.element = null;
            this.container = null;
            this.actions = null;
            this.resizeObserver = null;
            this.ticking = false;
        }

        connectedCallback() {

            this.innerHTML = '<button class="storefront-highlight-actions"></button><div class="storefront-highlight-container"></div>';
            this.container = this.querySelector('.storefront-highlight-container');
            this.actions = this.querySelector('.storefront-highlight-actions');

            this.resizeObserver = new ResizeObserver(entries => {
                if (this.element) this.updatePosition();
            });

            // Handle scroll to update position
            window.addEventListener('scroll', () => {
                if (this.element && !this.ticking) {
                    window.requestAnimationFrame(() => {
                        this.updatePosition();
                        this.ticking = false;
                    });
                    this.ticking = true;
                }
            }, { capture: true, passive: true });

            doc.addEventListener('mouseover', e => {
                const ele = e.target.closest('[data-sf-id]');
                if (ele) this.show(ele);
            });

            doc.addEventListener('mouseout', e => {

                if (!this.element) return;

                // If moving to the highlight component itself, don't hide
                if (this.contains(e.relatedTarget)) return;

                // If moving to a child of the element, don't hide
                if (this.element.contains(e.relatedTarget)) return;

                this.hide();
            });

            this.addEventListener('mouseout', e => {
                if (this.contains(e.relatedTarget)) return; // Internal move
                if (this.element && this.element.contains(e.relatedTarget)) return; // Back to element
                this.hide();
            });

            this.actions.addEventListener('click', e => {

                e.stopPropagation();
                e.preventDefault();

                if (!this.element) return;

                const moduleWrapperElement = this.element.closest('[data-sf-module]')
                let module = moduleWrapperElement ? moduleWrapperElement.getAttribute('data-sf-module') : 'pages';

                if (!Lib.data.modules[module]) {
                    return;
                }

                const id = this.element.getAttribute('data-sf-id');

                Lib.send('storefront:edit', {
                    module,
                    id,
                });

            });
        }

        show(element) {

            if (this.element === element) return;

            this.element = element;

            const title = element.getAttribute('data-sf-title');

            if (title) {
                this.actions.setAttribute('title', title);
            } else {
                this.actions.removeAttribute('title');
            }

            this.resizeObserver.observe(element);
            this.updatePosition();
            this.setAttribute('active', true);
        }

        hide() {
            if (!this.element) return;
            this.resizeObserver.unobserve(this.element);
            this.removeAttribute('active');
            this.element = null;
        }

        updatePosition() {

            if (!this.element) return;

            const rect = this.element.getBoundingClientRect();
            const scrollX = window.scrollX;
            const scrollY = window.scrollY;

            this.style.width = `${rect.width}px`;
            this.style.height = `${rect.height}px`;
            this.style.left = `${rect.left + scrollX}px`;
            this.style.top = `${rect.top + scrollY}px`;

            // Handle edge detection for actions
            if ((rect.top + scrollY) < 40) {
                this.classList.add('top-aligned');
            } else {
                this.classList.remove('top-aligned');
            }
        }
    });

    doc.addEventListener("DOMContentLoaded", (event) => {

        Lib.init();

        if (Lib.isInIframe) {
            document.body.appendChild(document.createElement('storefront-highlight'));
        }
    });

    global.storefront = Lib;

})(window, document, (s) => document.querySelector(s), (s) => document.querySelectorAll(s));
