/*
** Copyright (C) 2021-2026 initMAX s.r.o.
**
** This program is free software: you can redistribute it and/or modify it under the terms of
** the GNU Affero General Public License as published by the Free Software Foundation, version 3.
**
** This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
** without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
** See the GNU Affero General Public License for more details.
**
** You should have received a copy of the GNU Affero General Public License along with this program.
** If not, see <https://www.gnu.org/licenses/>.
**/

/**
 * Draggable modal dialogs, Zabbix 6.0 - 7.4.
 *
 * Dragging is only half the job: Zabbix re-centres an open dialog on resize and
 * on content changes, which yanks a dragged dialog back under the cursor. The
 * method that does it was RENAMED - `Overlay.prototype.centerDialog` up to 7.2,
 * `Overlay.prototype.fixPosition` from 7.4 - so the override is installed on
 * whichever one this frontend actually has. Patching only the old name left 7.4
 * with a dialog that could be dragged and then jumped back, which is worse than
 * not offering the feature.
 *
 * The drag handle is `>.dashboard-widget-head, >.overlay-dialogue-header`; both
 * class names are present across the whole range.
 */
($ => {
    const HANDLE = '>.dashboard-widget-head, >.overlay-dialogue-header';
    const MOVED_CLASS = 'uxmax-moved';

    function makeDraggable(element) {
        $(element).draggable({
            containment: 'window',
            handle: HANDLE,
            start: (e, ui) => ui.helper.addClass(MOVED_CLASS)
        });
    }

    function watchForDialogs() {
        (new MutationObserver(mutations => {
            for (const mutation of [...mutations]) {
                for (const elm of [...mutation.addedNodes]) {
                    if (elm.getAttribute && elm.getAttribute('role') === 'dialog') {
                        makeDraggable(elm);
                    }
                }
            }
        })).observe(document.body, {childList: true, subtree: true});
    }

    // Leave a dialog the user has dragged where they put it. Whichever
    // repositioning method this frontend has, wrap THAT one - probed, because a
    // module can outlive a frontend upgrade.
    //
    // Done at ready time, NOT at parse time: Zabbix emits a module's scripts
    // before class.overlay.js on some lines, so `Overlay` is simply not defined
    // yet and a parse-time patch silently does nothing. It looked installed on
    // 7.4 (the file loaded, the console was clean) and was not.
    function guardDraggedDialogs() {
        if (typeof Overlay === 'undefined' || !Overlay.prototype) {
            return;
        }

        ['centerDialog', 'fixPosition'].forEach(name => {
            const original = Overlay.prototype[name];

            if (typeof original !== 'function' || original.uxmaxGuarded) {
                return;
            }

            const wrapper = function () {
                if (this.$dialogue && this.$dialogue.is('.' + MOVED_CLASS)) {
                    return;
                }

                return original.apply(this, arguments);
            };

            wrapper.uxmaxGuarded = true;
            Overlay.prototype[name] = wrapper;
        });
    }

    function install() {
        guardDraggedDialogs();
        watchForDialogs();
    }

    // readyState, not a bare DOMContentLoaded listener: the v1 (6.0/6.2)
    // package injects its scripts after the document is already parsed, and a
    // listener added after the event has fired never runs.
    if (document.readyState === 'loading') {
        document.addEventListener('DOMContentLoaded', install);
    }
    else {
        install();
    }
})(jQuery);
