(function () {
    'use strict';

    const PREFIX = '[S10 persistent checklist v1.3.1]';

    if (window.__S10_PERSISTENT_CHECKLIST_V131__) {
        return;
    }

    window.__S10_PERSISTENT_CHECKLIST_V131__ = true;


    function waitForJQuery(callback) {

        if (window.jQuery) {
            callback(window.jQuery);
            return;
        }

        let attempts = 0;

        const timer = setInterval(function () {

            attempts++;

            if (window.jQuery) {
                clearInterval(timer);
                callback(window.jQuery);
                return;
            }

            if (attempts >= 100) {
                clearInterval(timer);
                console.error(PREFIX, 'jQuery GetCourse не найден');
            }

        }, 100);
    }


    waitForJQuery(function ($) {

        const busyTasks = new Set();
        const knownTasks = new Set();


        function normalizeTaskId(value) {

            value = String(value || '');

            return /^\d+$/.test(value)
                ? value
                : null;
        }


        function getJSON(url, data) {

            return new Promise(function (resolve, reject) {

                $.getJSON(url, data)
                    .done(resolve)
                    .fail(reject);
            });
        }


        function post(url, data) {

            return new Promise(function (resolve, reject) {

                $.post(url, data)
                    .done(resolve)
                    .fail(reject);
            });
        }


        function isKanbanIframePage() {

            return window.location.pathname.indexOf(
                '/pl/tasks/kanban/task-view'
            ) !== -1;
        }


        function getUrlTaskId() {

            return normalizeTaskId(
                new URLSearchParams(
                    window.location.search
                ).get('id')
            );
        }


        function getUrlTaskScriptId() {

            return normalizeTaskId(
                new URLSearchParams(
                    window.location.search
                ).get('taskScriptId')
            );
        }


        function getTaskIdFromChecklistClass(element) {

            if (!element || !element.classList) {
                return null;
            }

            for (const className of element.classList) {

                const match =
                    className.match(
                        /^checklistForTask_(\d+)$/
                    );

                if (match) {
                    return match[1];
                }
            }

            return null;
        }


        function getTaskIdFromElement(element) {

            if (!element) {
                return null;
            }


            const formContainer =
                element.closest(
                    '[id^="taskForm"]'
                );


            if (formContainer) {

                const match =
                    formContainer.id.match(
                        /^taskForm(\d+)$/
                    );

                if (match) {
                    return match[1];
                }
            }


            let current = element;

            for (let level = 0; level < 15; level++) {

                if (!current) {
                    break;
                }


                const managerLinks =
                    current.querySelectorAll
                        ? current.querySelectorAll(
                            '.change-manager-link[data-task-id]'
                        )
                        : [];


                if (managerLinks.length === 1) {

                    const id =
                        normalizeTaskId(
                            managerLinks[0].getAttribute(
                                'data-task-id'
                            )
                        );

                    if (id) {
                        return id;
                    }
                }


                const checklists =
                    current.querySelectorAll
                        ? current.querySelectorAll(
                            '[class*="checklistForTask_"]'
                        )
                        : [];


                const foundIds = new Set();


                checklists.forEach(function (checklist) {

                    const id =
                        getTaskIdFromChecklistClass(
                            checklist
                        );

                    if (id) {
                        foundIds.add(id);
                    }
                });


                if (foundIds.size === 1) {

                    return Array.from(
                        foundIds
                    )[0];
                }


                current =
                    current.parentElement;
            }


            if (isKanbanIframePage()) {

                return getUrlTaskId();
            }


            return null;
        }


        function discoverTaskIds() {

            const ids = new Set();


            document
                .querySelectorAll(
                    '[id^="taskForm"]'
                )
                .forEach(function (element) {

                    const match =
                        element.id.match(
                            /^taskForm(\d+)$/
                        );

                    if (match) {
                        ids.add(match[1]);
                    }
                });


            document
                .querySelectorAll(
                    '[class*="checklistForTask_"]'
                )
                .forEach(function (element) {

                    const id =
                        getTaskIdFromChecklistClass(
                            element
                        );

                    if (id) {
                        ids.add(id);
                    }
                });


            document
                .querySelectorAll(
                    '.change-manager-link[data-task-id]'
                )
                .forEach(function (element) {

                    const id =
                        normalizeTaskId(
                            element.getAttribute(
                                'data-task-id'
                            )
                        );

                    if (id) {
                        ids.add(id);
                    }
                });


            if (
                window.location.pathname ===
                '/pl/tasks/task/view'
            ) {

                const id =
                    getUrlTaskId();

                if (id) {
                    ids.add(id);
                }
            }


            if (isKanbanIframePage()) {

                const id =
                    getUrlTaskId();

                if (id) {
                    ids.add(id);
                }
            }


            return Array.from(ids);
        }


        function getTaskContainer(taskId) {

            const form =
                document.getElementById(
                    'taskForm' + taskId
                );


            if (form) {
                return form;
            }


            const checklist =
                document.querySelector(
                    '.checklistForTask_' +
                    taskId
                );


            if (checklist) {

                let current =
                    checklist.parentElement;


                for (let level = 0; level < 15; level++) {

                    if (!current) {
                        break;
                    }


                    if (
                        current.querySelector(
                            '.task-scripts'
                        )
                    ) {
                        return current;
                    }


                    current =
                        current.parentElement;
                }
            }


            const managerLink =
                document.querySelector(
                    '.change-manager-link' +
                    '[data-task-id="' +
                    taskId +
                    '"]'
                );


            if (managerLink) {

                let current =
                    managerLink.parentElement;


                for (let level = 0; level < 15; level++) {

                    if (!current) {
                        break;
                    }


                    const scripts =
                        current.querySelectorAll(
                            '.task-scripts'
                        );


                    const taskMarkers =
                        current.querySelectorAll(
                            '.change-manager-link[data-task-id]'
                        );


                    if (
                        scripts.length >= 1 &&
                        taskMarkers.length <= 1
                    ) {
                        return current;
                    }


                    current =
                        current.parentElement;
                }
            }


            const pageId =
                getUrlTaskId();


            if (
                window.location.pathname ===
                    '/pl/tasks/task/view' &&
                pageId === String(taskId)
            ) {

                const scripts =
                    document.querySelector(
                        '.task-scripts'
                    );

                return scripts
                    ? scripts.parentElement
                    : null;
            }


            if (
                isKanbanIframePage() &&
                pageId === String(taskId)
            ) {

                const scripts =
                    document.querySelector(
                        '.task-scripts'
                    );

                return scripts
                    ? scripts.parentElement
                    : null;
            }


            return null;
        }


        function parseChecklist(response) {

            if (
                !response ||
                response.success !== true ||
                typeof response.html !== 'string'
            ) {
                return null;
            }


            const doc =
                new DOMParser().parseFromString(
                    response.html,
                    'text/html'
                );


            const textarea =
                doc.querySelector(
                    'textarea[name="content"]'
                );


            const idInput =
                doc.querySelector(
                    'input[name="id"]'
                );


            if (
                !textarea ||
                !idInput ||
                !idInput.value
            ) {
                return null;
            }


            return {

                checklistId:
                    idInput.value,

                content:
                    textarea.value.replace(
                        /\r\n/g,
                        '\n'
                    )
            };
        }


        async function getChecklist(taskScriptId) {

            try {

                const response =
                    await getJSON(
                        '/pl/tasks/check-list/load-manual-view',
                        {
                            id: taskScriptId
                        }
                    );

                return parseChecklist(
                    response
                );

            } catch (error) {

                return null;
            }
        }


        async function saveChecklist(
            taskScriptId,
            content,
            checklistId
        ) {

            return post(
                '/pl/tasks/check-list/save',
                {
                    task_script_id:
                        taskScriptId,

                    id:
                        checklistId || '',

                    content:
                        content
                }
            );
        }


        async function refreshChecklist(
            taskId,
            taskScriptId
        ) {

            const response =
                await getJSON(
                    '/pl/tasks/check-list/load-manual-view',
                    {
                        id: taskScriptId
                    }
                );


            if (
                response &&
                response.html
            ) {

                $('.checklistForTask_' + taskId)
                    .html(
                        response.html
                    );
            }
        }


        async function refreshWholeTaskScripts(
            taskId
        ) {

            try {

                /*
                 * Нам здесь нужен именно обычный
                 * task-scripts endpoint.
                 *
                 * Его HTML мы уже вручную проверили:
                 * он возвращает нормальный delayed UI
                 * со ссылкой "выполнить сейчас".
                 */
                const response =
                    await getJSON(
                        '/pl/tasks/task/task-scripts',
                        {
                            id: taskId
                        }
                    );


                if (
                    !response ||
                    !response.success ||
                    !response.data ||
                    !response.data.html
                ) {
                    return false;
                }


                let taskScripts = null;


                if (isKanbanIframePage()) {

                    taskScripts =
                        document.querySelector(
                            '.task-scripts'
                        );

                } else {

                    const container =
                        getTaskContainer(
                            taskId
                        );


                    if (container) {

                        taskScripts =
                            container.querySelector(
                                '.task-scripts'
                            );
                    }
                }


                if (!taskScripts) {
                    return false;
                }


                $(taskScripts).replaceWith(
                    response.data.html
                );


                console.log(
                    PREFIX,
                    'интерфейс обновлён:',
                    taskId
                );


                return true;

            } catch (error) {

                console.error(
                    PREFIX,
                    'Ошибка перерисовки:',
                    taskId,
                    error
                );


                return false;
            }
        }


        async function getTaskState(taskId) {

            const response =
                await getJSON(
                    '/pl/tasks/task/task-scripts',
                    {
                        id: taskId
                    }
                );


            const html =
                response &&
                response.data &&
                typeof response.data.html === 'string'
                    ? response.data.html
                    : '';


            const doc =
                new DOMParser().parseFromString(
                    html,
                    'text/html'
                );


            const active =
                doc.querySelector(
                    '.active-task-script' +
                    '[data-task-script-id]'
                );


            const activeId =
                active
                    ? active.getAttribute(
                        'data-task-script-id'
                    )
                    : null;


            const historyIds =
                Array.from(
                    doc.querySelectorAll(
                        '.task-scripts-history ' +
                        '.task-script-row[data-id]'
                    )
                ).map(function (element) {

                    return element.getAttribute(
                        'data-id'
                    );
                });


            const completed =
                !activeId &&
                html.indexOf(
                    'Задача завершена'
                ) !== -1;


            return {
                activeId:
                    activeId,

                historyIds:
                    historyIds,

                completed:
                    completed
            };
        }


        async function findPreviousChecklist(ids) {

            for (const scriptId of ids) {

                const checklist =
                    await getChecklist(
                        scriptId
                    );


                if (
                    checklist &&
                    checklist.content &&
                    checklist.content.trim() !== ''
                ) {

                    return {

                        scriptId:
                            scriptId,

                        checklistId:
                            checklist.checklistId,

                        content:
                            checklist.content
                    };
                }
            }


            return null;
        }


        function handoffKey(taskId) {

            return (
                's10_checklist_handoff_' +
                taskId
            );
        }


        function transitionKey(taskId) {

            return (
                's10_task_transition_' +
                taskId
            );
        }


        function getActiveScriptId(taskId) {

            const container =
                getTaskContainer(
                    taskId
                );


            if (container) {

                const active =
                    container.querySelector(
                        '.active-task-script' +
                        '[data-task-script-id]'
                    );


                if (active) {

                    const id =
                        normalizeTaskId(
                            active.getAttribute(
                                'data-task-script-id'
                            )
                        );

                    if (id) {
                        return id;
                    }
                }
            }


            if (isKanbanIframePage()) {

                const active =
                    document.querySelector(
                        '.active-task-script' +
                        '[data-task-script-id]'
                    );


                if (active) {

                    const id =
                        normalizeTaskId(
                            active.getAttribute(
                                'data-task-script-id'
                            )
                        );

                    if (id) {
                        return id;
                    }
                }


                /*
                 * Ещё одна страховка для Kanban:
                 * исходный taskScriptId есть в URL iframe.
                 */
                return getUrlTaskScriptId();
            }


            return null;
        }


        function getChecklistTextarea(taskId) {

            let textarea =
                document.querySelector(
                    '.checklistForTask_' +
                    taskId +
                    ' textarea[name="content"]'
                );


            if (textarea) {
                return textarea;
            }


            if (isKanbanIframePage()) {

                textarea =
                    document.querySelector(
                        'textarea[name="content"]'
                    );


                if (textarea) {
                    return textarea;
                }
            }


            return null;
        }


        function markTransition(
            taskId,
            explicitScriptId
        ) {

            const scriptId =
                normalizeTaskId(
                    explicitScriptId
                ) ||
                getActiveScriptId(
                    taskId
                );


            if (!scriptId) {

                console.warn(
                    PREFIX,
                    'Не найден исходный taskScriptId:',
                    taskId
                );

                return;
            }


            sessionStorage.setItem(
                transitionKey(taskId),
                JSON.stringify({
                    fromScriptId:
                        scriptId,

                    time:
                        Date.now()
                })
            );


            const textarea =
                getChecklistTextarea(
                    taskId
                );


            if (
                textarea &&
                textarea.value.trim()
            ) {

                sessionStorage.setItem(
                    handoffKey(taskId),
                    JSON.stringify({

                        fromScriptId:
                            scriptId,

                        content:
                            textarea.value.replace(
                                /\r\n/g,
                                '\n'
                            ),

                        time:
                            Date.now()
                    })
                );

            } else {

                getChecklist(scriptId)
                    .then(function (checklist) {

                        if (
                            checklist &&
                            checklist.content
                        ) {

                            sessionStorage.setItem(
                                handoffKey(taskId),
                                JSON.stringify({

                                    fromScriptId:
                                        scriptId,

                                    content:
                                        checklist.content,

                                    time:
                                        Date.now()
                                })
                            );
                        }
                    });
            }


            console.log(
                PREFIX,
                'зафиксирован переход:',
                taskId,
                scriptId
            );
        }


        function getStoredJSON(key) {

            try {

                const raw =
                    sessionStorage.getItem(
                        key
                    );

                return raw
                    ? JSON.parse(raw)
                    : null;

            } catch (error) {

                return null;
            }
        }


        function getHandoff(taskId) {

            return getStoredJSON(
                handoffKey(taskId)
            );
        }


        function getTransition(taskId) {

            return getStoredJSON(
                transitionKey(taskId)
            );
        }


        function clearTransitionData(taskId) {

            sessionStorage.removeItem(
                handoffKey(taskId)
            );

            sessionStorage.removeItem(
                transitionKey(taskId)
            );
        }


        function escapeHtml(text) {

            const div =
                document.createElement(
                    'div'
                );

            div.textContent = text;

            return div.innerHTML;
        }


        function renderCompletedChecklist(
            taskId,
            content
        ) {

            $('#s10-persistent-checklist-' + taskId)
                .remove();


            let items = '';


            content
                .split('\n')
                .forEach(function (line) {

                    let text =
                        line.trim();


                    if (!text) {
                        return;
                    }


                    let checked = false;


                    if (
                        text.charAt(0) === '+'
                    ) {

                        checked = true;
                        text =
                            text.substring(1);
                    }


                    if (
                        text.charAt(0) === '#'
                    ) {

                        items +=
                            '<div style="' +
                            'font-weight:600;' +
                            'margin:10px 0 5px;' +
                            '">' +

                            escapeHtml(
                                text.replace(
                                    /^#+/,
                                    ''
                                ).trim()
                            ) +

                            '</div>';


                        return;
                    }


                    let padding = 0;


                    const dashMatch =
                        text.match(
                            /^(-+)\s*(.*)$/
                        );


                    if (dashMatch) {

                        padding =
                            dashMatch[1].length *
                            10;

                        text =
                            dashMatch[2];
                    }


                    items +=
                        '<div style="' +
                        'display:flex;' +
                        'align-items:flex-start;' +
                        'margin:7px 0;' +
                        'padding-left:' +
                        padding +
                        'px;' +
                        '">' +

                        '<input ' +
                        'type="checkbox" ' +
                        'disabled ' +
                        (
                            checked
                                ? 'checked '
                                : ''
                        ) +
                        'style="' +
                        'margin:3px 8px 0 0;' +
                        '">' +

                        '<span>' +
                        escapeHtml(text) +
                        '</span>' +

                        '</div>';
                });


            const block =
                '<div ' +
                'id="s10-persistent-checklist-' +
                taskId +
                '" ' +
                'style="' +
                'margin:15px 0 20px;' +
                'padding:15px;' +
                'border:1px solid #ddd;' +
                'background:#fff;' +
                '">' +

                '<div style="' +
                'font-size:18px;' +
                'font-weight:600;' +
                'margin-bottom:10px;' +
                '">' +
                'Чек-лист:' +
                '</div>' +

                items +

                '</div>';


            let taskScripts = null;


            if (isKanbanIframePage()) {

                taskScripts =
                    document.querySelector(
                        '.task-scripts'
                    );

            } else {

                const container =
                    getTaskContainer(
                        taskId
                    );


                if (container) {

                    taskScripts =
                        container.querySelector(
                            '.task-scripts'
                        );
                }
            }


            if (taskScripts) {

                taskScripts.insertAdjacentHTML(
                    'beforebegin',
                    block
                );
            }
        }


        async function syncTask(taskId) {

            taskId =
                normalizeTaskId(
                    taskId
                );


            if (!taskId) {
                return;
            }


            if (busyTasks.has(taskId)) {
                return;
            }


            busyTasks.add(
                taskId
            );


            try {

                const state =
                    await getTaskState(
                        taskId
                    );


                const transition =
                    getTransition(
                        taskId
                    );


                const handoff =
                    getHandoff(
                        taskId
                    );


                /*
                 * Есть активный task_script.
                 */
                if (state.activeId) {

                    const current =
                        await getChecklist(
                            state.activeId
                        );


                    const hasTransition =
                        transition &&
                        transition.fromScriptId &&
                        transition.fromScriptId !==
                            state.activeId;


                    /*
                     * Реально произошла смена task_script.
                     */
                    if (hasTransition) {

                        let desiredContent =
                            handoff &&
                            handoff.content
                                ? handoff.content
                                : null;


                        if (!desiredContent) {

                            const oldChecklist =
                                await getChecklist(
                                    transition.fromScriptId
                                );


                            if (oldChecklist) {

                                desiredContent =
                                    oldChecklist.content;
                            }
                        }


                        if (
                            desiredContent &&
                            desiredContent.trim()
                        ) {

                            const currentContent =
                                current &&
                                current.content
                                    ? current.content
                                    : '';


                            if (
                                currentContent !==
                                desiredContent
                            ) {

                                await saveChecklist(
                                    state.activeId,
                                    desiredContent,
                                    current
                                        ? current.checklistId
                                        : ''
                                );
                            }
                        }


                        /*
                         * На Kanban после подтверждённого
                         * перехода — ровно одна полная
                         * перерисовка.
                         */
                        if (isKanbanIframePage()) {

                            await refreshWholeTaskScripts(
                                taskId
                            );

                        } else if (
                            desiredContent
                        ) {

                            await refreshChecklist(
                                taskId,
                                state.activeId
                            );
                        }


                        clearTransitionData(
                            taskId
                        );


                        return;
                    }


                    /*
                     * Просто открыли существующую задачу.
                     * Ничего принудительно не перерисовываем.
                     */
                    if (!current) {

                        const previous =
                            await findPreviousChecklist(
                                state.historyIds
                            );


                        if (previous) {

                            await saveChecklist(
                                state.activeId,
                                previous.content,
                                ''
                            );


                            /*
                             * Тут блок обновляется только потому,
                             * что реально был восстановлен
                             * отсутствующий чек-лист.
                             */
                            if (isKanbanIframePage()) {

                                await refreshWholeTaskScripts(
                                    taskId
                                );

                            } else {

                                await refreshChecklist(
                                    taskId,
                                    state.activeId
                                );
                            }
                        }
                    }


                    return;
                }


                /*
                 * Задача завершена.
                 */
                if (state.completed) {

                    let content =
                        handoff &&
                        handoff.content
                            ? handoff.content
                            : null;


                    if (
                        !content &&
                        transition &&
                        transition.fromScriptId
                    ) {

                        const oldChecklist =
                            await getChecklist(
                                transition.fromScriptId
                            );


                        if (oldChecklist) {

                            content =
                                oldChecklist.content;
                        }
                    }


                    if (!content) {

                        const previous =
                            await findPreviousChecklist(
                                state.historyIds
                            );


                        if (previous) {

                            content =
                                previous.content;
                        }
                    }


                    if (
                        transition &&
                        isKanbanIframePage()
                    ) {

                        await refreshWholeTaskScripts(
                            taskId
                        );
                    }


                    if (content) {

                        renderCompletedChecklist(
                            taskId,
                            content
                        );
                    }


                    clearTransitionData(
                        taskId
                    );
                }


            } catch (error) {

                console.error(
                    PREFIX,
                    'Ошибка задачи ' +
                    taskId +
                    ':',
                    error
                );

            } finally {

                busyTasks.delete(
                    taskId
                );
            }
        }


        function scheduleTaskSync(taskId) {

            [
                500,
                1200,
                2500
            ].forEach(function (delay) {

                setTimeout(function () {

                    syncTask(
                        taskId
                    );

                }, delay);
            });
        }


        /*
         * =====================================
         * SUBMIT
         * =====================================
         *
         * ВАЖНО:
         *
         * обычная страница:
         * /pl/tasks/task/task-script-result
         *
         * Kanban:
         * /pl/tasks/kanban/task-script-result
         */


        document.addEventListener(
            'submit',
            function (event) {

                const form =
                    event.target;


                if (!form) {
                    return;
                }


                const action =
                    String(
                        form.action || ''
                    );


                if (
                    action.indexOf(
                        '/pl/tasks/task/task-script-result'
                    ) === -1 &&
                    action.indexOf(
                        '/pl/tasks/kanban/task-script-result'
                    ) === -1
                ) {
                    return;
                }


                const taskId =
                    getTaskIdFromElement(
                        form
                    ) ||
                    (
                        isKanbanIframePage()
                            ? getUrlTaskId()
                            : null
                    );


                if (!taskId) {
                    return;
                }


                /*
                 * В твоём Network Kanban передаёт
                 * taskScriptId непосредственно в форме.
                 */
                let submittedScriptId =
                    null;


                try {

                    const formData =
                        new FormData(
                            form
                        );


                    submittedScriptId =
                        normalizeTaskId(
                            formData.get(
                                'taskScriptId'
                            )
                        );

                } catch (error) {
                    submittedScriptId = null;
                }


                markTransition(
                    taskId,
                    submittedScriptId
                );


                scheduleTaskSync(
                    taskId
                );
            },
            true
        );


        /*
         * Выполнить сейчас / отказаться.
         */
        document.addEventListener(
            'click',
            function (event) {

                const element =
                    event.target.closest(
                        'button, a'
                    );


                if (!element) {
                    return;
                }


                const runNow =
                    element.matches(
                        '.run-script-now'
                    );


                const text =
                    String(
                        element.textContent ||
                        ''
                    )
                    .trim()
                    .toLowerCase();


                const refuseTask =
                    text.indexOf(
                        'отказаться от задачи'
                    ) !== -1;


                if (
                    !runNow &&
                    !refuseTask
                ) {
                    return;
                }


                const taskId =
                    getTaskIdFromElement(
                        element
                    ) ||
                    (
                        isKanbanIframePage()
                            ? getUrlTaskId()
                            : null
                    );


                if (!taskId) {
                    return;
                }


                markTransition(
                    taskId,
                    null
                );


                scheduleTaskSync(
                    taskId
                );
            },
            true
        );


        function scanPage() {

            const taskIds =
                discoverTaskIds();


            taskIds.forEach(function (taskId) {

                if (
                    knownTasks.has(
                        taskId
                    )
                ) {
                    return;
                }


                knownTasks.add(
                    taskId
                );


                scheduleTaskSync(
                    taskId
                );
            });
        }


        setTimeout(
            scanPage,
            700
        );


        const observer =
            new MutationObserver(
                function () {

                    clearTimeout(
                        window.__S10_TASK_SCAN_TIMER_V131__
                    );


                    window.__S10_TASK_SCAN_TIMER_V131__ =
                        setTimeout(
                            scanPage,
                            400
                        );
                }
            );


        observer.observe(
            document.body,
            {
                childList: true,
                subtree: true
            }
        );


        console.log(
            PREFIX,
            'запущен'
        );

    });

})();