/**
 * Griffin Assist Visual Feedback Manager
 * Rebuild-based AI applies are shown as a staggered reveal instead of a glow,
 * because the draft is re-rendered as a whole.
 */
(function($) {
    'use strict';

    window.ButlerFeedbackManager = {
        REVEAL_CLASS: 'griffinforms-new-formelement',
        REVEAL_DURATION: 560,
        STAGGER_DELAY: 42,
        MAX_REVEALS: 40,
        MAX_PAGES_FOR_CASCADE: 4,

        /**
         * Reveals the refreshed builder structure in a short staggered sequence.
         * For small forms, cascade page -> row -> field so the regenerated structure
         * feels intentionally placed into the canvas instead of glowing all at once.
         */
        reveal: function(detail = {}) {
            const $root = $('#griffinforms-app-presentationarea');
            if (!$root.length) {
                return;
            }

            if (this.revealFromLineage($root, detail.lineage || null)) {
                return;
            }

            const $pages = $root.find('[data-gf-fe="true"][data-gf-itemtype="formpage"]');
            if (!$pages.length) {
                this.revealFallback($root);
                return;
            }

            if ($pages.length > this.MAX_PAGES_FOR_CASCADE) {
                this.revealFallback($root);
                return;
            }

            const queue = [];

            $pages.each((pageIndex, pageEl) => {
                const $page = $(pageEl);
                queue.push($page.get(0));

                const $pageContainer = $page.closest('.griffinforms-app-formlayout-formpage-container');
                const $rows = $pageContainer.find('[data-gf-fe="true"][data-gf-itemtype="pagerow"]');
                $rows.each((rowIndex, rowEl) => {
                    queue.push(rowEl);

                    const $fields = $(rowEl).find('[data-gf-fe="true"][data-gf-itemtype="field"]');
                    $fields.each((fieldIndex, fieldEl) => {
                        queue.push(fieldEl);
                    });
                });
            });

            const uniqueQueue = [];
            const seen = new Set();
            queue.forEach((element) => {
                if (!element || seen.has(element)) {
                    return;
                }

                seen.add(element);
                uniqueQueue.push(element);
            });

            if (!uniqueQueue.length || uniqueQueue.length > this.MAX_REVEALS) {
                this.revealFallback($root);
                return;
            }

            uniqueQueue.forEach((element, index) => {
                const $element = $(element);
                const delay = index * this.STAGGER_DELAY;

                setTimeout(() => {
                    $element.addClass(this.REVEAL_CLASS);

                    setTimeout(() => {
                        $element.removeClass(this.REVEAL_CLASS);
                    }, this.REVEAL_DURATION);
                }, delay);
            });
        },

        revealFromLineage: function($root, lineage) {
            if (!lineage || typeof lineage !== 'object') {
                return false;
            }

            const queue = [];
            const addBySignature = (signature, itemType) => {
                if (!signature) {
                    return;
                }

                const $elements = $root.find(
                    `[data-gf-fe="true"][data-gf-itemtype="${itemType}"][data-gf-ai-signature="${this.escapeSelector(signature)}"]`
                );
                $elements.each((index, element) => queue.push(element));
            };

            const addedPages = Array.isArray(lineage.pages && lineage.pages.added) ? lineage.pages.added : [];
            const addedFields = Array.isArray(lineage.fields && lineage.fields.added) ? lineage.fields.added : [];

            addedPages.forEach((entry) => addBySignature((entry && entry.signature) || '', 'formpage'));
            addedFields.forEach((entry) => addBySignature((entry && entry.signature) || '', 'field'));

            const uniqueQueue = [];
            const seen = new Set();
            queue.forEach((element) => {
                if (!element || seen.has(element)) {
                    return;
                }
                seen.add(element);
                uniqueQueue.push(element);
            });

            if (!uniqueQueue.length) {
                return false;
            }

            uniqueQueue.slice(0, this.MAX_REVEALS).forEach((element, index) => {
                const $element = $(element);
                const delay = index * this.STAGGER_DELAY;

                setTimeout(() => {
                    $element.addClass(this.REVEAL_CLASS);

                    setTimeout(() => {
                        $element.removeClass(this.REVEAL_CLASS);
                    }, this.REVEAL_DURATION);
                }, delay);
            });

            return true;
        },

        escapeSelector: function(value) {
            const stringValue = String(value || '');
            if (window.CSS && typeof window.CSS.escape === 'function') {
                return window.CSS.escape(stringValue);
            }

            return stringValue.replace(/([!"#$%&'()*+,./:;<=>?@[\\\]^`{|}~])/g, '\\$1');
        },

        revealFallback: function($root) {
            let $elements = $root.find(
                '[data-gf-fe="true"][data-gf-itemtype="formpage"], ' +
                '[data-gf-fe="true"][data-gf-itemtype="field"]'
            );

            if (!$elements.length) {
                $elements = $root.find('[data-gf-fe="true"]');
            }

            $elements.slice(0, this.MAX_REVEALS).each((index, element) => {
                const $element = $(element);
                const delay = index * this.STAGGER_DELAY;

                setTimeout(() => {
                    $element.addClass(this.REVEAL_CLASS);

                    setTimeout(() => {
                        $element.removeClass(this.REVEAL_CLASS);
                    }, this.REVEAL_DURATION);
                }, delay);
            });
        }
    };

    /**
     * Listener for AI apply completion.
     * The builder has already been refreshed at this point, so reveal the current markup.
     */
    document.addEventListener('gf-ai-mutation-applied', function(e) {
        if (e.detail) {
            window.ButlerFeedbackManager.reveal(e.detail);
        }
    });

})(jQuery);
