/*global SelectBox, interpolate*/
// Handles related-objects functionality: lookup link for raw_id_fields
// and Add Another links.
'use strict';
{
    // 引入Django封装的jQuery
    const $ = django.jQuery;
    // 弹窗索引：用于区分多个层级的弹窗
    let popupIndex = 0;
    // 存储已打开的关联对象弹窗窗口
    const relatedWindows = [];
    /**
     * 关闭所有子弹窗
     * 递归关闭当前窗口打开的所有关联弹窗，避免窗口残留
     */
    function dismissChildPopups() {
        relatedWindows.forEach(function(win) {
            if(!win.closed) {
                win.dismissChildPopups();
                win.close();    
            }
        });
    }
    /**
     * 设置弹窗索引
     * 根据当前窗口名称判断是否为弹窗，提取并设置popupIndex
     * 用于区分多层级弹窗（如弹窗中再打开弹窗）
     */
    function setPopupIndex() {
        if(document.getElementsByName("_popup").length > 0) {
            const index = window.name.lastIndexOf("__") + 2;
            popupIndex = parseInt(window.name.substring(index));   
        } else {
            popupIndex = 0;
        }
    }
    /**
     * 给名称添加弹窗索引
     * 用于生成子弹窗的唯一名称（避免窗口名称冲突）
     * @param {string} name - 基础名称
     * @return {string} 添加索引后的名称（如"name__2"）
     */
    function addPopupIndex(name) {
        return name + "__" + (popupIndex + 1);
    }
    /**
     * 从名称中移除弹窗索引
     * 关闭弹窗时恢复原始名称，用于定位关联的表单元素
     * @param {string} name - 带索引的名称
     * @return {string} 移除索引后的原始名称
     */
    function removePopupIndex(name) {
        return name.replace(new RegExp("__" + (popupIndex + 1) + "$"), '');
    }
    /**
     * 显示管理员弹窗（基础方法）
     * 打开新窗口展示关联对象的添加/编辑/查找页面
     * @param {HTMLElement} triggeringLink - 触发弹窗的链接元素
     * @param {RegExp} name_regexp - 用于提取基础名称的正则表达式
     * @param {boolean} add_popup - 是否添加_popup参数（标记为弹窗模式）
     * @return {boolean} false - 阻止链接默认跳转行为
     */
    function showAdminPopup(triggeringLink, name_regexp, add_popup) {
        const name = addPopupIndex(triggeringLink.id.replace(name_regexp, ''));
        const href = new URL(triggeringLink.href);
        if (add_popup) {
            href.searchParams.set('_popup', 1);
        }
        const win = window.open(href, name, 'height=500,width=800,resizable=yes,scrollbars=yes');
        relatedWindows.push(win);
        win.focus();
        return false;
    }
    /**
     * 显示关联对象查找弹窗
     * 用于raw_id_fields类型的字段，点击查找图标打开弹窗选择对象
     * @param {HTMLElement} triggeringLink - 触发链接（通常是查找图标）
     * @return {boolean} 调用showAdminPopup的返回值
     */
    function showRelatedObjectLookupPopup(triggeringLink) {
        return showAdminPopup(triggeringLink, /^lookup_/, true);
    }
    /**
     * 关闭关联对象查找弹窗
     * 选择对象后，将选中的ID填充到对应的输入框
     * @param {Window} win - 弹窗窗口对象
     * @param {string} chosenId - 选中的对象ID
     */
    function dismissRelatedLookupPopup(win, chosenId) {
        const name = removePopupIndex(win.name);
        const elem = document.getElementById(name);
        if (elem.classList.contains('vManyToManyRawIdAdminField') && elem.value) {
            elem.value += ',' + chosenId;
        } else {
            elem.value = chosenId;
        }
        $(elem).trigger('change');
        const index = relatedWindows.indexOf(win);
        if (index > -1) {
            relatedWindows.splice(index, 1);
        }
        win.close();
    }
    /**
     * 显示关联对象操作弹窗（添加/编辑/删除）
     * 用于打开关联对象的添加、编辑或删除页面
     * @param {HTMLElement} triggeringLink - 触发链接（如"添加"或"编辑"按钮）
     * @return {boolean} 调用showAdminPopup的返回值
     */
    function showRelatedObjectPopup(triggeringLink) {
        return showAdminPopup(triggeringLink, /^(change|add|delete)_/, false);
    }
    /**
     * 更新关联对象链接状态
     * 当关联字段的值变化时，更新"查看"、"编辑"、"删除"等链接的可用性
     * @param {HTMLElement} triggeringLink - 触发变化的输入框/选择框
     */
    function updateRelatedObjectLinks(triggeringLink) {
        const $this = $(triggeringLink);
        const siblings = $this.nextAll('.view-related, .change-related, .delete-related');
        if (!siblings.length) {
            return;
        }
        const value = $this.val();
        if (value) {
            siblings.each(function() {
                const elm = $(this);
                elm.attr('href', elm.attr('data-href-template').replace('__fk__', value));
                elm.removeAttr('aria-disabled');
            });
        } else {
            siblings.removeAttr('href');
            siblings.attr('aria-disabled', true);
        }
    }
    /**
     * 更新关联选择框的选项
     * 当添加/编辑关联对象后，同步更新页面中其他相关的选择框选项
     * @param {HTMLElement} currentSelect - 当前操作的选择框
     * @param {Window} win - 弹窗窗口对象
     * @param {string} objId - 原对象ID（编辑时使用）
     * @param {string} newRepr - 新的对象显示文本
     * @param {string} newId - 新的对象ID
     * @param {Array} skipIds - 需要跳过的选择框ID列表
     */
    function updateRelatedSelectsOptions(currentSelect, win, objId, newRepr, newId, skipIds = []) {
        // After create/edit a model from the options next to the current
        // select (+ or :pencil:) update ForeignKey PK of the rest of selects
        // in the page.

        const path = win.location.pathname;
        // Extract the model from the popup url '.../<model>/add/' or
        // '.../<model>/<id>/change/' depending the action (add or change).
        const modelName = path.split('/')[path.split('/').length - (objId ? 4 : 3)];
        // Select elements with a specific model reference and context of "available-source".
        const selectsRelated = document.querySelectorAll(`[data-model-ref="${modelName}"] [data-context="available-source"]`);

        selectsRelated.forEach(function(select) {
            if (currentSelect === select || skipIds && skipIds.includes(select.id)) {
                return;
            }

            let option = select.querySelector(`option[value="${objId}"]`);

            if (!option) {
                option = new Option(newRepr, newId);
                select.options.add(option);
                // Update SelectBox cache for related fields.
                if (window.SelectBox !== undefined && !SelectBox.cache[currentSelect.id]) {
                    SelectBox.add_to_cache(select.id, option);
                    SelectBox.redisplay(select.id);
                }
                return;
            }

            option.textContent = newRepr;
            option.value = newId;
        });
    }
    /**
     * 关闭添加关联对象弹窗
     * 添加新关联对象后，将新对象添加到选择框或输入框，并同步更新其他相关选择框
     * @param {Window} win - 弹窗窗口对象
     * @param {string} newId - 新对象的ID
     * @param {string} newRepr - 新对象的显示文本
     */
    function dismissAddRelatedObjectPopup(win, newId, newRepr) {
        const name = removePopupIndex(win.name);
        const elem = document.getElementById(name);
        if (elem) {
            const elemName = elem.nodeName.toUpperCase();
            if (elemName === 'SELECT') {
                elem.options[elem.options.length] = new Option(newRepr, newId, true, true);
                updateRelatedSelectsOptions(elem, win, null, newRepr, newId);
            } else if (elemName === 'INPUT') {
                if (elem.classList.contains('vManyToManyRawIdAdminField') && elem.value) {
                    elem.value += ',' + newId;
                } else {
                    elem.value = newId;
                }
            }
            // Trigger a change event to update related links if required.
            $(elem).trigger('change');
        } else {
            const toId = name + "_to";
            const toElem = document.getElementById(toId);
            const o = new Option(newRepr, newId);
            SelectBox.add_to_cache(toId, o);
            SelectBox.redisplay(toId);
            if (toElem && toElem.nodeName.toUpperCase() === 'SELECT') {
                const skipIds = [name + "_from"];
                updateRelatedSelectsOptions(toElem, win, null, newRepr, newId, skipIds);
            }
        }
        const index = relatedWindows.indexOf(win);
        if (index > -1) {
            relatedWindows.splice(index, 1);
        }
        win.close();
    }
    /**
     * 关闭编辑关联对象弹窗
     * 编辑关联对象后，更新选择框中对应选项的文本和ID，并同步其他相关选择框
     * @param {Window} win - 弹窗窗口对象
     * @param {string} objId - 原对象ID
     * @param {string} newRepr - 编辑后的显示文本
     * @param {string} newId - 编辑后的对象ID（可能不变）
     */
    function dismissChangeRelatedObjectPopup(win, objId, newRepr, newId) {
        const id = removePopupIndex(win.name.replace(/^edit_/, ''));
        const selectsSelector = interpolate('#%s, #%s_from, #%s_to', [id, id, id]);
        const selects = $(selectsSelector);
        selects.find('option').each(function() {
            if (this.value === objId) {
                this.textContent = newRepr;
                this.value = newId;
            }
        }).trigger('change');
        updateRelatedSelectsOptions(selects[0], win, objId, newRepr, newId);
        selects.next().find('.select2-selection__rendered').each(function() {
            // The element can have a clear button as a child.
            // Use the lastChild to modify only the displayed value.
            this.lastChild.textContent = newRepr;
            this.title = newRepr;
        });
        const index = relatedWindows.indexOf(win);
        if (index > -1) {
            relatedWindows.splice(index, 1);
        }
        win.close();
    }
    /**
     * 关闭删除关联对象弹窗
     * 删除关联对象后，从选择框中移除对应的选项
     * @param {Window} win - 弹窗窗口对象
     * @param {string} objId - 被删除对象的ID
     */
    function dismissDeleteRelatedObjectPopup(win, objId) {
        const id = removePopupIndex(win.name.replace(/^delete_/, ''));
        const selectsSelector = interpolate('#%s, #%s_from, #%s_to', [id, id, id]);
        const selects = $(selectsSelector);
        selects.find('option').each(function() {
            if (this.value === objId) {
                $(this).remove();
            }
        }).trigger('change');
        const index = relatedWindows.indexOf(win);
        if (index > -1) {
            relatedWindows.splice(index, 1);
        }
        win.close();
    }
    // 将核心方法暴露到window全局，供页面元素调用
    window.showRelatedObjectLookupPopup = showRelatedObjectLookupPopup;
    window.dismissRelatedLookupPopup = dismissRelatedLookupPopup;
    window.showRelatedObjectPopup = showRelatedObjectPopup;
    window.updateRelatedObjectLinks = updateRelatedObjectLinks;
    window.dismissAddRelatedObjectPopup = dismissAddRelatedObjectPopup;
    window.dismissChangeRelatedObjectPopup = dismissChangeRelatedObjectPopup;
    window.dismissDeleteRelatedObjectPopup = dismissDeleteRelatedObjectPopup;
    window.dismissChildPopups = dismissChildPopups;
    window.relatedWindows = relatedWindows;

    // Kept for backward compatibility
    window.showAddAnotherPopup = showRelatedObjectPopup;
    window.dismissAddAnotherPopup = dismissAddRelatedObjectPopup;

    window.addEventListener('unload', function(evt) {
        window.dismissChildPopups();
    });

    $(document).ready(function() {
        setPopupIndex();
        $("a[data-popup-opener]").on('click', function(event) {
            event.preventDefault();
            opener.dismissRelatedLookupPopup(window, $(this).data("popup-opener"));
        });
        $('body').on('click', '.related-widget-wrapper-link[data-popup="yes"]', function(e) {
            e.preventDefault();
            if (this.href) {
                const event = $.Event('django:show-related', {href: this.href});
                $(this).trigger(event);
                if (!event.isDefaultPrevented()) {
                    showRelatedObjectPopup(this);
                }
            }
        });
        $('body').on('change', '.related-widget-wrapper select', function(e) {
            const event = $.Event('django:update-related');
            $(this).trigger(event);
            if (!event.isDefaultPrevented()) {
                updateRelatedObjectLinks(this);
            }
        });
        $('.related-widget-wrapper select').trigger('change');
        $('body').on('click', '.related-lookup', function(e) {
            e.preventDefault();
            const event = $.Event('django:lookup-related');
            $(this).trigger(event);
            if (!event.isDefaultPrevented()) {
                showRelatedObjectLookupPopup(this);
            }
        });
    });
}
