/**
 * @fileoverview KeyGroups Page Initialization and Management. (Refactored to use ui.js)
 *
 * @description
 * This module handles all the client-side interactivity for the KeyGroups
 * management page. It leverages the central `modalManager` from ui.js for all modal
 * interactions, ensuring architectural consistency.
 */

import { modalManager,taskCenterManager } from '../components/ui.js'; 
import CustomSelect from '../components/customSelect.js';
import { debounce, isValidApiKeyFormat, initModal } from '../utils/utils.js';
import { apiFetch, apiFetchJson } from '../services/api.js'; 
import { apiKeyManager } from '../components/apiKeyManager.js';

class TagInput {
    constructor(container) {
        this.container = container;
        this.input = container.querySelector('.tag-input-new');
        this.tags = [];
        this._initEventListeners();
    }

    _initEventListeners() {
        this.container.addEventListener('click', (e) => {
            if (e.target.classList.contains('tag-delete')) {
                this._removeTag(e.target.parentElement);
            }
        });

        this.input.addEventListener('keydown', (e) => {
            if (e.key === 'Enter' || e.key === ',') {
                e.preventDefault();
                const value = this.input.value.trim();
                if (value) {
                    this._addTag(value);
                    this.input.value = '';
                }
            }
        });
    }

    _addTag(value) {
        if (this.tags.includes(value)) return;
        this.tags.push(value);

        const tagEl = document.createElement('span');
        tagEl.className = 'tag-item';
        tagEl.innerHTML = `${value}<button class="tag-delete">&times;</button>`;
        
        this.container.insertBefore(tagEl, this.input);
    }

    _removeTag(tagEl) {
        const value = tagEl.textContent.slice(0, -1); // Remove the '×'
        this.tags = this.tags.filter(t => t !== value);
        tagEl.remove();
    }

    getValues() {
        return this.tags;
    }

    setValues(values) {
        // Clear existing tags
        this.container.querySelectorAll('.tag-item').forEach(el => el.remove());
        this.tags = [];
        // Add new ones
        values.forEach(value => this._addTag(value));
    }
}


class RequestSettingsModal {
    constructor(modalId, onSaveCallback) {
        this.modal = document.getElementById(modalId);
        if (!this.modal) {
            throw new Error(`Modal with id "${modalId}" not found.`);
        }
        this.onSave = onSaveCallback;

        // --- Form Element Mapping ---
        this.elements = {
            // Main buttons
            saveBtn: document.getElementById('request-settings-save-btn'),
            // Custom Headers
            customHeadersContainer: document.getElementById('CUSTOM_HEADERS_container'),
            addCustomHeaderBtn: document.getElementById('addCustomHeaderBtn'),
            // Streaming
            streamOptimizerEnabled: document.getElementById('STREAM_OPTIMIZER_ENABLED'),
            streamingSettingsPanel: document.getElementById('streaming-settings-panel'), // 新增
            streamMinDelay: document.getElementById('STREAM_MIN_DELAY'),
            streamMaxDelay: document.getElementById('STREAM_MAX_DELAY'),
            streamShortTextThresh: document.getElementById('STREAM_SHORT_TEXT_THRESHOLD'),
            streamLongTextThresh: document.getElementById('STREAM_LONG_TEXT_THRESHOLD'),
            streamChunkSize: document.getElementById('STREAM_CHUNK_SIZE'),
            fakeStreamEnabled: document.getElementById('FAKE_STREAM_ENABLED'),
            fakeStreamInterval: document.getElementById('FAKE_STREAM_EMPTY_DATA_INTERVAL_SECONDS'),
            // Model Settings
            imageModelsContainer: document.getElementById('IMAGE_MODELS_container'),
            searchModelsContainer: document.getElementById('SEARCH_MODELS_container'),
            filteredModelsContainer: document.getElementById('FILTERED_MODELS_container'),
            toolsCodeExecutionEnabled: document.getElementById('TOOLS_CODE_EXECUTION_ENABLED'),
            urlContextEnabled: document.getElementById('URL_CONTEXT_ENABLED'),
            urlContextModelsContainer: document.getElementById('URL_CONTEXT_MODELS_container'),
            showSearchLink: document.getElementById('SHOW_SEARCH_LINK'),
            showThinkingProcess: document.getElementById('SHOW_THINKING_PROCESS'),
            thinkingModelsContainer: document.getElementById('THINKING_MODELS_container'),
            thinkingBudgetMapContainer: document.getElementById('THINKING_BUDGET_MAP_container'),
            safetySettingsContainer: document.getElementById('SAFETY_SETTINGS_container'),
            addSafetySettingBtn: document.getElementById('addSafetySettingBtn'),
            // Overrides
            configOverrides: document.getElementById('group-config-overrides'),
        };

        this._initEventListeners();
    }

    _initEventListeners() {
        // Event delegation for remove buttons within dynamic containers
        this.modal.addEventListener('click', (e) => {
            const removeBtn = e.target.closest('.remove-btn');
            if (removeBtn) {
                const itemToRemove = removeBtn.parentElement;
                itemToRemove.remove();
            }
        });

        if (this.elements.addCustomHeaderBtn) {
            this.elements.addCustomHeaderBtn.addEventListener('click', () => this.addCustomHeaderItem());
        }

        if (this.elements.addSafetySettingBtn) {
            this.elements.addSafetySettingBtn.addEventListener('click', () => this.addSafetySettingItem());
        }

        if (this.elements.saveBtn) {
            this.elements.saveBtn.addEventListener('click', this._handleSave.bind(this));
        }
         // [新增] 流式优化开关的监听器
        if (this.elements.streamOptimizerEnabled) {
            this.elements.streamOptimizerEnabled.addEventListener('change', (e) => {
                this._toggleStreamingPanel(e.target.checked);
            });
        }
    }
    // [新增] 控制流式面板显示/隐藏的辅助函数
    _toggleStreamingPanel(is_enabled) {
        if (this.elements.streamingSettingsPanel) {
            if (is_enabled) {
                this.elements.streamingSettingsPanel.classList.remove('hidden');
            } else {
                this.elements.streamingSettingsPanel.classList.add('hidden');
            }
        }
    }

    async _handleSave() {
        const data = this.collectFormData();
        if (this.onSave) {
            try {
                if (this.elements.saveBtn) {
                    this.elements.saveBtn.disabled = true;
                    this.elements.saveBtn.textContent = 'Saving...';
                }
                await this.onSave(data);
                this.close();
            } catch (error) {
                console.error("Failed to save request settings:", error);
                // TODO: Show error message to user in the modal
            } finally {
                if (this.elements.saveBtn) {
                    this.elements.saveBtn.disabled = false;
                    this.elements.saveBtn.textContent = 'Save Changes';
                }
            }
        }
    }

    open() {
        this.modal.classList.remove('hidden');
    }

    close() {
        this.modal.classList.add('hidden');
    }

    /**
     * Adds a new key-value pair item for Custom Headers.
     * @param {string} [key=''] - The initial key.
     * @param {string} [value=''] - The initial value.
     */
    addCustomHeaderItem(key = '', value = '') {
        const container = this.elements.customHeadersContainer;
        const item = document.createElement('div');
        item.className = 'dynamic-kv-item';
        item.innerHTML = `
            <input type="text" class="modal-input text-xs bg-zinc-100 dark:bg-zinc-700/50" placeholder="Header Name" value="${key}">
            <input type="text" class="modal-input text-xs" placeholder="Header Value" value="${value}">
            <button type="button" class="remove-btn text-zinc-400 hover:text-red-500 transition-colors"><i class="fas fa-trash-alt"></i></button>
        `;
        container.appendChild(item);
    }

    /**
     * Adds a new item for Safety Settings.
     * @param {string} [category=''] - The initial category.
     * @param {string} [threshold=''] - The initial threshold.
     */
    addSafetySettingItem(category = '', threshold = '') {
        const container = this.elements.safetySettingsContainer;
        const item = document.createElement('div');
        item.className = 'safety-setting-item flex items-center gap-x-2';

        const harmCategories = [
            "HARM_CATEGORY_HARASSMENT", "HARM_CATEGORY_HATE_SPEECH",
            "HARM_CATEGORY_SEXUALLY_EXPLICIT", "HARM_CATEGORY_DANGEROUS_CONTENT","HARM_CATEGORY_DANGEROUS_CONTENT",
            "HARM_CATEGORY_CIVIC_INTEGRITY" 
        ];
        const harmThresholds = [
            "BLOCK_OFF","BLOCK_NONE", "BLOCK_LOW_AND_ABOVE",
            "BLOCK_MEDIUM_AND_ABOVE", "BLOCK_ONLY_HIGH"
        ];

        const categorySelect = document.createElement('select');
        categorySelect.className = 'modal-input flex-grow'; // .modal-input 在静态<select>上是有效的
        harmCategories.forEach(cat => {
            const option = new Option(cat.replace('HARM_CATEGORY_', ''), cat);
            if (cat === category) option.selected = true;
            categorySelect.add(option);
        });
        const thresholdSelect = document.createElement('select');
        thresholdSelect.className = 'modal-input w-48';
        harmThresholds.forEach(thr => {
            const option = new Option(thr.replace('BLOCK_', '').replace('_AND_ABOVE', '+'), thr);
            if (thr === threshold) option.selected = true;
            thresholdSelect.add(option);
        });
        
        const removeButton = document.createElement('button');
        removeButton.type = 'button';
        removeButton.className = 'remove-btn text-zinc-400 hover:text-red-500 transition-colors';
        removeButton.innerHTML = `<i class="fas fa-trash-alt"></i>`;
        item.appendChild(categorySelect);
        item.appendChild(thresholdSelect);
        item.appendChild(removeButton);
        container.appendChild(item);
    }
    /**
     * Populates the modal form with data received from the backend.
     * @param {object} data - The request configuration data.
     */
    populateForm(data) {
        if (!data) return;

        // --- Simple Toggles & Inputs ---
        const isStreamOptimizerEnabled = !!data.stream_optimizer_enabled;
        this._setToggle(this.elements.streamOptimizerEnabled, isStreamOptimizerEnabled);
        this._toggleStreamingPanel(isStreamOptimizerEnabled); 
        this._setToggle(this.elements.streamOptimizerEnabled, data.stream_optimizer_enabled);
        this._setValue(this.elements.streamMinDelay, data.stream_min_delay);
        this._setValue(this.elements.streamMaxDelay, data.stream_max_delay);
        this._setValue(this.elements.streamShortTextThresh, data.stream_short_text_threshold);
        this._setValue(this.elements.streamLongTextThresh, data.stream_long_text_threshold);
        this._setValue(this.elements.streamChunkSize, data.stream_chunk_size);
        this._setToggle(this.elements.fakeStreamEnabled, data.fake_stream_enabled);
        this._setValue(this.elements.fakeStreamInterval, data.fake_stream_empty_data_interval_seconds);
        this._setToggle(this.elements.toolsCodeExecutionEnabled, data.tools_code_execution_enabled);
        this._setToggle(this.elements.urlContextEnabled, data.url_context_enabled);
        this._setToggle(this.elements.showSearchLink, data.show_search_link);
        this._setToggle(this.elements.showThinkingProcess, data.show_thinking_process);
        this._setValue(this.elements.configOverrides, data.config_overrides);

        // --- Dynamic & Complex Fields ---
        this._populateKVItems(this.elements.customHeadersContainer, data.custom_headers, this.addCustomHeaderItem.bind(this));
        this._populateKVItems(this.elements.safetySettingsContainer, data.safety_settings, this.addSafetySettingItem.bind(this));
        
        // TODO: Handle Tag Inputs for model lists
        // this.imageModelsInput.setValues(data.image_models || []);
        // this.searchModelsInput.setValues(data.search_models || []);
        // ... and so on for other tag inputs
    }

    /**
     * Collects all data from the form fields and returns it as an object.
     * @returns {object} The collected request configuration data.
     */
    collectFormData() {
        const data = {
            // Simple Toggles & Inputs
            stream_optimizer_enabled: this.elements.streamOptimizerEnabled.checked,
            stream_min_delay: parseInt(this.elements.streamMinDelay.value, 10),
            stream_max_delay: parseInt(this.elements.streamMaxDelay.value, 10),
            stream_short_text_threshold: parseInt(this.elements.streamShortTextThresh.value, 10),
            stream_long_text_threshold: parseInt(this.elements.streamLongTextThresh.value, 10),
            stream_chunk_size: parseInt(this.elements.streamChunkSize.value, 10),
            fake_stream_enabled: this.elements.fakeStreamEnabled.checked,
            fake_stream_empty_data_interval_seconds: parseInt(this.elements.fakeStreamInterval.value, 10),
            tools_code_execution_enabled: this.elements.toolsCodeExecutionEnabled.checked,
            url_context_enabled: this.elements.urlContextEnabled.checked,
            show_search_link: this.elements.showSearchLink.checked,
            show_thinking_process: this.elements.showThinkingProcess.checked,
            config_overrides: this.elements.configOverrides.value,

            // Dynamic & Complex Fields
            custom_headers: this._collectKVItems(this.elements.customHeadersContainer),
            safety_settings: this._collectSafetySettings(this.elements.safetySettingsContainer),

            // TODO: Collect from Tag Inputs
            // image_models: this.imageModelsInput.getValues(),
        };
        return data;
    }

    // --- Private Helper Methods for Form Handling ---

    _setValue(element, value) {
        if (element && value !== null && value !== undefined) {
            element.value = value;
        }
    }

    _setToggle(element, value) {
        if (element) {
            element.checked = !!value;
        }
    }

    _clearContainer(container) {
        if (container) {
            // Keep the first child if it's a template or header
            const firstChild = container.firstElementChild;
            const isTemplate = firstChild && (firstChild.tagName === 'TEMPLATE' || firstChild.id === 'kv-item-header');
            
            let child = isTemplate ? firstChild.nextElementSibling : container.firstElementChild;
            while (child) {
                const next = child.nextElementSibling;
                child.remove();
                child = next;
            }
        }
    }

    _populateKVItems(container, items, addItemFn) {
        this._clearContainer(container);
        if (items && typeof items === 'object') {
            for (const [key, value] of Object.entries(items)) {
                addItemFn(key, value);
            }
        }
    }

    _collectKVItems(container) {
        const items = {};
        container.querySelectorAll('.dynamic-kv-item').forEach(item => {
            const keyEl = item.querySelector('.dynamic-kv-key');
            const valueEl = item.querySelector('.dynamic-kv-value');
            if (keyEl && valueEl && keyEl.value) {
                items[keyEl.value] = valueEl.value;
            }
        });
        return items;
    }

    _collectSafetySettings(container) {
        const items = {};
        container.querySelectorAll('.safety-setting-item').forEach(item => {
            const categorySelect = item.querySelector('select:first-child');
            const thresholdSelect = item.querySelector('select:last-of-type');
            if (categorySelect && thresholdSelect && categorySelect.value) {
                items[categorySelect.value] = thresholdSelect.value;
            }
        });
        return items;
    }
}


class KeyGroupsPage {

// [重構] 构造函数现在接收 modalManager 实例
    constructor(modalManagerInstance) {
        // 1. 引入UI和状态管理对象
        this.modalManager = modalManagerInstance;
        this.state = {
            groups: [],
            apiKeys: [], // 新增：存储当前分组的API Keys
            activeGroupId: null,
            isLoading: true,
            isApiKeysLoading: false, // 新增：API Keys加载状态
        };

        this.taskPollInterval = null;
        this.debouncedSaveOrder = debounce(this.saveGroupOrder.bind(this), 1500);

        this.elements = {
            // Modals
            keyGroupModal: document.getElementById('keygroup-modal'),
            modalTitle: document.getElementById('modal-title'),
            addApiModal: document.getElementById('add-api-modal'),
            deleteApiModal: document.getElementById('delete-api-modal'),
            requestSettingsModal: document.getElementById('request-settings-modal'),
           
            // Page Elements
            dashboardTitle: document.querySelector('#group-dashboard h2'),
            dashboardControls: document.querySelector('#group-dashboard .flex.items-center.gap-x-3'),
            apiListContainer: document.getElementById('api-list-container'),
            
            // Group List specific elements
            groupListCollapsible: document.getElementById('group-list-collapsible'),
            desktopGroupContainer: document.querySelector('#desktop-group-cards-list .card-list-content'),
            mobileGroupContainer: document.getElementById('mobile-group-cards-list'),
            addGroupBtnContainer: document.getElementById('add-group-btn-container'),
            
            // Mobile specific elements
            groupMenuToggle: document.getElementById('group-menu-toggle'),
            mobileActiveGroupDisplay: document.querySelector('.mobile-group-selector > div'),

            requestSettings: {
                // Main buttons
                saveBtn: document.getElementById('request-settings-save-btn'),
                // Custom Headers
                customHeadersContainer: document.getElementById('CUSTOM_HEADERS_container'),
                addCustomHeaderBtn: document.getElementById('addCustomHeaderBtn'),
                // Streaming
                streamOptimizerEnabled: document.getElementById('STREAM_OPTIMIZER_ENABLED'),
                streamingSettingsPanel: document.getElementById('streaming-settings-panel'), // 新增
                streamMinDelay: document.getElementById('STREAM_MIN_DELAY'),
                streamMaxDelay: document.getElementById('STREAM_MAX_DELAY'),
                streamShortTextThresh: document.getElementById('STREAM_SHORT_TEXT_THRESHOLD'),
                streamLongTextThresh: document.getElementById('STREAM_LONG_TEXT_THRESHOLD'),
                streamChunkSize: document.getElementById('STREAM_CHUNK_SIZE'),
                fakeStreamEnabled: document.getElementById('FAKE_STREAM_ENABLED'),
                fakeStreamInterval: document.getElementById('FAKE_STREAM_EMPTY_DATA_INTERVAL_SECONDS'),
                // Model Settings
                imageModelsContainer: document.getElementById('IMAGE_MODELS_container'),
                searchModelsContainer: document.getElementById('SEARCH_MODELS_container'),
                filteredModelsContainer: document.getElementById('FILTERED_MODELS_container'),
                toolsCodeExecutionEnabled: document.getElementById('TOOLS_CODE_EXECUTION_ENABLED'),
                urlContextEnabled: document.getElementById('URL_CONTEXT_ENABLED'),
                urlContextModelsContainer: document.getElementById('URL_CONTEXT_MODELS_container'),
                showSearchLink: document.getElementById('SHOW_SEARCH_LINK'),
                showThinkingProcess: document.getElementById('SHOW_THINKING_PROCESS'),
                thinkingModelsContainer: document.getElementById('THINKING_MODELS_container'),
                thinkingBudgetMapContainer: document.getElementById('THINKING_BUDGET_MAP_container'),
                safetySettingsContainer: document.getElementById('SAFETY_SETTINGS_container'),
                addSafetySettingBtn: document.getElementById('addSafetySettingBtn'),
                // Overrides
                configOverrides: document.getElementById('group-config-overrides'),
            },
        };
        
        this.initialized = this.elements.keyGroupModal !== null &&
                           this.elements.desktopGroupContainer !== null;
        
        if (this.initialized) {
            this.allowedModelsInput = new TagInput(document.getElementById('allowed-models-container'));
            this.allowedUpstreamsInput = new TagInput(document.getElementById('allowed-upstreams-container'));
            this.allowedTokensInput = new TagInput(document.getElementById('allowed-tokens-container'));
        }
        this.activeTooltip = null;
        this.requestSettingsModal = null; // Defer initialization
    }


    // 3. 统一的初始化流程
    async init() {
        if (!this.initialized) {
            console.error("KeyGroupsPage: Could not initialize. Essential elements are missing from the DOM.");
            return;
        }
        // Initialize modal here to ensure DOM is ready
        this.requestSettingsModal = new RequestSettingsModal(
            'request-settings-modal',
            this.handleSaveRequestSettings.bind(this)
        );
        this.initEventListeners();
        await this.loadKeyGroups(); // 页面初始化时加载数据
    }
    
    /**
     * [重構] 全面重写事件监听器，使用 modalManager 并废除 initModal。
     */
    initEventListeners() {
        // --- 模态框触发器初始化 ---
        this._initModalTrigger('keygroup-modal', '.add-group-btn, [data-modal-open="keygroup-modal"]', (event, modalId) => {
            // 从事件目标中提取数据来判断是“创建”还是“编辑”
            const groupData = null; // 示例： const groupData = event.currentTarget.dataset.groupData;
            this.openGroupModal(groupData);
        });
        
        this._initModalTrigger('add-api-modal', '#add-api-btn', this._resetAddApiModal.bind(this));
        
        this._initModalTrigger('delete-api-modal', '#delete-api-btn');
        
        this._initModalTrigger('request-settings-modal', '[data-modal-open="request-settings-modal"]', this.openRequestSettingsModal.bind(this));
        
        // 为所有由 modalManager 控制的模态框统一设置关闭逻辑
        this._initGlobalModalClosers(['keygroup-modal', 'add-api-modal', 'delete-api-modal', 'request-settings-modal']);

        const importButton = document.getElementById('add-api-import-btn');
        if (importButton) {
            importButton.addEventListener('click', this.handleAddApiKeysSubmit.bind(this));
        }

        if (this.elements.groupMenuToggle) {
           this.elements.groupMenuToggle.addEventListener('click', () => {
               this.elements.groupListCollapsible.classList.toggle('hidden');
           });
        }
         // 这个元素是桌面和移动列表的共同父级，非常适合事件委托。
        if (this.elements.groupListCollapsible) {
            this.elements.groupListCollapsible.addEventListener('click', (event) => {
                this.handleGroupCardClick(event);
            });
        }
        // Event delegation for dashboard controls (clone, edit, delete)
        if(this.elements.dashboardControls) {
            this.elements.dashboardControls.addEventListener('click', (event) => {
                this.handleDashboardAction(event);
            });
        }
        // Event delegation for API card actions
        if(this.elements.apiListContainer) {
            this.elements.apiListContainer.addEventListener('click', (event) => {
                this.handleApiKeyCardAction(event);
            });
        }
       
        // [重構] RequestSettingsModal 的事件监听器移至此处
        if (this.elements.requestSettings.saveBtn) {
            this.elements.requestSettings.saveBtn.addEventListener('click', this.handleSaveRequestSettings.bind(this));
        }
        if (this.elements.requestSettingsModal) {
            // Event delegation for remove buttons within the modal
            this.elements.requestSettingsModal.addEventListener('click', (e) => {
                const removeBtn = e.target.closest('.remove-btn');
                if (removeBtn) {
                    const itemToRemove = removeBtn.parentElement;
                    itemToRemove.remove();
                }
            });
            // Specific button listeners
            if (this.elements.requestSettings.addCustomHeaderBtn) {
                this.elements.requestSettings.addCustomHeaderBtn.addEventListener('click', () => this.addCustomHeaderItem());
            }
            if (this.elements.requestSettings.addSafetySettingBtn) {
                this.elements.requestSettings.addSafetySettingBtn.addEventListener('click', () => this.addSafetySettingItem());
            }
            if (this.elements.requestSettings.streamOptimizerEnabled) {
                this.elements.requestSettings.streamOptimizerEnabled.addEventListener('change', (e) => {
                    this._toggleStreamingPanel(e.target.checked);
                });
            }
        }

        this.initCustomSelects();
        this.initTooltips();
        this.initDragAndDrop();
        this._initBatchActions();
        // [优化] 这两个函数在数据加载并渲染后调用会更好，但暂时保留在这里
        //this.updateAllHealthIndicators();
        //this.updateAllApiKeyStatusIndicators();
    }

    // 4. 数据获取与渲染逻辑 
    async loadKeyGroups() {
        this.state.isLoading = true;

        // --- [测试数据注入点] ---
        /*const MOCK_DATA = [
            { id: 1, display_name: '默认分组 (Default)', name: 'default', description: '当前选中的分组', successRate: 95 },
            { id: 2, display_name: '高优先级 (High-Priority)', name: 'high-priority', description: '用于处理紧急任务', successRate: 80 },
            { id: 3, display_name: '批量处理 (Batch-Jobs)', name: 'batch-jobs', description: '用于后台和批量作业', successRate: 45 },
            { id: 4, display_name: '实验性功能 (Experimental)', name: 'experimental', description: '测试新模型和功能', successRate: 25 },
            { id: 5, display_name: '旧系统密钥 (Legacy)', name: 'legacy', description: '即将弃用的旧密钥', successRate: 5 },
            { id: 6, display_name: '内部工具 (Internal-Tools)', name: 'internal', description: '仅供内部使用的工具', successRate: 100 },
            { id: 7, display_name: '合作伙伴 A (Partner-A)', name: 'partner-a', description: '为特定合作伙伴提供的API', successRate: 98 },
            { id: 8, display_name: '数据分析 (Data-Analysis)', name: 'data-analysis', description: '用于数据分析和报告', successRate: 35 },
            { id: 9, display_name: '性能测试 (Perf-Testing)', name: 'perf-testing', description: '用于进行压力和性能测试', successRate: 15 },
            { id: 10, display_name: '通用API (General-API)', name: 'general', description: '提供给普通用户的通用接口', successRate: 72 },
            { id: 11, display_name: '文档生成 (Docs-Gen)', name: 'docs-gen', description: '用于自动化生成文档', successRate: 99 },
            { id: 12, display_name: '文档生成 (Docs-Gen)', name: 'docs-gen', description: '用于自动化生成文档', successRate: 99 },
            { id: 13, display_name: '文档生成 (Docs-Gen)', name: 'docs-gen', description: '用于自动化生成文档', successRate: 99 },
            { id: 14, display_name: '文档生成 (Docs-Gen)', name: 'docs-gen', description: '用于自动化生成文档', successRate: 99 },
            { id: 15, display_name: '文档生成 (Docs-Gen)', name: 'docs-gen', description: '用于自动化生成文档', successRate: 99 },
            { id: 16, display_name: '已禁用 (Disabled)', name: 'disabled', description: '此分组已被禁用', successRate: 2 }
        ];
        const responseData = { success: true, data: MOCK_DATA };*/
        
        try {

            const responseData = await apiFetchJson('/admin/keygroups');
            //const responseData = await response.json();
            // [修正] 根据您提供的API响应结构进行精准解析
            if (responseData && responseData.success && Array.isArray(responseData.data)) {
                // 如果响应成功且 'data' 字段是一个数组，则赋值
                this.state.groups = responseData.data;
            } else {
                // 如果API返回的结构不符合预期，记录错误并设置为空数组
                console.error("API response format is incorrect:", responseData);
                this.state.groups = [];
            }
            
            if (this.state.groups.length > 0 && !this.state.activeGroupId) {
               this.state.activeGroupId = this.state.groups[0].id;
            }
            
            this.renderGroupList();
            // [重大逻辑修改] updateDashboard 会触发 loadApiKeysForGroup
            if (this.state.activeGroupId) {
               this.updateDashboard();
            }
            this.updateAllHealthIndicators();
            
        } catch (error) {
            console.error("Failed to load or parse key groups:", error);
            this.state.groups = [];
            this.renderGroupList(); // 渲染空列表
            this.updateDashboard(); // 更新仪表盘为空状态
        } finally {
            this.state.isLoading = false;
        }
    }

    /**
     * Helper function to determine health indicator CSS classes based on success rate.
     * @param {number} rate - The success rate (0-100).
     * @returns {{ring: string, dot: string}} - The CSS classes for the ring and dot.
     */
    _getHealthIndicatorClasses(rate) {
        if (rate >= 50) return { ring: 'bg-green-500/20', dot: 'bg-green-500' };
        if (rate >= 30) return { ring: 'bg-yellow-500/20', dot: 'bg-yellow-500' };
        if (rate >= 10) return { ring: 'bg-orange-500/20', dot: 'bg-orange-500' };
        return { ring: 'bg-red-500/20', dot: 'bg-red-500' };
    }

    /**
     * Renders the list of group cards based on the current state.
     */
    renderGroupList() {
        if (!this.state.groups) return;
        // --- 桌面端列表渲染 (最终卡片布局) ---
        const desktopListHtml = this.state.groups.map(group => {
            const isActive = group.id === this.state.activeGroupId;
            const cardClass = isActive ? 'group-card-active' : 'group-card-inactive';
            const successRate = 100; // Placeholder
            const healthClasses = this._getHealthIndicatorClasses(successRate);
            
            // [核心修正] 同时生成两种类型的标签
            const channelTag = this._getChannelTypeTag(group.channel_type || 'Local');
            const customTags = this._getCustomTags(group.custom_tags); // 假设 group.custom_tags 是一个数组
            return `
                <div class="${cardClass}" data-group-id="${group.id}" data-success-rate="${successRate}">
                    <div class="flex items-center gap-x-3">
                        <div data-health-indicator class="health-indicator-ring ${healthClasses.ring}">
                            <div data-health-dot class="health-indicator-dot ${healthClasses.dot}"></div>
                        </div>
                        <div class="flex-grow">
                            <!-- [最终布局] 1. 名称 -> 2. 描述 -> 3. 标签 -->
                            <h3 class="font-semibold text-sm">${group.display_name}</h3>
                            <p class="card-sub-text my-1.5">${group.description || 'No description available'}</p>
                            <div class="flex items-center gap-x-1.5 flex-wrap">
                                ${channelTag}
                                ${customTags}
                            </div>
                        </div>
                    </div>
                </div>`;
        }).join('');
        if (this.elements.desktopGroupContainer) {
            this.elements.desktopGroupContainer.innerHTML = desktopListHtml;
            if (this.elements.addGroupBtnContainer) {
                this.elements.desktopGroupContainer.parentElement.appendChild(this.elements.addGroupBtnContainer);
            }
        }
        // --- 移动端列表渲染 (保持不变) ---
        const mobileListHtml = this.state.groups.map(group => {
            const isActive = group.id === this.state.activeGroupId;
            const cardClass = isActive ? 'group-card-active' : 'group-card-inactive';
            return `
                <div class="${cardClass}" data-group-id="${group.id}">
                    <h3 class="font-semibold text-sm">${group.display_name} (${group.name})</h3>
                </div>`;
        }).join('');
        if (this.elements.mobileGroupContainer) {
            this.elements.mobileGroupContainer.innerHTML = mobileListHtml;
        }
    }

    // [修正] 5. 事件处理器和UI更新函数，现在完全由 state 驱动
    handleGroupCardClick(event) {
        const clickedCard = event.target.closest('[data-group-id]');
        if (!clickedCard) return;
        const groupId = parseInt(clickedCard.dataset.groupId, 10);
        if (this.state.activeGroupId !== groupId) {
            this.state.activeGroupId = groupId;
            this.renderGroupList();
            this.updateDashboard(); // updateDashboard 现在会处理 API key 的加载
        }
        
        if (window.innerWidth < 1024) {
            this.elements.groupListCollapsible.classList.add('hidden');
        }
    }
    updateDashboard() {
        const activeGroup = this.state.groups.find(g => g.id === this.state.activeGroupId);
        
        if (activeGroup) {
            if (this.elements.dashboardTitle) {
                this.elements.dashboardTitle.textContent = `${activeGroup.display_name}`;
            }
            if (this.elements.mobileActiveGroupDisplay) {
                this.elements.mobileActiveGroupDisplay.innerHTML = `
                    <h3 class="font-semibold text-sm">${activeGroup.display_name}</h3>
                    <p class="card-sub-text">当前选择</p>`;
            }
            // [重大逻辑修改] 更新 Dashboard 时，加载对应的 API Keys
            this.loadApiKeysForGroup(this.state.activeGroupId);
        } else {
             if (this.elements.dashboardTitle) this.elements.dashboardTitle.textContent = 'No Group Selected';
             if (this.elements.mobileActiveGroupDisplay) this.elements.mobileActiveGroupDisplay.innerHTML = `<h3 class="font-semibold text-sm">请选择一个分组</h3>`;
             // 如果没有选中的分组，清空 API Key 列表
             this.state.apiKeys = [];
             this.renderApiKeyList();
        }
    }

   // =========================================================================
   // API Key Management (NEW LOGIC)
   // =========================================================================

   /**
     * Fetches and renders API keys for the specified group.
     * @param {number} groupId - The ID of the group to load keys for.
     */
   async loadApiKeysForGroup(groupId) {
       if (!groupId) return;

       this.state.isApiKeysLoading = true;
       this.renderApiKeyList(); // Render loading state

       try {
           const response = await apiFetch(`/admin/keygroups/${groupId}/keys`,{ noCache: true });
           const responseData = await response.json();

           if (responseData && responseData.success && Array.isArray(responseData.data)) {
               this.state.apiKeys = responseData.data;
           } else {
               console.error("API response for keys is incorrect:", responseData);
               this.state.apiKeys = [];
           }
       } catch (error) {
           console.error(`Failed to load API keys for group ${groupId}:`, error);
           this.state.apiKeys = [];
       } finally {
           this.state.isApiKeysLoading = false;
           this.renderApiKeyList(); // Render final state (data or empty message)
       }
   }

   /**
     * Renders the list of API keys based on the current state.
     */
   renderApiKeyList() {
       const container = this.elements.apiListContainer;
       if (!container) return;

       if (this.state.isApiKeysLoading) {
           container.innerHTML = '<div class="text-center p-8 text-gray-500">Loading API Keys...</div>';
           return;
       }

       if (this.state.apiKeys.length === 0) {
           container.innerHTML = '<div class="text-center p-8 text-gray-500">No API Keys in this group.</div>';
           return;
       }

       const listHtml = this.state.apiKeys.map(mapping => this.createApiKeyCardHtml(mapping)).join('');
       container.innerHTML = `
           <div class="grid grid-cols-1 md:grid-cols-2 gap-3">
               ${listHtml}
           </div>
       `;
       this.updateAllApiKeyStatusIndicators(); // Re-apply status colors after render
   }

   /**
     * [最终修正版]
     * Creates the HTML for a single API key card, adapting to the flat APIKeyDetails structure.
     * @param {object} item - The APIKeyDetails object from the API.
     * @returns {string} The HTML string for the card.
     */
   createApiKeyCardHtml(item) {
       // [核心数据结构变更] 不再有嵌套的 apiKey 对象，item 本身就是所有数据的集合
       if (!item || !item.api_key) return ''; // 安全检查

       // --- 数据准备 ---
       // 直接从 item 对象的最顶层访问所有字段
       const maskedKey = `${item.api_key.substring(0, 4)}......${item.api_key.substring(item.api_key.length - 4)}`;
       const status = item.status;
       const errorCount = item.consecutive_error_count;
       const keyId = item.id; // 这是 api_keys.id
       // 使用从后端补全的字段
       const mappingId = `${item.api_key_id}-${item.key_group_id}`; 

       // --- 行为挂钩 (保持不变) ---
       const setActiveAction = `data-action="set-status" data-new-status="ACTIVE"`;
       const revalidateAction = `data-action="revalidate"`;
       const disableAction = `data-action="set-status" data-new-status="DISABLED"`;
       const deleteAction = `data-action="delete-key"`;

       // --- 模板渲染 (保持不变) ---
       return `
           <div class="api-card group relative flex items-center gap-x-3 rounded-lg p-3 bg-white dark:bg-zinc-800/50 border border-zinc-200 dark:border-zinc-700/60" 
                data-status="${status}" 
                data-key-id="${keyId}" 
                data-mapping-id="${mappingId}">

               <input type="checkbox" class="api-key-checkbox h-4 w-4 rounded border-zinc-300 text-blue-600 focus:ring-blue-500 shrink-0">
               <span data-status-indicator class="w-2 h-2 rounded-full shrink-0"></span>

               <div class="flex-grow">
                   <p class="font-mono text-xs font-semibold">${maskedKey}</p>
                   <p class="text-xs text-zinc-400 mt-1">失败: ${errorCount} 次</p>
               </div>

               <div class="flex items-center gap-x-2 text-zinc-400 text-xs z-10">
                   <button class="hover:text-blue-500" data-action="toggle-visibility" title="查看完整Key"><i class="fas fa-eye"></i></button>
                   <button class="hover:text-blue-500" data-action="copy-key" title="复制Key"><i class="fas fa-copy"></i></button>
               </div>

               <!-- Hover Menu -->
               <div class="absolute right-14 top-1/2 -translate-y-1/2 flex items-center bg-zinc-200 dark:bg-zinc-700 rounded-full shadow-md opacity-0 group-hover:opacity-100 transition-opacity duration-200 z-20">
                   <button class="px-2 py-1 hover:text-green-500" ${setActiveAction} title="设为可用"><i class="fas fa-check-circle"></i></button>
                   <button class="px-2 py-1 hover:text-blue-500" ${revalidateAction} title="重新验证"><i class="fas fa-sync-alt"></i></button>
                   <button class="px-2 py-1 hover:text-yellow-500" ${disableAction} title="禁用"><i class="fas fa-ban"></i></button>
                   <button class="px-2 py-1 hover:text-red-500" ${deleteAction} title="从分组中移除"><i class="fas fa-trash-alt"></i></button>
               </div>
           </div>
       `;
   }


    /**
     * [升级] 辅助函数：解析、清理并校验用户输入的Keys。
     * @param {string} text - The raw text from the textarea.
     * @returns {Array<string>} - An array of unique, valid-formatted API keys.
     */
    _parseAndCleanKeys(text) {
        // 1. 替换常见分隔符为空格，然后按任意空白符分割
        const keys = text.replace(/[,;]/g, ' ').split(/[\s\n]+/);
        
        const cleanedKeys = keys
            .map(key => key.trim()) // 2. 去除首尾空格
            // [核心修正] 使用我们新的、更精准的格式校验函数进行过滤
            .filter(key => isValidApiKeyFormat(key));
        
        // 3. 使用 Set 去重
        return [...new Set(cleanedKeys)];
    }


    // [防禦性診斷版] handleAddApiKeysSubmit
    async handleAddApiKeysSubmit(event) {
        event.preventDefault();
        console.log("handleAddApiKeysSubmit triggered."); // 診斷日誌1
        if (!this.state.activeGroupId) {
            console.error("No active group ID. Aborting.");
            return;
        }
        if (this.taskPollInterval) {
            clearInterval(this.taskPollInterval);
            this.taskPollInterval = null;
        }
        // --- DOM 元素獲取與健壯性檢查 ---
        const textarea = document.getElementById('api-add-textarea');
        const importButton = document.getElementById('add-api-import-btn');
        const inputView = document.getElementById('add-api-input-view');
        const resultView = document.getElementById('add-api-result-view');
        const title = document.getElementById('add-api-modal-title');
        const validateCheckbox = document.getElementById('validate-on-import-checkbox');
        // 關鍵的防禦性檢查
        if (!textarea || !importButton || !inputView || !resultView || !title || !validateCheckbox) {
            console.error("One or more modal elements are missing from the DOM!");
            // 打印出哪個元素是null，幫助定位問題
            console.table({ textarea, importButton, inputView, resultView, title, validateCheckbox });
            alert("模態框內部組件不完整，無法執行導入。請檢查瀏覽器控制台。");
            return;
        }
        // --- 檢查通過，繼續執行 ---
        console.log("All modal elements found. Proceeding with logic."); // 診斷日誌2
        const shouldValidate = validateCheckbox.checked;
        const cleanedKeys = this._parseAndCleanKeys(textarea.value);
        
        if (cleanedKeys.length === 0) {
            alert('沒有檢測到有效的API Keys。');
            return;
        }
        importButton.disabled = true;
        importButton.innerHTML = `<i class="fas fa-spinner fa-spin mr-2"></i>正在启动...`;
        textarea.disabled = true;
        try {
            console.log("Attempting to call apiKeyManager.addKeysToGroup..."); // 診斷日誌3
            const response = await apiKeyManager.addKeysToGroup(this.state.activeGroupId, cleanedKeys.join('\n'), shouldValidate);
            console.log("API call response received:", response); // 診斷日誌4
            if (response && response.success && response.data && response.data.id) {
                const task = response.data;
                title.textContent = '正在批量添加...';
                inputView.classList.add('hidden');
                resultView.classList.remove('hidden');
                this._pollTaskStatus(task.id, resultView);
            } else {
                // 如果API調用成功但業務失敗，也拋出錯誤
                throw new Error(response.message || '啟動導入任務失敗，後端未返回任務ID。');
            }
        } catch (error) {
            console.error("Error catched in handleAddApiKeysSubmit:", error); // 診斷日誌5
            if (this.taskPollInterval) {
                clearInterval(this.taskPollInterval);
                this.taskPollInterval = null;
            }
            
            // 這裡的錯誤信息處理保持不變
            const errorMessage = error.data && error.data.Message 
                ? error.data.Message 
                : (error.message || '启动任务失败，请检查网络或联系管理员。');
            title.textContent = '操作失败';
            inputView.classList.add('hidden');
            resultView.classList.remove('hidden');
            resultView.innerHTML = `<div class="p-4 bg-red-50 border border-red-200 rounded-md">
                                        <p class="text-red-700 font-semibold">错误</p>
                                        <p class="text-red-600 text-sm mt-1">${errorMessage}</p>
                                    </div>`;
            
            importButton.style.display = 'none';
        }
    }
/*   
    // [新增] 核心逻辑：处理“导入”按钮点击事件
    async handleAddApiKeysSubmit(event) {
        event.preventDefault();
        if (!this.state.activeGroupId) { return; }
        // [核心修正] 在所有操作開始之前，立即斬斷任何來自過去的定時器。
        // 這是解決競態條件、防止“幽靈回調”覆蓋UI的關鍵。
        if (this.taskPollInterval) {
            clearInterval(this.taskPollInterval);
            this.taskPollInterval = null;
        }
        const textarea = document.getElementById('api-add-textarea');
        const importButton = document.getElementById('add-api-import-btn');
        const inputView = document.getElementById('add-api-input-view');
        const resultView = document.getElementById('add-api-result-view');
        const title = document.getElementById('add-api-modal-title');
        const validateCheckbox = document.getElementById('validate-on-import-checkbox');
        const shouldValidate = validateCheckbox.checked;
        const cleanedKeys = this._parseAndCleanKeys(textarea.value);
        if (cleanedKeys.length === 0) {
            alert('沒有檢測到有效的API Keys。');
            return;
        }
        importButton.disabled = true;
        importButton.innerHTML = `<i class="fas fa-spinner fa-spin mr-2"></i>正在启动...`;
        textarea.disabled = true;
        try {
            const response = await apiKeyManager.addKeysToGroup(this.state.activeGroupId, cleanedKeys.join('\n'), shouldValidate);
            if (response && response.success && response.data && response.data.id) {
                const task = response.data;
                title.textContent = '正在批量添加...';
                inputView.classList.add('hidden');
                resultView.classList.remove('hidden');
                this._pollTaskStatus(task.id, resultView);
            } else {
                throw new Error(response.message || '启动导入任务失败。');
            }
        } catch (error) {
            // catch 塊中的 clearInterval 仍然保留，作為雙重保險。
            if (this.taskPollInterval) {
                clearInterval(this.taskPollInterval);
                this.taskPollInterval = null;
            }
            const errorMessage = error.data && error.data.Message 
                ? error.data.Message 
                : '启动任务失败，请检查网络或联系管理员。';
            if(title) title.textContent = '操作失败';
            if (inputView) inputView.classList.add('hidden');
            if (resultView) {
                resultView.classList.remove('hidden');
                resultView.innerHTML = `<div class="p-4 bg-red-50 border border-red-200 rounded-md">
                                            <p class="text-red-700 font-semibold">错误</p>
                                            <p class="text-red-600 text-sm mt-1">${errorMessage}</p>
                                        </div>`;
            }
            
            if (importButton) importButton.style.display = 'none';
        }
    }

*/
    // [新增] 辅助函数：重置“添加API”模态框到初始状态
     // 在重置模態框時，強力清除任何可能存在的輪詢定時器
    _resetAddApiModal() {
        // [核心修正] 這是解決“幽靈定時器”問題的關鍵
        if (this.taskPollInterval) {
            clearInterval(this.taskPollInterval);
            this.taskPollInterval = null; // 徹底清除引用
        }
        const title = document.getElementById('add-api-modal-title');
        const inputView = document.getElementById('add-api-input-view');
        const resultView = document.getElementById('add-api-result-view');
        const textarea = document.getElementById('api-add-textarea');
        const importBtn = document.getElementById('add-api-import-btn');
        if (title) title.textContent = '批量添加 API Keys';
        if (inputView) inputView.classList.remove('hidden');
        if (resultView) {
            resultView.classList.add('hidden');
            resultView.innerHTML = ''; 
        }
        if (textarea) {
            textarea.value = '';
            textarea.disabled = false;
        }
        
        // 恢復導入按鈕的狀態和可見性
        if (importBtn) {
            importBtn.disabled = false;
            importBtn.textContent = '导入';
            importBtn.style.display = ''; // 移除 'display: none'
        }
    }

    // [数据UI双修版]
    _pollTaskStatus(taskId, resultContainer) {
        if (this.taskPollInterval) {
            clearInterval(this.taskPollInterval);
        }
        this.taskPollInterval = setInterval(async () => {
            try {
                // apiKeyManager.getTaskStatus(taskId) 返回的是完整的API响应体 { success: true, data: {...} }
                const response = await apiKeyManager.getTaskStatus(taskId);
                // [核心修正] 我们需要的是 response.data 里的任务对象，而不是整个 response！
                const task = response.data; 
                if (!task) {
                    // 如果 task 不存在，说明 API 响应格式不對，立即停止以防错误
                    console.error("Task data is missing in the API response.", response);
                    clearInterval(this.taskPollInterval);
                    this.taskPollInterval = null;
                    // 这里可以显示一个更通用的错误信息
                    resultContainer.innerHTML = `<div class="p-4 text-red-700 bg-red-100">无法解析任务数据，请检查API响应。</div>`;
                    return;
                }
                const progressText = `正在处理: ${task.processed} / ${task.total}`;
                if (task.is_running) {
                    resultContainer.innerHTML = `<div class="text-center py-4"><i class="fas fa-spinner fa-spin fa-2x text-gray-400 mb-4"></i><p class="text-sm text-gray-600">${progressText}</p></div>`;
                } else {
                    clearInterval(this.taskPollInterval);
                    this.taskPollInterval = null;
                    const importButton = document.getElementById('add-api-import-btn');
                    if (importButton) {
                        importButton.style.display = 'none';
                    }
                    let resultHtml = ``;
                    if (task.error) {
                        resultHtml = `<h3 class="font-semibold text-xl text-red-500 text-center">导入失败</h3><p class="mt-2 text-sm text-center text-gray-600">${task.error}</p>`;
                    } else {
                        const result = task.result || {};
                        resultHtml = `
                            <div class="text-center">
                                <h3 class="font-semibold text-xl text-green-600">导入完成</h3>
                                <ul class="mt-4 space-y-2 text-gray-700">
                                    <li class="flex justify-between items-center text-sm"><span>新创建并链接:</span><span class="font-mono bg-gray-100 px-2 py-1 rounded">${result.newly_created_count || 0}</span></li>
                                    <li class="flex justify-between items-center text-sm"><span>已存在并链接:</span><span class="font-mono bg-gray-100 px-2 py-1 rounded">${result.already_existed_count || 0}</span></li>
                                    <li class="flex justify-between items-center text-sm font-bold"><span>总计链接到分组:</span><span class="font-mono bg-green-100 text-green-800 px-2 py-1 rounded">${result.linked_to_group_count || 0}</span></li>
                                </ul>
                            </div>`;
                        this.loadApiKeysForGroup(this.state.activeGroupId);
                    }
                    resultContainer.innerHTML = resultHtml;
                }
            } catch (error) {
                clearInterval(this.taskPollInterval);
                this.taskPollInterval = null;
                
                // UI修正：在轮询失败时也应该隐藏“导入”按钮，只留关闭
                const importButton = document.getElementById('add-api-import-btn');
                if (importButton) {
                    importButton.style.display = 'none';
                }

                if(resultContainer) {
                    resultContainer.innerHTML = `<div class="p-4 bg-red-50 border border-red-200 rounded-md">
                                                    <p class="text-red-700 font-semibold">轮询任务状态失败</p>
                                                    <p class="text-red-600 text-sm mt-1">${error.message}</p>
                                                </div>`;
                }
            }
        }, 2000);
    }


    // --- [新增] 统一的模态框初始化和关闭辅助函数 ---
    /**
     * Helper to setup modal open triggers.
     * @param {string} modalId - The ID of the modal to open.
     * @param {string} selector - The CSS selector for the trigger elements.
     * @param {function} [onOpen=()=>{}] - Callback to execute before showing the modal.
     */
    _initModalTrigger(modalId, selector, onOpen = () => {}) {
        document.querySelectorAll(selector).forEach(trigger => {
            trigger.addEventListener('click', (event) => {
                onOpen(event, modalId); //
                this.modalManager.show(modalId);
            });
        });
    }
    /**
     * Helper to setup close triggers for a list of modals.
     * @param {string[]} modalIds - An array of modal IDs.
     */
    _initGlobalModalClosers(modalIds) {
        modalIds.forEach(modalId => {
            const modal = document.getElementById(modalId);
            if (!modal) return;
            
            // Close buttons with data-modal-close attribute
            modal.querySelectorAll(`[data-modal-close="${modalId}"]`).forEach(trigger => {
                trigger.addEventListener('click', () => {
                     // 特殊处理 'add-api-modal' 的关闭，确保重置
                    if (modalId === 'add-api-modal') {
                        this._resetAddApiModal();
                    }
                    this.modalManager.hide(modalId);
                });
            });
            // Clicking on the overlay (the modal element itself)
            modal.addEventListener('click', (event) => {
                if (event.target === modal) {
                    if (modalId === 'add-api-modal') {
                        this._resetAddApiModal();
                    }
                    this.modalManager.hide(modalId);
                }
            });
        });
    }
    /**
     * Initializes all custom select components on the page.
     */
    initCustomSelects() {
        const customSelects = document.querySelectorAll('.custom-select');
        customSelects.forEach(select => new CustomSelect(select));
    }

        /**
     * Initializes all batch action dropdowns on the page.
     * This version uses class selectors to support multiple dropdown instances
     * for responsive layouts (e.g., one for mobile, one for desktop).
     */
    _initBatchActions() {
        // 关键改动：使用 querySelectorAll 和 class 来获取所有批量操作的容器
        const dropdownContainers = document.querySelectorAll('.batch-action-dropdown');
        if (dropdownContainers.length === 0) return;
        // 为页面上找到的每一个批量操作组件都绑定事件
        dropdownContainers.forEach(container => {
            const btn = container.querySelector('.batch-action-btn');
            const panel = container.querySelector('.batch-action-panel');
            if (!btn || !panel) return;
            btn.addEventListener('click', (event) => {
                event.stopPropagation(); // 阻止事件冒泡到 document
                // 优化：在打开当前面板前，关闭所有其他可能已打开的面板
                document.querySelectorAll('.batch-action-panel').forEach(p => {
                    if (p !== panel) {
                        p.classList.add('hidden');
                    }
                });
                
                // 切换当前点击按钮对应的面板
                panel.classList.toggle('hidden');
            });
        });
        // 全局点击监听器：现在它会关闭所有打开的面板，无论哪个被打开
        document.addEventListener('click', () => {
            document.querySelectorAll('.batch-action-panel').forEach(panel => {
                panel.classList.add('hidden');
            });
        });
    }


    // [新增] 负责与后端API通信的新方法
    /**
     * Sends the new group UI order to the backend API.
     * @param {Array<object>} orderData - An array of objects, e.g., [{id: 1, order: 0}, {id: 2, order: 1}]
     */
    async saveGroupOrder(orderData) {
        console.log('Debounced save triggered. Sending UI order to API:', orderData);
        try {
            // 调用您已验证成功的API端点
            const response = await apiFetch('/admin/keygroups/order', {
                method: 'PUT',
                body: JSON.stringify(orderData),
                noCache: true
            });
            const result = await response.json(); 
            if (!result.success) {
                // 如果后端返回操作失败，抛出错误
                throw new Error(result.message || 'Failed to save UI order on the server.');
            }
            console.log('UI order saved successfully.');
            // (可选) 在这里可以显示一个短暂的 "保存成功" 的提示消息 (Toast/Snackbar)
        } catch (error) {
            console.error('Failed to save new group UI order:', error);
            // [重要] 如果API调用失败，应该重新加载一次分组列表，
            // 以便UI回滚到数据库中存储的、未经修改的正确顺序。
            this.loadKeyGroups(); 
        }
    }

    /**
     * Initializes drag-and-drop functionality for the group list.
     */
    initDragAndDrop() {
        if (typeof Sortable === 'undefined') {
            console.error('SortableJS is not loaded.');
            return;
        }
        
        const container = this.elements.desktopGroupContainer; 
        if (!container) return;

        new Sortable(container, {
            animation: 150,
            ghostClass: 'sortable-ghost',
            dragClass: 'sortable-drag',
            filter: '#add-group-btn-container',
            onEnd: (evt) => {
                // [核心修正] 使用属性选择器，这是最稳健的方式
                const groupCards = Array.from(container.querySelectorAll('[data-group-id]'));

                const orderedState = groupCards.map(card => {
                    // [核心修正] 读取正确的 dataset 属性 (data-group-id -> dataset.groupId)
                    const cardId = parseInt(card.dataset.groupId, 10);
                    return this.state.groups.find(group => group.id === cardId);
                }).filter(Boolean);
                
                if (orderedState.length !== this.state.groups.length) {
                    console.error("Drag-and-drop failed: Could not map all DOM elements to state. Aborting.");
                    return; 
                }

                // 更新正确的状态数组
                this.state.groups = orderedState;
                
                const payload = this.state.groups.map((group, index) => ({
                    id: group.id,
                    order: index
                }));

                this.debouncedSaveOrder(payload);
            },
        });
    }




    /**
     * Opens the modal for creating or editing a key group.
     * @param {object|null} groupData - If provided, fills the modal with data for editing.
     */
    openGroupModal(groupData = null) {
        if (groupData && typeof groupData.name !== 'undefined') { // Check if it's actual data, not an event
            this.elements.modalTitle.textContent = '编辑 Key Group';
            // TODO: Populate form fields with groupData
        } else {
            this.elements.modalTitle.textContent = '创建新的 Key Group';
            // TODO: Clear form fields
        }
    }

 
    /**
     * Handles actions from the dashboard controls (clone, edit, delete).
     * @param {Event} event - The click event.
     */
    handleDashboardAction(event) {
        const button = event.target.closest('button');
        if (!button) return;

        if (button.innerHTML.includes('fa-clone')) {
            console.log('Clone action triggered for group:', this.elements.dashboardTitle.textContent);
        } else if (button.innerHTML.includes('fa-cog')) {
            console.log('Edit action triggered for group:', this.elements.dashboardTitle.textContent);
            this.openGroupModal({ name: this.elements.dashboardTitle.textContent, mock: true });
        } else if (button.innerHTML.includes('fa-sliders-h')) {
            this.openRequestSettingsModal();
        } else if (button.innerHTML.includes('fa-trash')) {
            console.log('Delete action triggered for group:', this.elements.dashboardTitle.textContent);
        }
    }

   /**
    * Handles all actions within an API key card using a data-action dispatch pattern.
    * @param {Event} event - The click event.
    */
   async handleApiKeyCardAction(event) {
       const button = event.target.closest('button[data-action]');
       if (!button) return;

       const card = button.closest('.api-card');
       if (!card) return;

       const keyId = parseInt(card.dataset.keyId, 10);
       const groupId = this.state.activeGroupId;
       const action = button.dataset.action;
       
       // 从 state 中查找完整的 API Key 信息，用于复制和显示
       const mapping = this.state.apiKeys.find(m => m.APIKey && m.APIKey.id === keyId);
       const fullApiKey = mapping ? mapping.APIKey.api_key : null;

       switch (action) {
           case 'toggle-visibility': {
               const keyElement = card.querySelector('.font-mono');
               const icon = button.querySelector('i');
               if (!keyElement || !fullApiKey) break;

               if (icon.classList.contains('fa-eye')) { // Currently showing masked
                   keyElement.textContent = fullApiKey;
                   icon.classList.replace('fa-eye', 'fa-eye-slash');
                   button.title = "隐藏完整Key";
               } else { // Currently showing full key
                   const maskedKey = `${fullApiKey.substring(0, 4)}...${fullApiKey.substring(fullApiKey.length - 4)}`;
                   keyElement.textContent = maskedKey;
                   icon.classList.replace('fa-eye-slash', 'fa-eye');
                   button.title = "查看完整Key";
               }
               break;
           }

           case 'copy-key': {
               if (!fullApiKey) {
                   console.warn("Could not find full API key to copy.");
                   // TODO: Show user a notification
                   break;
               }
               navigator.clipboard.writeText(fullApiKey).then(() => {
                   // TODO: Show a success toast/tooltip, e.g., "Copied!"
                   console.log(`API Key ${keyId} copied to clipboard.`);
               }).catch(err => {
                   console.error('Failed to copy API key: ', err);
               });
               break;
           }

           case 'set-status': {
               const newStatus = button.dataset.newStatus;
               if (!newStatus) break;
               
               console.log(`Setting status of key ${keyId} in group ${groupId} to ${newStatus}`);
               try {
                   const response = await apiFetch(`/admin/groups/${groupId}/keys/${keyId}`, {
                       method: 'PUT',
                       body: JSON.stringify({ status: newStatus })
                   });
                   const result = await response.json();
                   if (result.success) {
                       // 成功后，重新加载列表以显示最新状态
                       this.loadApiKeysForGroup(groupId); 
                   } else {
                       throw new Error(result.message);
                   }
               } catch (error) {
                   console.error(`Failed to set status for key ${keyId}:`, error);
                   // TODO: Show error notification
               }
               break;
           }

           case 'delete-key': {
               // 推荐在实际操作前增加一个确认对话框
               if (!confirm(`确定要从这个分组中移除 API Key (ID: ${keyId}) 吗？`)) {
                   return;
               }
               
               console.log(`Deleting key ${keyId} from group ${groupId}`);
               try {
                   const response = await apiFetch(`/admin/keygroups/${groupId}/apikeys/bulk`, {
                       method: 'DELETE',
                       body: JSON.stringify({ api_key_ids: [keyId] })
                   });
                   const result = await response.json();
                   if (result.success) {
                        this.loadApiKeysForGroup(groupId);
                   } else {
                       throw new Error(result.message);
                   }
               } catch (error) {
                   console.error(`Failed to delete key ${keyId}:`, error);
                   // TODO: Show error notification
               }
               break;
           }
               
           case 'revalidate': {
               // [后端待办] 此功能需要后端提供一个专门的API端点
               console.log(`[TODO] Revalidating key ${keyId} in group ${groupId}. Needs backend endpoint.`);
               alert("重新验证功能正在开发中。");
               
               /* 理想的调用方式:
               try {
                   const response = await apiFetch(`/admin/groups/${groupId}/keys/${keyId}/revalidate`, { method: 'POST' });
                   // ... 处理异步任务启动的逻辑 ...
               } catch (error) {
                   console.error(`Failed to start revalidation for key ${keyId}:`, error);
               }
               */
               break;
           }
       }
   }


    /**
     * Helper function to generate a styled HTML tag for the channel type.
     * @param {string} type - The channel type string (e.g., 'OpenAI', 'Azure').
     * @returns {string} - The generated HTML span element.
     */
    _getChannelTypeTag(type) {
        if (!type) return ''; // 如果没有类型，则返回空字符串
        const styles = {
            'OpenAI': 'bg-green-100 text-green-800 dark:bg-green-900 dark:text-green-300',
            'Azure': 'bg-blue-100 text-blue-800 dark:bg-blue-900 dark:text-blue-300',
            'Claude': 'bg-orange-100 text-orange-800 dark:bg-orange-900 dark:text-orange-300',
            'Gemini': 'bg-sky-100 text-sky-800 dark:bg-sky-900 dark:text-sky-300',
            'Local': 'bg-gray-100 text-gray-800 dark:bg-gray-700 dark:text-gray-300'
        };
        const baseClass = 'inline-block text-xs font-medium px-2 py-0.5 rounded-md';
        const tagClass = styles[type] || styles['Local']; // 如果类型未知，则使用默认样式
        return `<span class="${baseClass} ${tagClass}">${type}</span>`;
    }


    /**
     * Generates styled HTML for custom tags with deterministically assigned colors.
     * @param {string[]} tags - An array of custom tag strings.
     * @returns {string} - The generated HTML for all custom tags.
     */
    _getCustomTags(tags) {
        if (!tags || !Array.isArray(tags) || tags.length === 0) {
            return '';
        }
        // 预设的彩色背景调色板 (Tailwind classes)
        const colorPalette = [
            'bg-pink-100 text-pink-800 dark:bg-pink-900 dark:text-pink-300',
            'bg-purple-100 text-purple-800 dark:bg-purple-900 dark:text-purple-300',
            'bg-indigo-100 text-indigo-800 dark:bg-indigo-900 dark:text-indigo-300',
            'bg-cyan-100 text-cyan-800 dark:bg-cyan-900 dark:text-cyan-300',
            'bg-teal-100 text-teal-800 dark:bg-teal-900 dark:text-teal-300',
            'bg-lime-100 text-lime-800 dark:bg-lime-900 dark:text-lime-300',
        ];
        const baseClass = 'inline-block text-xs font-medium px-2 py-0.5 rounded-md';
        return tags.map(tag => {
            // 使用一个简单的确定性哈希算法，确保同一个标签名总能获得同一种颜色
            let hash = 0;
            for (let i = 0; i < tag.length; i++) {
                hash += tag.charCodeAt(i);
            }
            const colorClass = colorPalette[hash % colorPalette.length];
            return `<span class="${baseClass} ${colorClass}">${tag}</span>`;
        }).join('');
    }


    _updateHealthIndicator(cardElement) {
        const rate = parseFloat(cardElement.dataset.successRate);
        if (isNaN(rate)) return;

        const indicator = cardElement.querySelector('[data-health-indicator]');
        const dot = cardElement.querySelector('[data-health-dot]');
        if (!indicator || !dot) return;

        const colors = {
            green: ['bg-green-500/20', 'bg-green-500'],
            yellow: ['bg-yellow-500/20', 'bg-yellow-500'],
            orange: ['bg-orange-500/20', 'bg-orange-500'],
            red: ['bg-red-500/20', 'bg-red-500'],
        };

        Object.values(colors).forEach(([bgClass, dotClass]) => {
            indicator.classList.remove(bgClass);
            dot.classList.remove(dotClass);
        });

        let newColor;
        if (rate >= 50) newColor = colors.green;
        else if (rate >= 25) newColor = colors.yellow;
        else if (rate >= 10) newColor = colors.orange;
        else newColor = colors.red;
        
        indicator.classList.add(newColor[0]);
        dot.classList.add(newColor[1]);
    }

    updateAllHealthIndicators() {
        if (!this.elements.groupListCollapsible) return;
        const allCards = this.elements.groupListCollapsible.querySelectorAll('[data-success-rate]');
        allCards.forEach(card => this._updateHealthIndicator(card));
    }

    _updateApiKeyStatusIndicator(cardElement) {
        const status = cardElement.dataset.status;
        if (!status) return;

        const indicator = cardElement.querySelector('[data-status-indicator]');
        if (!indicator) return;

        const statusColors = {
            'ACTIVE': 'bg-green-500',
            'PENDING': 'bg-gray-400',
            'COOLDOWN': 'bg-yellow-500',
            'DISABLED': 'bg-orange-500',
            'BANNED': 'bg-red-500',
        };

        // Remove any existing color classes
        Object.values(statusColors).forEach(colorClass => {
            indicator.classList.remove(colorClass);
        });

        // Add the new color class
        if (statusColors[status]) {
            indicator.classList.add(statusColors[status]);
        }
    }

    updateAllApiKeyStatusIndicators() {
        const allCards = this.elements.apiListContainer.querySelectorAll('.api-card[data-status]');
        allCards.forEach(card => this._updateApiKeyStatusIndicator(card));
    }

    initTooltips() {
        const tooltipIcons = document.querySelectorAll('.tooltip-icon');
        tooltipIcons.forEach(icon => {
            icon.addEventListener('mouseenter', (e) => this.showTooltip(e));
            icon.addEventListener('mouseleave', () => this.hideTooltip());
        });
    }

    showTooltip(e) {
        this.hideTooltip();

        const target = e.currentTarget;
        const text = target.dataset.tooltipText;
        if (!text) return;

        const tooltip = document.createElement('div');
        tooltip.className = 'global-tooltip';
        tooltip.textContent = text;
        document.body.appendChild(tooltip);
        this.activeTooltip = tooltip;

        const targetRect = target.getBoundingClientRect();
        const tooltipRect = tooltip.getBoundingClientRect();

        let top = targetRect.top - tooltipRect.height - 8;
        let left = targetRect.left + (targetRect.width / 2) - (tooltipRect.width / 2);

        if (top < 0) top = targetRect.bottom + 8;
        if (left < 0) left = 8;
        if (left + tooltipRect.width > window.innerWidth) {
            left = window.innerWidth - tooltipRect.width - 8;
        }

        tooltip.style.top = `${top}px`;
        tooltip.style.left = `${left}px`;
    }

    hideTooltip() {
        if (this.activeTooltip) {
            this.activeTooltip.remove();
            this.activeTooltip = null;
        }
    }

    // [集成] 打开高级设置模态框并加载数据
    // =========================================================================
    // [完成] RequestSettingsModal 的方法被完整地迁移到这里
    // =========================================================================
    
    async openRequestSettingsModal() {
        if (!this.state.activeGroupId) {
            console.warn("No active group selected to open request settings.");
            return;
        }
        this._populateRequestSettingsForm({}); // Currently populating with empty data
        this.modalManager.show('request-settings-modal');
        // 后续将取消此处的注释以从后端加载数据
        /*
        try {
            const response = await apiFetch(`/admin/keygroups/${this.state.activeGroupId}/request-config`);
            const result = await response.json();
            
            if (result.success) {
                this._populateRequestSettingsForm(result.data);
            } else {
                console.warn(`Failed to fetch request settings: ${result.message}. Creating new config.`);
                this._populateRequestSettingsForm({});
            }
            this.modalManager.show('request-settings-modal');
        } catch (error) {
            console.error("Error fetching request settings:", error);
            this._populateRequestSettingsForm({});
            this.modalManager.show('request-settings-modal');
        }
        */
    }
    
    async handleSaveRequestSettings() {
        if (!this.state.activeGroupId) {
            console.error("No active group selected to save settings for.");
            return;
        }
        const data = this._collectRequestSettingsFormData();
        const saveBtn = this.elements.requestSettings.saveBtn;
        
        try {
            if (saveBtn) {
                saveBtn.disabled = true;
                saveBtn.textContent = 'Saving...';
            }
            
            console.log(`[SIMULATED] Saving request settings for group ${this.state.activeGroupId}:`, data);
            
            // 后续将取消此处的注释以向后端保存数据
            /*
            const response = await apiFetch(`/admin/keygroups/${this.state.activeGroupId}/request-config`, {
                method: 'PUT',
                body: JSON.stringify(data)
            });
            const result = await response.json();
            if (!result.success) throw new Error(result.message);
            */
            this.modalManager.hide('request-settings-modal');
            
        } catch (error) {
            console.error("Failed to save request settings:", error);
            // 可以在模态框内显示错误信息给用户
            alert(`保存失败: ${error.message}`);
        } finally {
            if (saveBtn) {
                saveBtn.disabled = false;
                saveBtn.textContent = 'Save Changes';
            }
        }
    }
    // --- 所有来自旧 RequestSettingsModal 的辅助方法 ---
    _populateRequestSettingsForm(data = {}) {
        const rsElements = this.elements.requestSettings;
        
        // Simple Toggles & Inputs
        const isStreamOptimizerEnabled = !!data.stream_optimizer_enabled;
        this._setToggle(rsElements.streamOptimizerEnabled, isStreamOptimizerEnabled);
        this._toggleStreamingPanel(isStreamOptimizerEnabled); 
        this._setValue(rsElements.streamMinDelay, data.stream_min_delay);
        this._setValue(rsElements.streamMaxDelay, data.stream_max_delay);
        this._setValue(rsElements.streamShortTextThresh, data.stream_short_text_threshold);
        this._setValue(rsElements.streamLongTextThresh, data.stream_long_text_threshold);
        this._setValue(rsElements.streamChunkSize, data.stream_chunk_size);
        this._setToggle(rsElements.fakeStreamEnabled, data.fake_stream_enabled);
        this._setValue(rsElements.fakeStreamInterval, data.fake_stream_empty_data_interval_seconds);
        this._setToggle(rsElements.toolsCodeExecutionEnabled, data.tools_code_execution_enabled);
        this._setToggle(rsElements.urlContextEnabled, data.url_context_enabled);
        this._setToggle(rsElements.showSearchLink, data.show_search_link);
        this._setToggle(rsElements.showThinkingProcess, data.show_thinking_process);
        this._setValue(rsElements.configOverrides, data.config_overrides);
        // Dynamic Fields
        this._populateKVItems(rsElements.customHeadersContainer, data.custom_headers, this.addCustomHeaderItem.bind(this));
        
        // 由于 safety_settings 的 `add` 方法有硬编码列表，最好在调用 populate 之前确保容器是空的
        this._clearContainer(rsElements.safetySettingsContainer);
        if (data.safety_settings && typeof data.safety_settings === 'object') {
             for (const [key, value] of Object.entries(data.safety_settings)) {
                this.addSafetySettingItem(key, value);
            }
        }
    }
    _collectRequestSettingsFormData() {
        const rsElements = this.elements.requestSettings;
        return {
            stream_optimizer_enabled: rsElements.streamOptimizerEnabled.checked,
            stream_min_delay: parseInt(rsElements.streamMinDelay.value, 10),
            stream_max_delay: parseInt(rsElements.streamMaxDelay.value, 10),
            stream_short_text_threshold: parseInt(rsElements.streamShortTextThresh.value, 10),
            stream_long_text_threshold: parseInt(rsElements.streamLongTextThresh.value, 10),
            stream_chunk_size: parseInt(rsElements.streamChunkSize.value, 10),
            fake_stream_enabled: rsElements.fakeStreamEnabled.checked,
            fake_stream_empty_data_interval_seconds: parseInt(rsElements.fakeStreamInterval.value, 10),
            tools_code_execution_enabled: rsElements.toolsCodeExecutionEnabled.checked,
            url_context_enabled: rsElements.urlContextEnabled.checked,
            show_search_link: rsElements.showSearchLink.checked,
            show_thinking_process: rsElements.showThinkingProcess.checked,
            config_overrides: rsElements.configOverrides.value,
            custom_headers: this._collectKVItems(rsElements.customHeadersContainer, 'text', 'text'),
            safety_settings: this._collectSafetySettings(rsElements.safetySettingsContainer),
            // TODO: Collect from Tag Inputs
            // image_models: this.imageModelsInput.getValues(),
        };
    }
    _toggleStreamingPanel(is_enabled) {
        const panel = this.elements.requestSettings.streamingSettingsPanel;
        if (panel) {
            if (is_enabled) {
                panel.classList.remove('hidden');
            } else {
                panel.classList.add('hidden');
            }
        }
    }
    addCustomHeaderItem(key = '', value = '') {
        const container = this.elements.requestSettings.customHeadersContainer;
        if (!container) return;
        const item = document.createElement('div');
        item.className = 'dynamic-kv-item';
        item.innerHTML = `
            <input type="text" class="modal-input text-xs" name="custom_header_key" placeholder="Header Name" value="${key}">
            <input type="text" class="modal-input text-xs" name="custom_header_value" placeholder="Header Value" value="${value}">
            <button type="button" class="remove-btn text-zinc-400 hover:text-red-500 transition-colors"><i class="fas fa-trash-alt"></i></button>
        `;
        container.appendChild(item);
    }
    addSafetySettingItem(category = '', threshold = '') {
        const container = this.elements.requestSettings.safetySettingsContainer;
        if (!container) return;
        const item = document.createElement('div');
        item.className = 'safety-setting-item flex items-center gap-x-2';
        const harmCategories = ["HARM_CATEGORY_HARASSMENT", "HARM_CATEGORY_HATE_SPEECH", "HARM_CATEGORY_SEXUALLY_EXPLICIT", "HARM_CATEGORY_DANGEROUS_CONTENT", "HARM_CATEGORY_CIVIC_INTEGRITY"];
        const harmThresholds = ["BLOCK_OFF", "BLOCK_NONE", "BLOCK_LOW_AND_ABOVE", "BLOCK_MEDIUM_AND_ABOVE", "BLOCK_ONLY_HIGH"];
        
        const categorySelect = document.createElement('select');
        categorySelect.className = 'modal-input flex-grow';
        harmCategories.forEach(cat => {
            const option = new Option(cat.replace('HARM_CATEGORY_', ''), cat);
            if (cat === category) option.selected = true;
            categorySelect.add(option);
        });
        
        const thresholdSelect = document.createElement('select');
        thresholdSelect.className = 'modal-input w-48';
        harmThresholds.forEach(thr => {
            const option = new Option(thr.replace('BLOCK_', '').replace('_AND_ABOVE', '+'), thr);
            if (thr === threshold) option.selected = true;
            thresholdSelect.add(option);
        });
        
        const removeButton = document.createElement('button');
        removeButton.type = 'button';
        removeButton.className = 'remove-btn text-zinc-400 hover:text-red-500 transition-colors';
        removeButton.innerHTML = `<i class="fas fa-trash-alt"></i>`;
        
        item.appendChild(categorySelect);
        item.appendChild(thresholdSelect);
        item.appendChild(removeButton);
        container.appendChild(item);
    }
    _setValue(element, value) {
        if (element && value !== null && value !== undefined) {
            element.value = value;
        }
    }
    _setToggle(element, value) {
        if (element) {
            element.checked = !!value;
        }
    }
    _clearContainer(container) {
        if (container) {
            while (container.firstChild) {
                container.removeChild(container.firstChild);
            }
        }
    }
    _populateKVItems(container, items, addItemFn) {
        this._clearContainer(container);
        if (items && typeof items === 'object') {
            for (const [key, value] of Object.entries(items)) {
                addItemFn(key, value);
            }
        }
    }
    _collectKVItems(container, keyName, valueName) {
        const items = {};
        if (!container) return items;
        container.querySelectorAll('.dynamic-kv-item').forEach(item => {
            const keyEl = item.querySelector(`[name="${keyName}"]`);
            const valueEl = item.querySelector(`[name="${valueName}"]`);
            if (keyEl && valueEl && keyEl.value) {
                items[keyEl.value] = valueEl.value;
            }
        });
        return items;
    }
    _collectSafetySettings(container) {
        const items = {};
        if (!container) return items;
        container.querySelectorAll('.safety-setting-item').forEach(item => {
            const categorySelect = item.querySelector('select:first-child');
            const thresholdSelect = item.querySelector('select:nth-child(2)');
            if (categorySelect && thresholdSelect && categorySelect.value) {
                items[categorySelect.value] = thresholdSelect.value;
            }
        });
        return items;
    }
}

/**
 * Entry point for the KeyGroups page script.
 */
export default function init() {
    console.log('[Modern Frontend] keygroups.js module loaded.');
    const page = new KeyGroupsPage(modalManager);
    page.init(); //调用统一的 init 方法
}