using System.Text;
using CncSimulator.Core;

namespace CncSimulator.Admin
{
    /// <summary>
    /// 管理页面HTML生成器。
    /// 总管理页面：显示数据库地址+手动启停。
    /// 单地址页面：设备卡片+统计+设备增减。
    /// </summary>
    public class AdminHandler
    {
        /// <summary>生成总管理页面</summary>
        public string BuildGatewayPage(SimulatorEngine engine)
        {
            var sb = new StringBuilder();
            sb.AppendLine("<!DOCTYPE html><html lang='zh-CN'><head><meta charset='utf-8'>");
            sb.AppendLine("<meta name='viewport' content='width=device-width, initial-scale=1'>");
            sb.AppendLine("<title>CNC 模拟采集服务 - 总管理</title>");
            sb.AppendLine("<style>");
            sb.AppendLine("* { margin:0; padding:0; box-sizing:border-box; }");
            sb.AppendLine("body { font-family:'Microsoft YaHei',sans-serif; background:#f0f2f5; color:#333; }");
            sb.AppendLine(".header { background:#1890ff; color:#fff; padding:16px 24px; display:flex; justify-content:space-between; align-items:center; }");
            sb.AppendLine(".header h1 { font-size:20px; }");
            sb.AppendLine(".header-actions button { margin-left:8px; padding:6px 16px; border:none; border-radius:4px; cursor:pointer; font-size:14px; }");
            sb.AppendLine(".btn-start { background:#52c41a; color:#fff; }");
            sb.AppendLine(".btn-stop { background:#ff4d4f; color:#fff; }");
            sb.AppendLine(".btn-blue { background:#1890ff; color:#fff; }");
            sb.AppendLine(".container { max-width:1200px; margin:20px auto; padding:0 20px; }");
            sb.AppendLine(".section { background:#fff; border-radius:8px; padding:20px; margin-bottom:16px; box-shadow:0 1px 4px rgba(0,0,0,0.1); }");
            sb.AppendLine(".section h2 { font-size:16px; margin-bottom:12px; padding-bottom:8px; border-bottom:1px solid #e8e8e8; }");
            sb.AppendLine("table { width:100%; border-collapse:collapse; }");
            sb.AppendLine("th,td { padding:10px 12px; text-align:left; border-bottom:1px solid #f0f0f0; font-size:14px; }");
            sb.AppendLine("th { background:#fafafa; font-weight:600; color:#666; }");
            sb.AppendLine(".status-dot { display:inline-block; width:8px; height:8px; border-radius:50%; margin-right:6px; }");
            sb.AppendLine(".status-running { background:#52c41a; }");
            sb.AppendLine(".status-stopped { background:#d9d9d9; }");
            sb.AppendLine("button { cursor:pointer; }");
            sb.AppendLine(".btn-sm { padding:4px 12px; border:1px solid #d9d9d9; border-radius:4px; background:#fff; font-size:13px; }");
            sb.AppendLine(".btn-sm:hover { border-color:#1890ff; color:#1890ff; }");
            sb.AppendLine(".btn-sm-primary { padding:4px 12px; border:1px solid #1890ff; border-radius:4px; background:#1890ff; color:#fff; font-size:13px; }");
            sb.AppendLine(".btn-sm-danger { padding:4px 12px; border:1px solid #ff4d4f; border-radius:4px; background:#fff; color:#ff4d4f; font-size:13px; }");
            sb.AppendLine(".interval-input { width:60px; padding:2px 6px; border:1px solid #d9d9d9; border-radius:4px; text-align:center; }");
            sb.AppendLine(".modal-overlay { display:none; position:fixed; top:0; left:0; width:100%; height:100%; background:rgba(0,0,0,0.4); z-index:1000; justify-content:center; align-items:center; }");
            sb.AppendLine(".modal-overlay.show { display:flex; }");
            sb.AppendLine(".modal { background:#fff; border-radius:8px; padding:24px; width:520px; max-height:80vh; overflow-y:auto; box-shadow:0 4px 20px rgba(0,0,0,0.2); }");
            sb.AppendLine(".modal h3 { font-size:16px; margin-bottom:12px; padding-bottom:8px; border-bottom:1px solid #e8e8e8; }");
            sb.AppendLine(".machine-list { max-height:350px; overflow-y:auto; margin-bottom:16px; }");
            sb.AppendLine(".machine-item { display:flex; align-items:center; padding:8px 4px; border-bottom:1px solid #f5f5f5; }");
            sb.AppendLine(".machine-item:hover { background:#fafafa; }");
            sb.AppendLine(".machine-item input[type=checkbox] { margin-right:10px; width:16px; height:16px; cursor:pointer; }");
            sb.AppendLine(".machine-item .code { font-weight:600; min-width:100px; font-size:14px; }");
            sb.AppendLine(".machine-item .name { color:#666; font-size:13px; }");
            sb.AppendLine(".modal-actions { display:flex; justify-content:space-between; align-items:center; }");
            sb.AppendLine(".modal-actions .sel-actions { font-size:13px; color:#666; }");
            sb.AppendLine(".modal-actions .sel-actions a { color:#1890ff; cursor:pointer; text-decoration:none; margin-right:12px; }");
            sb.AppendLine(".modal-actions .btn-group { display:flex; gap:8px; }");
            sb.AppendLine(".btn-confirm { padding:6px 20px; border:1px solid #1890ff; border-radius:4px; background:#1890ff; color:#fff; font-size:14px; cursor:pointer; }");
            sb.AppendLine(".btn-confirm:hover { background:#40a9ff; }");
            sb.AppendLine(".btn-cancel { padding:6px 20px; border:1px solid #d9d9d9; border-radius:4px; background:#fff; color:#333; font-size:14px; cursor:pointer; }");
            sb.AppendLine("</style></head><body>");
            sb.AppendLine("<div class='header'>");
            sb.AppendLine("  <h1>CNC 模拟采集服务</h1>");
            sb.AppendLine("  <div class='header-actions'>");
            sb.AppendLine("    <button class='btn-start' onclick='startAll()'>全部启动</button>");
            sb.AppendLine("    <button class='btn-stop' onclick='stopAll()'>全部停止</button>");
            sb.AppendLine("    <button class='btn-blue' onclick='reloadDb()'>刷新数据库</button>");
            sb.AppendLine("  </div>");
            sb.AppendLine("</div>");
            sb.AppendLine("<div class='container'>");
            sb.AppendLine("  <div class='section'><h2>数据库采集地址</h2>");
            sb.AppendLine("    <table><thead><tr><th>ID</th><th>名称</th><th>机床数</th><th>状态</th><th>端口</th><th>频率(秒)</th><th>总零件</th><th>操作</th></tr></thead>");
            sb.AppendLine("    <tbody id='addrTable'></tbody></table>");
            sb.AppendLine("  </div>");
            sb.AppendLine("  <div class='section'><h2>运行中模拟端口</h2>");
            sb.AppendLine("    <table><thead><tr><th>名称</th><th>端口</th><th>设备</th><th>请求次数</th><th>总零件</th><th>操作</th></tr></thead>");
            sb.AppendLine("    <tbody id='runningTable'></tbody></table>");
            sb.AppendLine("  </div>");
            sb.AppendLine("</div>");
            // 机床选择弹窗
            sb.AppendLine("<div class='modal-overlay' id='machineModal'>");
            sb.AppendLine("  <div class='modal'>");
            sb.AppendLine("    <h3 id='modalTitle'>选择要模拟的机床</h3>");
            sb.AppendLine("    <div class='machine-list' id='machineList'></div>");
            sb.AppendLine("    <div class='modal-actions'>");
            sb.AppendLine("      <div class='sel-actions'>");
            sb.AppendLine("        <a onclick=\"toggleAll(true)\">全选</a><a onclick=\"toggleAll(false)\">取消全选</a>");
            sb.AppendLine("        <span id='selCount'>已选 0 台</span>");
            sb.AppendLine("      </div>");
            sb.AppendLine("      <div class='btn-group'>");
            sb.AppendLine("        <button class='btn-cancel' onclick='closeModal()'>取消</button>");
            sb.AppendLine("        <button class='btn-confirm' id='btnConfirmStart' onclick='confirmStart()'>启动模拟</button>");
            sb.AppendLine("      </div>");
            sb.AppendLine("    </div>");
            sb.AppendLine("  </div>");
            sb.AppendLine("</div>");
            sb.AppendLine("<script>");
            sb.AppendLine("function refresh(){");
            sb.AppendLine("  fetch('/admin/api/db-addresses').then(r=>r.json()).then(addrs=>{");
            sb.AppendLine("    window._addrCache=addrs;");
            sb.AppendLine("    var tb=document.getElementById('addrTable');tb.innerHTML='';");
            sb.AppendLine("    addrs.forEach(function(a){");
            sb.AppendLine("      var st=a.isRunning?'<span class=\"status-dot status-running\"></span>运行中':'<span class=\"status-dot status-stopped\"></span>未启动';");
            sb.AppendLine("      var portVal=a.runningPort||'';");
            sb.AppendLine("      var h='<tr><td>'+a.dbId+'</td><td>'+a.name+'</td><td>'+a.machineCount+'台</td><td>'+st+'</td>';");
            sb.AppendLine("      h+='<td>'+(a.isRunning?a.runningPort:'-')+'</td>';");
            sb.AppendLine("      h+='<td>'+(a.isRunning?'<input class=\"interval-input\" id=\"int_'+a.dbId+'\" value=\"10\" disabled>':'<input class=\"interval-input\" id=\"int_'+a.dbId+'\" value=\"10\">')+'</td>';");
            sb.AppendLine("      h+='<td id=\"parts_'+a.dbId+'\">-</td>';");
            sb.AppendLine("      h+='<td>';");
            sb.AppendLine("      if(a.isRunning){h+='<button class=\"btn-sm-danger\" onclick=\"stopAddr('+a.dbId+')\">停止</button> ';");
            sb.AppendLine("        h+='<a class=\"btn-sm\" href=\"http://localhost:'+a.runningPort+'/admin\" target=\"_blank\">管理</a> ';}");
            sb.AppendLine("      else{h+='<button class=\"btn-sm-primary\" onclick=\"startAddr('+a.dbId+')\">启动</button>'}");
            sb.AppendLine("      h+='</td></tr>';");
            sb.AppendLine("      tb.innerHTML+=h;");
            sb.AppendLine("    });");
            sb.AppendLine("  }).catch(function(){});");
            sb.AppendLine("  fetch('/admin/api/status').then(r=>r.json()).then(data=>{");
            sb.AppendLine("    var rt=document.getElementById('runningTable');rt.innerHTML='';");
            sb.AppendLine("    data.forEach(function(s){");
            sb.AppendLine("      rt.innerHTML+='<tr><td>'+s.name+'</td><td>'+s.port+'</td><td>'+s.onlineDevices+'/'+s.totalDevices+'</td><td>'+s.requestCount+'</td><td>'+(s.totalParts||0)+'</td><td><a class=\"btn-sm\" href=\"http://localhost:'+s.port+'/admin\" target=\"_blank\">管理</a> <button class=\"btn-sm-danger\" onclick=\"stopAddr('+s.dbAddressId+')\">停止</button></td></tr>';");
            sb.AppendLine("    });");
            sb.AppendLine("    // 更新零件数");
            sb.AppendLine("    data.forEach(function(s){ var el=document.getElementById('parts_'+s.dbAddressId); if(el) el.textContent=s.totalParts||0; });");
            sb.AppendLine("  }).catch(function(){});");
            sb.AppendLine("}");
            sb.AppendLine("function startAddr(dbId){");
            sb.AppendLine("  // 从db-addresses缓存中找到该地址的机床列表，打开弹窗");
            sb.AppendLine("  window._pendingAddrId=dbId;");
            sb.AppendLine("  var intEl=document.getElementById('int_'+dbId);");
            sb.AppendLine("  window._pendingInterval=intEl?parseInt(intEl.value):10;");
            sb.AppendLine("  var addr=window._addrCache.find(function(a){return a.dbId===dbId;});");
            sb.AppendLine("  if(!addr||!addr.machines||addr.machines.length===0){alert('该地址下没有机床');return;}");
            sb.AppendLine("  document.getElementById('modalTitle').textContent='选择要模拟的机床 - '+addr.name;");
            sb.AppendLine("  var list=document.getElementById('machineList');list.innerHTML='';");
            sb.AppendLine("  addr.machines.forEach(function(m){");
            sb.AppendLine("    list.innerHTML+='<div class=\"machine-item\"><input type=\"checkbox\" checked data-code=\"'+(m.DeviceCode||m.deviceCode)+'\" data-name=\"'+(m.Name||m.name)+'\"><span class=\"code\">'+(m.DeviceCode||m.deviceCode)+'</span><span class=\"name\">'+(m.Name||m.name)+'</span></div>';");
            sb.AppendLine("  });");
            sb.AppendLine("  updateSelCount();");
            sb.AppendLine("  document.getElementById('machineModal').classList.add('show');");
            sb.AppendLine("}");
            sb.AppendLine("function closeModal(){document.getElementById('machineModal').classList.remove('show');}");
            sb.AppendLine("function toggleAll(checked){var cbs=document.querySelectorAll('#machineList input[type=checkbox]');cbs.forEach(function(cb){cb.checked=checked;});updateSelCount();}");
            sb.AppendLine("function updateSelCount(){var cbs=document.querySelectorAll('#machineList input[type=checkbox]:checked');document.getElementById('selCount').textContent='已选 '+cbs.length+' 台';}");
            sb.AppendLine("document.getElementById('machineList').addEventListener('change',function(e){if(e.target.type==='checkbox')updateSelCount();});");
            sb.AppendLine("function confirmStart(){");
            sb.AppendLine("  var cbs=document.querySelectorAll('#machineList input[type=checkbox]:checked');");
            sb.AppendLine("  if(cbs.length===0){alert('请至少选择一台机床');return;}");
            sb.AppendLine("  var codes=[];cbs.forEach(function(cb){codes.push(cb.getAttribute('data-code'));});");
            sb.AppendLine("  closeModal();");
            sb.AppendLine("  fetch('/admin/api/start-address',{method:'POST',headers:{'Content-Type':'application/json'},body:JSON.stringify({dbAddressId:window._pendingAddrId,interval:window._pendingInterval,deviceCodes:codes})}).then(r=>r.json()).then(function(){refresh();});");
            sb.AppendLine("}");
            sb.AppendLine("function stopAddr(dbId){fetch('/admin/api/stop-address',{method:'POST',headers:{'Content-Type':'application/json'},body:JSON.stringify({dbAddressId:dbId})}).then(function(){refresh();});}");
            sb.AppendLine("function startAll(){fetch('/admin/api/start-all',{method:'POST'}).then(function(){refresh();});}");
            sb.AppendLine("function stopAll(){fetch('/admin/api/stop-all',{method:'POST'}).then(function(){refresh();});}");
            sb.AppendLine("function reloadDb(){fetch('/admin/api/reload-db',{method:'POST'}).then(function(){refresh();});}");
            sb.AppendLine("setInterval(refresh,2000);refresh();");
            sb.AppendLine("</script></body></html>");
            return sb.ToString();
        }

        /// <summary>生成单地址管理页面</summary>
        public string BuildSingleAddressPage(SimulatorServer server)
        {
            var sb = new StringBuilder();
            sb.AppendLine("<!DOCTYPE html><html lang='zh-CN'><head><meta charset='utf-8'>");
            sb.AppendLine("<meta name='viewport' content='width=device-width, initial-scale=1'>");
            sb.AppendLine("<title>" + server.Name + " - 模拟管理</title>");
            sb.AppendLine("<style>");
            sb.AppendLine("* { margin:0; padding:0; box-sizing:border-box; }");
            sb.AppendLine("body { font-family:'Microsoft YaHei',sans-serif; background:#f0f2f5; color:#333; }");
            sb.AppendLine(".header { background:#1890ff; color:#fff; padding:16px 24px; display:flex; justify-content:space-between; align-items:center; }");
            sb.AppendLine(".header h1 { font-size:18px; }");
            sb.AppendLine(".header-actions button { margin-left:8px; padding:6px 16px; border:none; border-radius:4px; cursor:pointer; font-size:14px; }");
            sb.AppendLine(".btn-start { background:#52c41a; color:#fff; }");
            sb.AppendLine(".btn-stop { background:#ff4d4f; color:#fff; }");
            sb.AppendLine(".container { max-width:1200px; margin:20px auto; padding:0 20px; }");
            sb.AppendLine(".section { background:#fff; border-radius:8px; padding:20px; margin-bottom:16px; box-shadow:0 1px 4px rgba(0,0,0,0.1); }");
            sb.AppendLine(".section h2 { font-size:16px; margin-bottom:12px; padding-bottom:8px; border-bottom:1px solid #e8e8e8; }");
            sb.AppendLine(".settings-row { display:flex; gap:24px; align-items:center; flex-wrap:wrap; margin-bottom:8px; }");
            sb.AppendLine(".settings-row label { font-size:14px; color:#666; min-width:100px; }");
            sb.AppendLine(".settings-row input,.settings-row select { padding:4px 8px; border:1px solid #d9d9d9; border-radius:4px; }");
            sb.AppendLine(".btn-apply { padding:4px 12px; border:1px solid #1890ff; border-radius:4px; background:#fff; color:#1890ff; cursor:pointer; }");
            sb.AppendLine(".stats-grid { display:grid; grid-template-columns:repeat(auto-fill,minmax(180px,1fr)); gap:12px; }");
            sb.AppendLine(".stat-item { text-align:center; padding:12px; background:#fafafa; border-radius:4px; }");
            sb.AppendLine(".stat-item .value { font-size:24px; font-weight:600; color:#1890ff; }");
            sb.AppendLine(".stat-item .label { font-size:13px; color:#999; margin-top:4px; }");
            sb.AppendLine(".device-cards { display:grid; grid-template-columns:repeat(auto-fill,minmax(300px,1fr)); gap:12px; }");
            sb.AppendLine(".device-card { border:1px solid #e8e8e8; border-radius:6px; padding:12px; }");
            sb.AppendLine(".device-card.offline { opacity:0.5; background:#fafafa; }");
            sb.AppendLine(".device-card h3 { font-size:14px; margin-bottom:6px; }");
            sb.AppendLine(".device-card .info { font-size:13px; color:#666; line-height:1.8; }");
            sb.AppendLine(".device-card .actions { margin-top:8px; display:flex; flex-wrap:wrap; gap:4px; }");
            sb.AppendLine(".device-card .actions button { padding:2px 8px; font-size:12px; border:1px solid #d9d9d9; border-radius:3px; background:#fff; cursor:pointer; }");
            sb.AppendLine(".device-card .actions button:hover { border-color:#1890ff; color:#1890ff; }");
            sb.AppendLine(".device-card .actions button.btn-remove { border-color:#ff4d4f; color:#ff4d4f; }");
            sb.AppendLine(".parts-table { width:100%; border-collapse:collapse; font-size:13px; }");
            sb.AppendLine(".parts-table th,.parts-table td { padding:6px 8px; text-align:left; border-bottom:1px solid #f0f0f0; }");
            sb.AppendLine(".parts-table th { background:#fafafa; color:#666; }");
            sb.AppendLine(".json-preview { max-height:200px; overflow:auto; background:#fafafa; padding:12px; border-radius:4px; font-family:Consolas,monospace; font-size:12px; white-space:pre-wrap; word-break:break-all; }");
            sb.AppendLine(".log-table { width:100%; border-collapse:collapse; font-size:13px; }");
            sb.AppendLine(".log-table th,.log-table td { padding:6px 8px; text-align:left; border-bottom:1px solid #f0f0f0; }");
            sb.AppendLine(".log-table th { background:#fafafa; color:#666; }");
            sb.AppendLine(".add-device-row { display:flex; gap:8px; align-items:center; margin-top:12px; }");
            sb.AppendLine(".add-device-row input { padding:4px 8px; border:1px solid #d9d9d9; border-radius:4px; font-size:13px; }");
            sb.AppendLine(".add-device-row button { padding:4px 12px; border:1px solid #52c41a; border-radius:4px; background:#52c41a; color:#fff; font-size:13px; cursor:pointer; }");
            sb.AppendLine("</style></head><body>");
            sb.AppendLine("<div class='header'>");
            sb.AppendLine("  <h1>" + server.Name + " (端口 " + server.Port + ")</h1>");
            sb.AppendLine("  <div class='header-actions'>");
            sb.AppendLine("    <a href='http://localhost:" + server.Port + "/' target='_blank' style='color:#fff;margin-right:8px;font-size:14px;'>数据接口</a>");
            sb.AppendLine("    <button class='btn-start' onclick='startSim()'>启动</button>");
            sb.AppendLine("    <button class='btn-stop' onclick='stopSim()'>停止</button>");
            sb.AppendLine("  </div>");
            sb.AppendLine("</div>");
            sb.AppendLine("<div class='container'>");

            // 统计概览
            sb.AppendLine("  <div class='section'><h2>统计概览</h2>");
            sb.AppendLine("    <div class='stats-grid' id='statsGrid'>加载中...</div>");
            sb.AppendLine("  </div>");

            // 零件统计表（按设备+NC程序）
            sb.AppendLine("  <div class='section'><h2>零件统计（按设备+NC程序）</h2>");
            sb.AppendLine("    <table class='parts-table'>");
            sb.AppendLine("      <thead><tr><th>设备编码</th><th>描述</th><th>NC程序</th><th>零件数</th><th>当前零件</th></tr></thead>");
            sb.AppendLine("      <tbody id='partsTable'></tbody>");
            sb.AppendLine("    </table>");
            sb.AppendLine("  </div>");

            // 全局设置
            sb.AppendLine("  <div class='section'><h2>全局设置</h2>");
            sb.AppendLine("    <div class='settings-row'>");
            sb.AppendLine("      <label>数据变化频率:</label>");
            sb.AppendLine("      <input type='number' id='intervalInput' min='1' max='300' value='" + server.Config.DataChangeInterval + "'> 秒");
            sb.AppendLine("      <button class='btn-apply' onclick='setInterval2()'>应用</button>");
            sb.AppendLine("    </div>");
            sb.AppendLine("    <div class='settings-row'>");
            sb.AppendLine("      <label>剧本模式:</label>");
            sb.AppendLine("      <label><input type='radio' name='mode' value='auto'" + (server.Config.ScenarioMode == "auto" ? " checked" : "") + "> 自动循环</label>");
            sb.AppendLine("      <label><input type='radio' name='mode' value='manual'" + (server.Config.ScenarioMode == "manual" ? " checked" : "") + "> 手动触发</label>");
            sb.AppendLine("    </div>");
            sb.AppendLine("    <div class='settings-row'>");
            sb.AppendLine("      <label>网络异常模拟:</label>");
            sb.AppendLine("      <select id='networkSelect' onchange='setNetwork(this.value)'>");
            sb.AppendLine("        <option value='normal'>正常</option><option value='http500'>HTTP 500</option>");
            sb.AppendLine("        <option value='timeout'>连接超时</option><option value='refuse'>拒绝连接</option>");
            sb.AppendLine("        <option value='empty'>返回空数组</option><option value='malformed'>畸形JSON</option>");
            sb.AppendLine("      </select>");
            sb.AppendLine("    </div>");
            sb.AppendLine("  </div>");

            // 设备状态卡片（含添加/移除）
            sb.AppendLine("  <div class='section'><h2>设备状态</h2>");
            sb.AppendLine("    <div class='device-cards' id='deviceCards'>加载中...</div>");
            sb.AppendLine("    <div class='add-device-row'>");
            sb.AppendLine("      <input id='addDeviceCode' placeholder='设备编码(如CNC-NEW)'>");
            sb.AppendLine("      <input id='addDeviceDesc' placeholder='设备描述'>");
            sb.AppendLine("      <button onclick='addDevice()'>添加设备</button>");
            sb.AppendLine("    </div>");
            sb.AppendLine("  </div>");

            // JSON预览
            sb.AppendLine("  <div class='section'><h2>当前返回JSON</h2>");
            sb.AppendLine("    <button class='btn-apply' onclick='refreshJson()' style='margin-bottom:8px;'>刷新</button>");
            sb.AppendLine("    <div class='json-preview' id='jsonPreview'>加载中...</div>");
            sb.AppendLine("  </div>");

            // 日志
            sb.AppendLine("  <div class='section'><h2>日志</h2>");
            sb.AppendLine("    <table class='log-table'>");
            sb.AppendLine("      <thead><tr><th>#</th><th>时间</th><th>设备数</th><th>关键数据</th><th>耗时</th></tr></thead>");
            sb.AppendLine("      <tbody id='logTable'></tbody>");
            sb.AppendLine("    </table>");
            sb.AppendLine("  </div>");
            sb.AppendLine("</div>");

            // JavaScript
            sb.AppendLine("<script>");
            sb.AppendLine("var scenarioNames={'machining':'正常加工','same_part':'同一零件','idle':'待机','program_change':'换零件','manual_reset':'手动清零','power_off':'断电','power_on':'恢复开机','pause':'暂停'};");
            sb.AppendLine("var runNames={0:'待机',1:'运行',3:'加工中'};");

            // 刷新统计
            sb.AppendLine("function refreshStats(){");
            sb.AppendLine("  fetch('/admin/api/stats').then(r=>r.json()).then(st=>{");
            sb.AppendLine("    document.getElementById('statsGrid').innerHTML=");
            sb.AppendLine("      '<div class=\"stat-item\"><div class=\"value\">'+st.totalDevices+'</div><div class=\"label\">总设备数</div></div>';");
            sb.AppendLine("    var sg=document.getElementById('statsGrid');");
            sb.AppendLine("    sg.innerHTML+='<div class=\"stat-item\"><div class=\"value\">'+st.onlineDevices+'</div><div class=\"label\">在线设备</div></div>';");
            sb.AppendLine("    sg.innerHTML+='<div class=\"stat-item\"><div class=\"value\">'+st.totalParts+'</div><div class=\"label\">总加工零件</div></div>';");
            // 零件统计表
            sb.AppendLine("    var pt=document.getElementById('partsTable');pt.innerHTML='';");
            sb.AppendLine("    var devs=st.partsByDevice;");
            sb.AppendLine("    Object.keys(devs).forEach(function(code){");
            sb.AppendLine("      var d=devs[code];");
            sb.AppendLine("      var progs=d.programs||{};");
            sb.AppendLine("      Object.keys(progs).forEach(function(prog){");
            sb.AppendLine("        pt.innerHTML+='<tr><td>'+code+'</td><td>'+d.desc+'</td><td>'+prog+'</td><td>'+progs[prog]+'</td><td>'+(prog===d.currentProgram?d.currentPartCount:'-')+'</td></tr>';");
            sb.AppendLine("      });");
            sb.AppendLine("    });");
            sb.AppendLine("  }).catch(function(){});");
            sb.AppendLine("}");

            // 刷新设备卡片
            sb.AppendLine("function refresh(){");
            sb.AppendLine("  fetch('/admin/api/status').then(r=>r.json()).then(data=>{");
            sb.AppendLine("    var cards=document.getElementById('deviceCards');cards.innerHTML='';");
            sb.AppendLine("    data.devices.forEach(function(d){");
            sb.AppendLine("      var cls=d.isOnline?'':'offline';");
            sb.AppendLine("      var scName=scenarioNames[d.scenario]||d.scenario;");
            sb.AppendLine("      var h='<div class=\"device-card '+cls+'\">';");
            sb.AppendLine("      h+='<h3>'+d.deviceCode+' '+d.desc+(d.isOnline?'':' (离线)')+'</h3>';");
            sb.AppendLine("      h+='<div class=\"info\">';");
            sb.AppendLine("      h+='场景:'+scName+' ('+d.scenarioTick+'/'+d.scenarioDuration+') 程序:'+d.programName+' 零件:'+d.partCount+' 状态:'+runNames[d.runStatus];");
            sb.AppendLine("      h+='</div>';");
            sb.AppendLine("      h+='<div class=\"actions\" data-device=\"'+d.deviceCode+'\">';");
            sb.AppendLine("      h+='<button data-event=\"program_change\">换零件</button>';");
            sb.AppendLine("      h+='<button data-event=\"manual_reset\">清零</button>';");
            sb.AppendLine("      h+='<button data-event=\"power_off\">断电</button>';");
            sb.AppendLine("      h+='<button data-event=\"pause\">暂停</button>';");
            sb.AppendLine("      h+='<button data-event=\"power_on\">恢复</button>';");
            sb.AppendLine("      h+='<button data-event=\"machining\">加工</button>';");
            sb.AppendLine("      h+='<button class=\"btn-remove\" onclick=\"removeDevice(\\''+d.deviceCode+'\\')\">移除</button>';");
            sb.AppendLine("      h+='</div></div>';");
            sb.AppendLine("      cards.innerHTML+=h;");
            sb.AppendLine("    });");
            sb.AppendLine("    document.querySelectorAll('.device-card .actions button[data-event]').forEach(function(btn){");
            sb.AppendLine("      btn.onclick=function(){var dev=this.parentElement.getAttribute('data-device');var evt=this.getAttribute('data-event');triggerEvent(dev,evt);};");
            sb.AppendLine("    });");
            sb.AppendLine("  }).catch(function(){});");
            sb.AppendLine("}");

            sb.AppendLine("function refreshJson(){fetch('/data').then(r=>r.text()).then(json=>{try{document.getElementById('jsonPreview').textContent=JSON.stringify(JSON.parse(json),null,2);}catch(e){document.getElementById('jsonPreview').textContent=json;}}).catch(function(e){document.getElementById('jsonPreview').textContent='请求失败:'+e.message;});}");

            sb.AppendLine("function refreshLogs(){fetch('/admin/api/logs').then(r=>r.json()).then(logs=>{var tb=document.getElementById('logTable');tb.innerHTML='';logs.forEach(function(l){tb.innerHTML+='<tr><td>'+l.index+'</td><td>'+l.timestamp+'</td><td>'+l.deviceCount+'</td><td>'+l.keyData+'</td><td>'+l.duration+'ms</td></tr>';});}).catch(function(){});}");

            sb.AppendLine("function triggerEvent(dev,evt){fetch('/admin/api/event',{method:'POST',headers:{'Content-Type':'application/json'},body:JSON.stringify({deviceId:dev,eventType:evt})}).then(function(){setTimeout(function(){refresh();refreshStats();},500);});}");
            sb.AppendLine("function addDevice(){var code=document.getElementById('addDeviceCode').value;var desc=document.getElementById('addDeviceDesc').value;if(!code)return;fetch('/admin/api/add-device',{method:'POST',headers:{'Content-Type':'application/json'},body:JSON.stringify({deviceCode:code,desc:desc})}).then(function(){refresh();refreshStats();});}");
            sb.AppendLine("function removeDevice(code){if(!confirm('确定移除设备'+code+'？'))return;fetch('/admin/api/remove-device',{method:'POST',headers:{'Content-Type':'application/json'},body:JSON.stringify({deviceCode:code})}).then(function(){refresh();refreshStats();});}");
            sb.AppendLine("function startSim(){fetch('/admin/api/start',{method:'POST'}).then(function(){refresh();});}");
            sb.AppendLine("function stopSim(){fetch('/admin/api/stop',{method:'POST'}).then(function(){refresh();});}");
            sb.AppendLine("function setInterval2(){var v=document.getElementById('intervalInput').value;fetch('/admin/api/interval',{method:'POST',headers:{'Content-Type':'application/json'},body:JSON.stringify({value:parseInt(v)})}).then(function(){});}");
            sb.AppendLine("function setNetwork(type){fetch('/admin/api/network',{method:'POST',headers:{'Content-Type':'application/json'},body:JSON.stringify({type:type})}).then(function(){});}");
            sb.AppendLine("document.querySelectorAll('input[name=mode]').forEach(function(r){r.addEventListener('change',function(){fetch('/admin/api/mode',{method:'POST',headers:{'Content-Type':'application/json'},body:JSON.stringify({mode:this.value})}).then(function(){});});});");

            sb.AppendLine("setInterval(function(){refresh();refreshStats();refreshLogs();refreshJson();},2000);");
            sb.AppendLine("refresh();refreshStats();refreshLogs();refreshJson();");
            sb.AppendLine("</script></body></html>");
            return sb.ToString();
        }
    }
}
