/* --- static/app.js --- */

// ==========================================
// 1. 全域變數與初始化
// ==========================================
let term, fitAddon, ws;
let currentMacDomainData = null;
let isConnected = false; // 💡 新增：用來追蹤目前的連線狀態

window.onload = initTerminal;
window.onresize = () => { if (fitAddon) fitAddon.fit(); };

// ==========================================
// 2. UI 互動與頁籤切換
// ==========================================
function switchTab(tabId, element) {
    document.querySelectorAll('.tab-content').forEach(tab => tab.classList.remove('active'));
    document.querySelectorAll('.tab-btn').forEach(btn => btn.classList.remove('active'));
    
    const targetTab = document.getElementById(tabId);
    if (targetTab) targetTab.classList.add('active');
    if (element) element.classList.add('active');
    
    if(tabId === 'cli-tab' && fitAddon) setTimeout(() => fitAddon.fit(), 50);
    
    // 💡 已經移除自動觸發 switchConfigTask()，避免切換頁籤時覆蓋使用者資料
}

// 💡 查詢頁籤專用的切換邏輯
function switchQueryTask() {
    // 只隱藏 query-tab 裡面的表單
    document.querySelectorAll('#query-tab .task-form').forEach(form => form.classList.remove('active'));
    const selectedTaskId = document.getElementById('queryTask').value;
    const targetForm = document.getElementById(selectedTaskId);
    if (targetForm) targetForm.classList.add('active');
}

// 💡 配置頁籤專用的切換邏輯 (現在只負責切換表單顯示，不自動抓資料)
function switchConfigTask() {
    // 只隱藏 config-tab 裡面的表單
    document.querySelectorAll('#config-tab .task-form').forEach(form => form.classList.remove('active'));
    const selectedTaskId = document.getElementById('configTask').value;
    const targetForm = document.getElementById(selectedTaskId);
    if (targetForm) targetForm.classList.add('active');
}

// 💡 新增的函數：由「🚀 載入任務」按鈕手動觸發
function startConfigTask() {
    // 💡 新增防呆：雙重檢查是否已連線
    if (!isConnected) {
        alert("請先成功連線至 CMTS 設備後，再執行載入任務！");
        return;
    }

    // 1. 先確保對應的表單有顯示出來
    switchConfigTask();
    
    // 2. 根據選擇的任務，決定要向設備抓取什麼資料
    const selectedTaskId = document.getElementById('configTask').value;
    
    if (selectedTaskId === 'form-bonding-config') {
        // 如果使用者正在編輯到一半，給予警告提示
        if (currentMacDomainData && !confirm("重新載入將會清除您目前未套用的設定，確定要繼續嗎？")) {
            return; // 使用者取消，中斷執行
        }
        
        // 確定載入，重置畫面並向設備抓取 MAC Domain 清單
        resetAllManagerData();
        loadMacDomainList();
    }
}

// 💡 新增函數：向後端請求 MAC Domain 清單並動態生成下拉選單
async function loadMacDomainList() {
    const connInfo = getGlobalConnectionInfo();
    if (!connInfo) return;

    const mdSelect = document.getElementById('cfgMacDomain');
    const statusSpan = document.getElementById('fetchStatus');

    // 顯示載入中狀態
    mdSelect.innerHTML = '<option value="">⏳ 查詢設備中...</option>';
    statusSpan.textContent = "正在自動抓取現有 MAC Domain 清單...";
    statusSpan.style.color = "#f39c12";

    try {
        const url = `/api/v1/cmts-mac-domain-list?host=${encodeURIComponent(connInfo.host)}&username=${encodeURIComponent(connInfo.user)}&password=${encodeURIComponent(connInfo.pass)}`;
        const response = await fetch(url);
        const result = await response.json();

        if (result.status === 'success' && result.data.length > 0) {
            mdSelect.innerHTML = ''; // 清空預設選項
            
            // 將後端抓到的陣列一一塞入下拉選單
            result.data.forEach(md => {
                const option = document.createElement('option');
                option.value = md;
                option.textContent = md;
                mdSelect.appendChild(option);
            });
            
            statusSpan.textContent = "✅ 清單抓取成功！請選擇目標並點擊讀取配置。";
            statusSpan.style.color = "#27ae60";
        } else {
            mdSelect.innerHTML = '<option value="">❌ 找不到資料</option>';
            statusSpan.textContent = "無法解析清單，請確認設備狀態。";
            statusSpan.style.color = "#e74c3c";
        }
    } catch (error) {
        mdSelect.innerHTML = '<option value="">❌ 連線錯誤</option>';
        statusSpan.textContent = "連線失敗：" + error;
        statusSpan.style.color = "#e74c3c";
    }
}

function toggleQueryInputs(mode) {
    const type = document.getElementById('queryType' + mode).value;
    const targetInput = document.getElementById('queryTarget' + mode);
    const globalTypes = ['partial_mode', 'hop', 'flap_list', 'flap_sum'];
    
    if (globalTypes.includes(type)) {
        targetInput.disabled = true;
        targetInput.style.backgroundColor = '#e8ecef';
        targetInput.placeholder = "此查詢為全域指令，不需輸入目標";
        targetInput.value = ""; 
    } else {
        targetInput.disabled = false;
        targetInput.style.backgroundColor = '#f8f9fa';
        targetInput.placeholder = mode === 'Cm' ? "例: 6467.7240.4076 (留白則查詢全體)" : "例: 13:0 (留白則查詢全體)";
    }
}

// 💡 新增函數：重置所有 Manager 頁籤的暫存資料與畫面
function resetAllManagerData() {
    // 1. 清空記憶體中的設定資料
    currentMacDomainData = null;

    // 2. 隱藏 MAC Domain 配置表單與 CLI 預覽區塊
    const configArea = document.getElementById('macDomainConfigArea');
    if (configArea) configArea.style.display = 'none';
    
    const previewEl = document.getElementById('cliPreviewContainer');
    if (previewEl) {
        previewEl.textContent = '';
        previewEl.style.display = 'none';
    }

    // 3. 隱藏並禁用「正式套用設定」按鈕
    const deployBtn = document.getElementById('btnDeployConfig');
    if (deployBtn) {
        deployBtn.style.display = 'none';
        deployBtn.disabled = true;
    }

    // 4. 重置 MAC Domain 下拉選單與狀態文字
    const mdSelect = document.getElementById('cfgMacDomain');
    if (mdSelect) mdSelect.innerHTML = '<option value="">請先點擊上方載入任務...</option>';
    
    const fetchStatus = document.getElementById('fetchStatus');
    if (fetchStatus) {
        fetchStatus.textContent = "請先讀取設備狀態...";
        fetchStatus.style.color = "#7f8c8d";
    }

    // 5. (選擇性) 清空查詢表單的輸入框
    document.getElementById('queryTargetCm').value = '';
    document.getElementById('queryTargetRpd').value = '';
}

// ==========================================
// 3. 終端機 (Terminal) 與 WebSocket 邏輯
// ==========================================
function colorizeTerminalStream(text) {
    if (text.includes('\x1b[')) return text;
    let res = text;
    res = res.replace(/\b(\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3})\b/g, '\x1b[1;34m$1\x1b[0m');
    res = res.replace(/\b([0-9a-fA-F]{4}\.[0-9a-fA-F]{4}\.[0-9a-fA-F]{4}|[0-9a-fA-F]{2}(?::[0-9a-fA-F]{2}){5})\b/g, '\x1b[1;35m$1\x1b[0m');
    res = res.replace(/\b(online|w-online|p-online|init\([^)]+\)|up|active|success|yes)\b/gi, '\x1b[1;32m$1\x1b[0m');
    res = res.replace(/\b(offline|down|admin-down|error|fail|failed|shutdown|reject|invalid|no)\b/gi, '\x1b[1;31m$1\x1b[0m');
    res = res.replace(/\b(Cable|GigabitEthernet|TenGigabitEthernet|Upstream|Downstream|Mac-domain|bonding-group|rpd)\b/gi, '\x1b[33m$1\x1b[0m');
    return res;
}

function initTerminal() {
    term = new Terminal({ cursorBlink: true, theme: { background: '#1e1e1e', foreground: '#e0e0e0' }, fontFamily: 'Courier New, monospace', fontSize: 15, scrollback: 100000 });
    fitAddon = new FitAddon.FitAddon();
    term.loadAddon(fitAddon);
    term.open(document.getElementById('terminal-container'));
    fitAddon.fit();
    term.writeln('Welcome to Harmonic cOS Web Terminal.');
    term.writeln('Please confirm the target device above and click "連線至 CMTS"... \r\n');
    
    term.onData((data) => { 
        if (ws && ws.readyState === WebSocket.OPEN) ws.send(data); 
    });
}

function getGlobalConnectionInfo() {
    const host = document.getElementById('cmtsHost').value.trim();
    const user = document.getElementById('cmtsUser').value.trim();
    const pass = document.getElementById('cmtsPass').value.trim();
    if (!host || !user || !pass) {
        alert("請在畫面上方完整輸入目標設備的 IP、帳號與密碼！");
        return null;
    }
    return { host, user, pass };
}

function connectWebSocket() {
    if (ws && ws.readyState === WebSocket.OPEN) return;
    const connInfo = getGlobalConnectionInfo();
    if (!connInfo) return;

    // 💡 關鍵修改 1：在發起新連線前，強制清空舊設備的所有殘留資料
    resetAllManagerData();

    term.writeln(`\x1b[33mConnecting to ${connInfo.host} via WebSocket...\x1b[0m`);
    const protocol = window.location.protocol === 'https:' ? 'wss:' : 'ws:';
    const wsUrl = `${protocol}//${window.location.host}/ws/terminal?host=${encodeURIComponent(connInfo.host)}&username=${encodeURIComponent(connInfo.user)}&password=${encodeURIComponent(connInfo.pass)}`;
    
    ws = new WebSocket(wsUrl);

    ws.onopen = () => {
        isConnected = true; // 💡 標記為已連線
        const btnLoadTask = document.getElementById('btn-load-task');
        if (btnLoadTask) {
            btnLoadTask.disabled = false; // 解鎖按鈕功能
            btnLoadTask.style.backgroundColor = '#c0392b'; // 恢復原本的紅色
            btnLoadTask.style.cursor = 'pointer'; // 恢復正常滑鼠游標
        }

        document.getElementById('wsStatus').textContent = `狀態：已連線`;
        document.getElementById('wsStatus').style.color = '#27ae60';
        document.getElementById('btnConnect').style.display = 'none';
        document.getElementById('btnDisconnect').style.display = 'inline-block';
        document.getElementById('cmtsHost').disabled = true;
        document.getElementById('cmtsUser').disabled = true;
        document.getElementById('cmtsPass').disabled = true;
        term.focus();
    };

    ws.onmessage = (event) => {
        term.write(colorizeTerminalStream(event.data));
    };

    ws.onclose = () => {
        isConnected = false; // 💡 標記為已斷線
        const btnLoadTask = document.getElementById('btn-load-task');
        if (btnLoadTask) {
            btnLoadTask.disabled = true; // 鎖定按鈕功能
            btnLoadTask.style.backgroundColor = '#95a5a6'; // 變回反灰色
            btnLoadTask.style.cursor = 'not-allowed'; // 變回禁止游標
        }

        document.getElementById('wsStatus').textContent = '狀態：已斷線';
        document.getElementById('wsStatus').style.color = '#c0392b';
        document.getElementById('btnConnect').style.display = 'inline-block';
        document.getElementById('btnDisconnect').style.display = 'none';
        document.getElementById('cmtsHost').disabled = false;
        document.getElementById('cmtsUser').disabled = false;
        document.getElementById('cmtsPass').disabled = false;
        term.writeln('\r\n\x1b[31m--- Connection Closed ---\x1b[0m\r\n');

        // 💡 關鍵修改 2：斷線時也自動重置畫面
        resetAllManagerData();
    };
}

function disconnectWebSocket() { if (ws) ws.close(); }

function injectCommand() {
    if (!ws || ws.readyState !== WebSocket.OPEN) return alert("請先點擊「連線至 CMTS」！");
    const cmd = document.getElementById('fixedCmd').value;
    ws.send(cmd + '\r');
    term.focus();
}

function getTerminalText() {
    if (!term) return '';
    try {
        if (term.hasSelection()) return term.getSelection();
        const buffer = term.buffer.active;
        let text = '';
        for (let i = 0; i < buffer.length; i++) {
            const line = buffer.getLine(i);
            if (line) text += line.translateToString(true) + '\n';
        }
        return text;
    } catch (err) {
        console.error("讀取終端機文字失敗:", err);
        return '';
    }
}

function downloadTerminal() {
    const text = getTerminalText();
    if (!text.trim()) return alert("沒有內容可下載！");
    try {
        const blob = new Blob([text], { type: 'text/plain;charset=utf-8' });
        const url = URL.createObjectURL(blob);
        const a = document.createElement('a');
        a.href = url;
        const timestamp = new Date().toISOString().replace(/[:.]/g, '-').substring(0, 19);
        a.download = `cmts_terminal_log_${timestamp}.txt`;
        document.body.appendChild(a);
        a.click();
        document.body.removeChild(a);
        URL.revokeObjectURL(url);
    } catch (err) {
        console.error("下載失敗:", err);
    }
}

// ==========================================
// 4. 綜合查詢 API 呼叫
// ==========================================
async function executeQuery(mode) {
    if (!ws || ws.readyState !== WebSocket.OPEN) {
        alert("請先點擊畫面上方的「連線至 CMTS」按鈕！");
        return;
    }

    const connInfo = getGlobalConnectionInfo();
    if (!connInfo) return;

    const queryType = document.getElementById('queryType' + mode).value;
    const target = document.getElementById('queryTarget' + mode).value.trim();
    const isDebug = document.getElementById('debugQuery' + mode).checked;
    
    openModal(connInfo.host);
    const outputEl = document.getElementById('modalOutput');
    outputEl.innerHTML = `<span style="color: #f39c12;">正在向 ${connInfo.host} 查詢中，請稍候...</span>`;
    
    try {
        const url = `/api/v1/cmts-query?query_type=${queryType}&target=${encodeURIComponent(target)}&host=${encodeURIComponent(connInfo.host)}&username=${encodeURIComponent(connInfo.user)}&password=${encodeURIComponent(connInfo.pass)}`;
        const response = await fetch(url);
        const result = await response.json();
        
        if (result.status === 'success') {
            outputEl.style.color = "#e0e0e0";
            if (isDebug) {
                outputEl.textContent = `[DEBUG] 實際發送指令: ${result.command}\n==================================================\n${result.data}`;
            } else {
                outputEl.textContent = result.data;
            }
        } else {
            outputEl.style.color = "#e74c3c";
            outputEl.textContent = `查詢失敗:\n${result.detail || result.message}`;
        }
    } catch (error) {
        outputEl.style.color = "#e74c3c";
        outputEl.textContent = `連線失敗: ${error}`;
    }
}

// ==========================================
// 5. MAC Domain 配置精靈邏輯
// ==========================================
async function fetchMacDomainConfig() {
    const target = document.getElementById('cfgMacDomain').value.trim();
    const connInfo = getGlobalConnectionInfo();
    if (!connInfo || !target) return alert("請確認設備連線資訊與 MAC Domain！");

    document.getElementById('fetchStatus').textContent = "⏳ 正在讀取並解析設定中...";
    document.getElementById('fetchStatus').style.color = "#f39c12";

    try {
        const url = `/api/v1/cmts-mac-domain-config?target=${encodeURIComponent(target)}&host=${encodeURIComponent(connInfo.host)}&username=${encodeURIComponent(connInfo.user)}&password=${encodeURIComponent(connInfo.pass)}`;
        const response = await fetch(url);
        const result = await response.json();

        if (result.status === 'success') {
            currentMacDomainData = result.data;
            populateFormFromData();
            document.getElementById('macDomainConfigArea').style.display = 'block';
            document.getElementById('fetchStatus').textContent = "✅ 讀取成功！";
            document.getElementById('fetchStatus').style.color = "#27ae60";
        } else {
            alert("讀取失敗：" + result.detail);
            document.getElementById('fetchStatus').textContent = "❌ 讀取失敗";
        }
    } catch (error) {
        alert("連線錯誤：" + error);
    }
}

function populateFormFromData() {
    const d = currentMacDomainData;
    
    // 💡 正名工程：對齊後端 common_settings
    document.getElementById('g_ip_prov').value = d.common_settings['ip-provisioning-mode'] || 'dual-stack';
    document.getElementById('g_diplexer').value = d.common_settings['diplexer-band-edge'] || 'enabled';
    document.getElementById('g_bat31').value = d.common_settings['cm-battery-mode-31-support'] || 'disabled';
    document.getElementById('g_bat30').value = d.common_settings['cm-battery-mode-30-support'] || 'disabled';
    document.getElementById('g_docsis40').value = d.common_settings['docsis40'] || 'disabled';
    document.getElementById('g_ds_dyn').value = d.common_settings['ds-dynamic-bonding-group'] || 'disabled';
    document.getElementById('g_us_dyn').value = d.common_settings['us-dynamic-bonding-group'] || 'disabled';

    // 💡 正名工程：對齊後端 basic_channel_sets
    document.getElementById('b_admin').value = d.basic_channel_sets['admin-state'] || 'down';
    document.getElementById('b_ds_pri').value = d.basic_channel_sets['ds-primary-set'] || '';
    document.getElementById('b_ds_non_pri').value = d.basic_channel_sets['ds-non-primary-set'] || '';
    document.getElementById('b_us_phy').value = d.basic_channel_sets['us-phy-channel-set'] || '';
    document.getElementById('b_ds_ofdm').value = d.basic_channel_sets['ds-ofdm-set'] || '';
    document.getElementById('b_us_ofdma').value = d.basic_channel_sets['us-ofdma-set'] || '';

    // 💡 正名工程：對齊後端 static_ds_bonding_groups
    const dsSelect = document.getElementById('select_ds_group');
    dsSelect.innerHTML = '<option value="_new_">[➕ 新增 DS Group]</option>';
    Object.keys(d.static_ds_bonding_groups).forEach(grp => dsSelect.innerHTML += `<option value="${grp}">${grp}</option>`);
    if (Object.keys(d.static_ds_bonding_groups).length > 0) dsSelect.value = Object.keys(d.static_ds_bonding_groups)[0];
    
    // 💡 正名工程：對齊後端 static_us_bonding_groups
    const usSelect = document.getElementById('select_us_group');
    usSelect.innerHTML = '<option value="_new_">[➕ 新增 US Group]</option>';
    Object.keys(d.static_us_bonding_groups).forEach(grp => usSelect.innerHTML += `<option value="${grp}">${grp}</option>`);
    if (Object.keys(d.static_us_bonding_groups).length > 0) usSelect.value = Object.keys(d.static_us_bonding_groups)[0];

    toggleGroupVisibility();
    loadDsGroupData();
    loadUsGroupData();
}

// 💡 新增函數：放棄修改，還原回記憶體中的原始設備設定
function revertFormChanges() {
    // 防呆：確保目前記憶體中有原始資料可以還原
    if (!currentMacDomainData) return;

    // 加上確認對話框，避免使用者誤觸
    if (!confirm("確定要放棄目前的修改，還原回設備原始的設定值嗎？")) {
        return;
    }

    // 1. 重新利用記憶體中的原始 JSON 資料填入表單
    populateFormFromData();

    // 2. 隱藏已經產生的 CLI 預覽與套用按鈕 (因為狀態已經改變)
    const previewEl = document.getElementById('cliPreviewContainer');
    if (previewEl) {
        previewEl.textContent = '';
        previewEl.style.display = 'none';
    }
    
    const deployBtn = document.getElementById('btnDeployConfig');
    if (deployBtn) {
        deployBtn.style.display = 'none';
        deployBtn.disabled = true;
    }

    // 3. 給予使用者視覺回饋
    const fetchStatus = document.getElementById('fetchStatus');
    fetchStatus.textContent = "🔄 已還原為原始設定！";
    fetchStatus.style.color = "#2980b9";
    
    // 3秒後把狀態文字改回綠色的讀取成功
    setTimeout(() => {
        fetchStatus.textContent = "✅ 讀取成功！";
        fetchStatus.style.color = "#27ae60";
    }, 3000);
}

function toggleGroupVisibility() {
    const dsDyn = document.getElementById('g_ds_dyn').value;
    const usDyn = document.getElementById('g_us_dyn').value;
    document.getElementById('section_group_ds').style.display = (dsDyn === 'disabled') ? 'block' : 'none';
    document.getElementById('section_group_us').style.display = (usDyn === 'disabled') ? 'block' : 'none';
}

function loadDsGroupData() {
    const grp = document.getElementById('select_ds_group').value;
    const newGrpInput = document.getElementById('input_new_ds_group');
    if (grp === '_new_') {
        newGrpInput.style.display = 'inline-block';
        document.getElementById('ds_g_admin').value = 'down';
        document.getElementById('ds_g_down').value = '';
        document.getElementById('ds_g_ofdm').value = '';
        document.getElementById('ds_g_fdx').value = '';
    } else {
        newGrpInput.style.display = 'none';
        // 💡 正名工程：對齊後端 static_ds_bonding_groups
        const data = currentMacDomainData.static_ds_bonding_groups[grp];
        document.getElementById('ds_g_admin').value = data['admin-state'] || 'down';
        document.getElementById('ds_g_down').value = data['down-channel-set'] || '';
        document.getElementById('ds_g_ofdm').value = data['ofdm-channel-set'] || '';
        document.getElementById('ds_g_fdx').value = data['fdx-ofdm-channel-set'] || '';
    }
}

function loadUsGroupData() {
    const grp = document.getElementById('select_us_group').value;
    const newGrpInput = document.getElementById('input_new_us_group');
    if (grp === '_new_') {
        newGrpInput.style.display = 'inline-block';
        document.getElementById('us_g_admin').value = 'down';
        document.getElementById('us_g_us').value = '';
        document.getElementById('us_g_ofdma').value = '';
        document.getElementById('us_g_fdx').value = '';
    } else {
        newGrpInput.style.display = 'none';
        // 💡 正名工程：對齊後端 static_us_bonding_groups
        const data = currentMacDomainData.static_us_bonding_groups[grp];
        document.getElementById('us_g_admin').value = data['admin-state'] || 'down';
        document.getElementById('us_g_us').value = data['us-channel-set'] || '';
        document.getElementById('us_g_ofdma').value = data['ofdma-channel-set'] || '';
        document.getElementById('us_g_fdx').value = data['fdx-ofdma-channel-set'] || '';
    }
}

function generateMacDomainCLI() {
    const md = document.getElementById('cfgMacDomain').value.trim();
    let cli = `! --- Harmonic MAC Domain Configuration SOP ---\n`;

    // --- 區塊 1: MAC Domain Base ---
    cli += `! 1. [區塊] MAC Domain 全域與 Base 設定\n`;
    cli += `cable mac-domain ${md} admin-state down\ncommit\n`;
    
    const baseCmds = [
        `ip-provisioning-mode ${document.getElementById('g_ip_prov').value}`,
        `diplexer-band-edge control ${document.getElementById('g_diplexer').value}`,
        `cm-battery-mode-31-support ${document.getElementById('g_bat31').value}`,
        `cm-battery-mode-30-support ${document.getElementById('g_bat30').value}`,
        `docsis40 ${document.getElementById('g_docsis40').value}`,
        `ds-dynamic-bonding-group ${document.getElementById('g_ds_dyn').value}`,
        `us-dynamic-bonding-group ${document.getElementById('g_us_dyn').value}`,
        `ds-primary-set ${document.getElementById('b_ds_pri').value}`,
        `ds-non-primary-set ${document.getElementById('b_ds_non_pri').value}`,
        `us-phy-channel-set ${document.getElementById('b_us_phy').value}`,
        `ds-ofdm-set ${document.getElementById('b_ds_ofdm').value}`,
        `us-ofdma-set ${document.getElementById('b_us_ofdma').value}`
    ];
    baseCmds.forEach(cmd => {
        if (!cmd.endsWith(" ")) cli += `cable mac-domain ${md} ${cmd}\n`;
    });
    cli += `cable mac-domain ${md} admin-state ${document.getElementById('b_admin').value}\ncommit\n`;

    // --- 區塊 2: DS Bonding Group ---
    if (document.getElementById('g_ds_dyn').value === 'disabled') {
        const isNewDs = document.getElementById('select_ds_group').value === '_new_';
        let dsName = isNewDs ? document.getElementById('input_new_ds_group').value.trim() : document.getElementById('select_ds_group').value;
        
        if (dsName) {
            cli += `\n! 2. [區塊] DS Bonding Group [${dsName}] 設定\n`;
            if (!isNewDs) cli += `cable mac-domain ${md} ds-bonding-group ${dsName} admin-state down\ncommit\n`;
            
            if (document.getElementById('ds_g_down').value) cli += `cable mac-domain ${md} ds-bonding-group ${dsName} down-channel-set ${document.getElementById('ds_g_down').value}\n`;
            if (document.getElementById('ds_g_ofdm').value) cli += `cable mac-domain ${md} ds-bonding-group ${dsName} ofdm-channel-set ${document.getElementById('ds_g_ofdm').value}\n`;
            if (document.getElementById('ds_g_fdx').value) cli += `cable mac-domain ${md} ds-bonding-group ${dsName} fdx-ofdm-channel-set ${document.getElementById('ds_g_fdx').value}\n`;
            
            cli += `cable mac-domain ${md} ds-bonding-group ${dsName} admin-state ${document.getElementById('ds_g_admin').value}\ncommit\n`;
        }
    }

    // --- 區塊 3: US Bonding Group ---
    if (document.getElementById('g_us_dyn').value === 'disabled') {
        const isNewUs = document.getElementById('select_us_group').value === '_new_';
        let usName = isNewUs ? document.getElementById('input_new_us_group').value.trim() : document.getElementById('select_us_group').value;
        
        if (usName) {
            cli += `\n! 3. [區塊] US Bonding Group [${usName}] 設定\n`;
            if (!isNewUs) cli += `cable mac-domain ${md} us-bonding-group ${usName} admin-state down\ncommit\n`;
            
            if (document.getElementById('us_g_us').value) cli += `cable mac-domain ${md} us-bonding-group ${usName} us-channel-set ${document.getElementById('us_g_us').value}\n`;
            if (document.getElementById('us_g_ofdma').value) cli += `cable mac-domain ${md} us-bonding-group ${usName} ofdma-channel-set ${document.getElementById('us_g_ofdma').value}\n`;
            if (document.getElementById('us_g_fdx').value) cli += `cable mac-domain ${md} us-bonding-group ${usName} fdx-ofdma-channel-set ${document.getElementById('us_g_fdx').value}\n`;
            
            cli += `cable mac-domain ${md} us-bonding-group ${usName} admin-state ${document.getElementById('us_g_admin').value}\ncommit\n`;
        }
    }

    const previewEl = document.getElementById('cliPreviewContainer');
    previewEl.textContent = cli;
    previewEl.style.display = 'block';
    
    const deployBtn = document.getElementById('btnDeployConfig');
    deployBtn.style.display = 'inline-block';
    deployBtn.disabled = false;
}

async function executeBondingConfig() {
    if (!confirm("⚠️ 警告：此操作將導致 MAC Domain 重新啟動，影響用戶服務。確定要執行嗎？")) return;
    
    const cliScript = document.getElementById('cliPreviewContainer').textContent;
    const connInfo = getGlobalConnectionInfo();
    if (!connInfo) return;

    openModal(connInfo.host);
    const outputEl = document.getElementById('modalOutput');
    outputEl.innerHTML = `<span style="color: #f39c12;">🚀 正在排隊並執行配置腳本，這可能需要幾秒鐘，請勿關閉視窗...</span>\n\n${cliScript}`;
    
    try {
        const response = await fetch('/api/v1/cmts-config', {
            method: 'POST',
            headers: { 'Content-Type': 'application/json' },
            body: JSON.stringify({
                script: cliScript,
                host: connInfo.host,
                username: connInfo.user,
                password: connInfo.pass
            })
        });
        const result = await response.json();
        
        if (result.status === 'success') {
            outputEl.style.color = "#e0e0e0";
            outputEl.textContent = `✅ 設定執行完成！\n==================================================\n${result.data}`;
        } else {
            outputEl.style.color = "#e74c3c";
            outputEl.textContent = `❌ 設定執行失敗:\n${result.message}`;
        }
    } catch (error) {
        outputEl.style.color = "#e74c3c";
        outputEl.textContent = `❌ 連線或伺服器錯誤: ${error}`;
    }
}

// ==========================================
// 6. Modal 彈出視窗控制
// ==========================================
function openModal(targetInfo) {
    document.getElementById('outputModal').classList.add('active');
    document.getElementById('modalTargetInfo').textContent = targetInfo ? `(${targetInfo})` : '';
    document.body.style.overflow = 'hidden';
}

function closeModal(event) {
    if (event && event.target !== event.currentTarget && event.target.className !== 'modal-close') return;
    document.getElementById('outputModal').classList.remove('active');
    document.body.style.overflow = '';
}
