// 全局变量,用于保存当前选中的节点数据
  let selectedNodeData = null;

  /**
   * 根据节点数据递归生成树形结构(返回 <li> 元素)
   * 假设节点数据格式:
   * {
   *   "node_name":node.name,
   *   "node_path":node.path,
   *   "node_status":node.status,
   *   "node_bwork":node.bwork,
   *   "node_vultype":node.vul_type,
   *   "node_vulgrade":node.vul_grade,
   *   children: [ { ... }, { ... } ]
   * }
   */
  function generateTreeHTML(nodeData) {
    const li = document.createElement("li");
    const nodeSpan = document.createElement("span");
    nodeSpan.className = "tree-node";
    //设置data属性
    nodeSpan.setAttribute("data-node_name", nodeData.node_name);
    nodeSpan.setAttribute("data-node_path", nodeData.node_path);
    nodeSpan.setAttribute("data-node_status", nodeData.node_status);
    nodeSpan.setAttribute("data-node_bwork", nodeData.node_bwork);
    nodeSpan.setAttribute("data-node_vultype", nodeData.node_vultype);
    nodeSpan.setAttribute("data-node_vulgrade", nodeData.node_vulgrade || "");
    nodeSpan.setAttribute("data-node_workstatus",nodeData.node_workstatus);
    if(nodeData.node_workstatus ===0){
      nodeSpan.classList.add("no-work");
    }else {
      nodeSpan.classList.remove("no-work");
    }
    // 根据漏洞级别添加样式
    if (nodeData.node_vulgrade) {
      nodeSpan.classList.remove("no-work");
      if (nodeData.node_vulgrade === "低危") {
        nodeSpan.classList.add("vul-low");
      } else if (nodeData.node_vulgrade === "中危") {
        nodeSpan.classList.add("vul-medium");
      } else if (nodeData.node_vulgrade === "高危") {
        nodeSpan.classList.add("vul-high");
      }
    }
    // 创建容器用于存放切换图标与文本
    const container = document.createElement("div");
    container.className = "node-container";
    // 如果有子节点,则添加切换图标
    if (nodeData.children && nodeData.children.length > 0) {
      const toggleIcon = document.createElement("span");
      toggleIcon.className = "toggle-icon";
      toggleIcon.textContent = "-"; // 默认展开时显示“-”
      container.appendChild(toggleIcon);
    }
    //节点文本
    const textSpan = document.createElement("span");
    textSpan.className = "node-text";
    textSpan.textContent = nodeData.node_name;
    container.appendChild(textSpan);
    nodeSpan.appendChild(container);
    li.appendChild(nodeSpan);
    //如果存在子节点,递归生成子节点列表
    if (nodeData.children && nodeData.children.length > 0) {
      const ul = document.createElement("ul");
      nodeData.children.forEach((child) => {
        ul.appendChild(generateTreeHTML(child));
      });
      li.appendChild(ul);
    }
    return li;
  }

  // 绑定所有节点的点击事件
  function bindTreeNodeEvents() {
    document.querySelectorAll(".tree-node").forEach((el) => {
      el.addEventListener("click", (event) => {
        // 阻止事件冒泡,避免点击时展开折叠影响
        event.stopPropagation();
        // 清除之前选中的节点样式
        document
          .querySelectorAll(".tree-node.selected")
          .forEach((node) => node.classList.remove("selected"));
        // 当前节点标记为选中
        el.classList.add("selected");
        // 读取 data 属性更新右侧显示
        const nodeName = el.getAttribute("data-node_name");
        const status = el.getAttribute("data-node_status");
        const nodepath = el.getAttribute("data-node_path");
        const nodebwork = el.getAttribute("data-node_bwork");
        const vulType = el.getAttribute("data-node_vultype");
        const vulLevel = el.getAttribute("data-node_vulgrade");
        const workstatus = el.getAttribute("data-node_workstatus");
        //selectedNodeData = { nodeName, status, vulType, vulLevel,nodepath,nodebwork };
        // 示例中默认填充
        selectedNodeData = {
          node_name: nodeName,
          node_path: nodepath,
          status: status,
          node_bwork: nodebwork,
          vul_type: vulType,
          vul_grade: vulLevel  || "-",
          workstatus: workstatus
        };
        //刷新界面内容
        update_select_node_data_show(nodeName,status,vulType,vulLevel,workstatus,nodebwork)
      });
      // 双击事件:展开/收缩子节点区域
      el.addEventListener("dblclick", (event) => {
        event.stopPropagation();
        // 找到该节点下的 <ul> 子节点列表
        const parentLi = el.parentElement;
        const childUl = parentLi.querySelector("ul");
        if (childUl) {
          // 切换 collapsed 类,控制 display
          childUl.classList.toggle("collapsed");
          // 更新切换图标
          const toggleIcon = el.querySelector(".toggle-icon");
          if (toggleIcon) {
            toggleIcon.textContent = childUl.classList.contains("collapsed")
              ? "+"
              : "-";
          }
        }
      });
    });
  }

  // 动态加载节点树数据
  async function loadNodeTree(task_id) {
    // 清空选中状态
    selectedNodeData = null;
    //刷新界面内容
    update_select_node_data_show("-","-","-","-","-",false)
    try {
      const res = await fetch("/api/task/gethistree", {
        method: "POST",
        headers: { "Content-Type": "application/json" },
        body: JSON.stringify({ task_id }),      //task_id:task_id
      });
      if (!res.ok) {
        const errorData = await res.json();
        throw new Error(errorData.error || `HTTP错误 ${res.status}`);
      }
      const data = await res.json();
      const treeData = data.tree;
      if (!treeData) {
        document.getElementById("treeContent").innerHTML =
          "<p>无节点数据</p>";
        return;
      }

      // 创建一个 <ul> 作为树的根容器
      const ul = document.createElement("ul");
      ul.className = "tree-root-ul";
      ul.appendChild(generateTreeHTML(treeData));
      // 替换节点树容器的内容
      const container = document.getElementById("treeContent");
      container.innerHTML = "";
      container.appendChild(ul);
      // 绑定节点点击事件
      bindTreeNodeEvents();
    } catch (error) {
      console.error("加载节点树失败:", error);
      document.getElementById("treeContent").innerHTML = "<p>加载节点树失败</p>";
    }
  }

  function getWorkStatus_Str(workstatus){
    strworkstatus = ""
    switch (workstatus){
      case 0:
        strworkstatus = "无待执行任务";
        break;
      case 1:
        strworkstatus = "待执行指令中";
        break;
      case 2:
        strworkstatus = "指令执行中";
        break;
      case 3:
        strworkstatus = "待提交llm中";
        break;
      case 4:
        strworkstatus = "提交llm中";
        break;
      default:
        strworkstatus = "-"
    }
    return strworkstatus
  }

  //根据web端过来的数据,更新节点的工作状态
  function updateTreeNode(node_path, node_workstatus) {
    // 根据 node_path 查找对应节点(假设每个 .tree-node 上设置了 data-node_path 属性)
    const nodeEl = document.querySelector(`.tree-node[data-node_path="${node_path}"]`);
    if (nodeEl) {
      // 更新 DOM 属性(属性值均为字符串)
      nodeEl.setAttribute("data-node_workstatus", node_workstatus);
      //判断是否需要更新界面
      if(selectedNodeData){
        if(node_path === selectedNodeData.node_path){ //只有是当前选中节点才更新数据
          selectedNodeData.workstatus = node_workstatus;
          strnew = getWorkStatus_Str(node_workstatus);
          document.getElementById("node_workstatus").textContent = strnew;
        }
      }
    } else {
      console.warn(`未找到节点 ${node_path}`);
    }
  }

  //刷新节点的数据显示
  function update_select_node_data_show(nodeName,testStatus,vulType,vulLevel,workStatus,nodebwork){
    document.getElementById("nodeName").textContent = nodeName;
    document.getElementById("testStatus").textContent = testStatus;
    document.getElementById("node_vulType").textContent = vulType;
    document.getElementById("node_vulLevel").textContent = vulLevel;
    str_workStatus = getWorkStatus_Str(Number(workStatus));
    document.getElementById("node_workstatus").textContent = str_workStatus;
    if(nodebwork==="true"){
      document.getElementById("node_bwork").textContent = "执行中";
    }else {
      document.getElementById("node_bwork").textContent = "暂停中";
    }
    setNodeBtnStatus();
  }

  //节点按钮的状态控制
  function setNodeBtnStatus(){
    const btn_VI = document.getElementById("btnViewInstr");
    if(!selectedNodeData){
      //没有选择node,按钮全部置不可用
      btn_VI.disabled = true;
      btn_VI.classList.add("disabled-btn");
    }
    else{
      btn_VI.disabled = false;
      btn_VI.classList.remove("disabled-btn");
    }
  }

  // // 刷新按钮事件绑定
  // document.getElementById("btnRefresh").addEventListener("click", () => {
  //   // 重新加载节点树数据
  //   loadNodeTree(cur_task_id);
  // });

  // 按钮事件:当未选中节点时提示
  function checkSelectedNode() {
    if (!selectedNodeData) {
      alert("请先选择节点");
      return false;
    }
    return true;
  }

  //----------------------查看节点--指令modal----------------------------
  let doneInstrs = []; // 已执行指令的所有数据
  let todoInstrs = []; // 待执行指令的所有数据
  let donePage = 1;    // 已执行指令当前页
  let todoPage = 1;    // 待执行指令当前页

  document.getElementById("btnViewInstr").addEventListener("click", () => {
    if (!checkSelectedNode()) return;
    openInstrModal()
  });
    // 打开对话框函数
  function openInstrModal() {
    const instrCanvas = new bootstrap.Offcanvas(document.getElementById('instrCanvas'));
    instrCanvas.show();

    // const modalEl = document.getElementById("instrModal");
    // // 假设用 Bootstrap 5 的 Modal 组件
    // const instrModal = new bootstrap.Modal(modalEl, {keyboard: false});
    // 显示对话框
    //instrModal.show();

    // 在打开 modal 时,先更新提示内容,将 loadingMsg 显示“请稍后,数据获取中…”
    const loadingMsg = document.getElementById("loadingMsg");
    if (loadingMsg) {
      loadingMsg.textContent = "请稍后,数据获取中...";
    }

    // 加载指令数据
    loadInstrData();
  }

  // 调用后端接口,获取指令数据
  async function loadInstrData() {
    task_id = cur_task_id;
    node_path = selectedNodeData.node_path;
    try {
      const res = await fetch("/api/task/hisnodegetinstr", {
        method: "POST",
        headers: { "Content-Type": "application/json" },
        body: JSON.stringify({task_id,node_path}),
      });
      if (!res.ok) {
        const errorData = await res.json();
        throw new Error(errorData.error || `HTTP错误 ${res.status}`);
      }
      const data = await res.json();
      // 数据获取成功后,清除加载提示
      const loadingMsg = document.getElementById("loadingMsg");
      if (loadingMsg) {
        loadingMsg.style.display = "none"; // 或者清空其 innerHTML
      }
      doneInstrs = data.doneInstrs || [];
      //todoInstrs = data.todoInstrs || [];
      donePage = 1;
      todoPage = 1;
      renderDoneInstrTable(donePage);
      //renderTodoInstrTable(todoPage);
    } catch (error) {
      console.error("加载指令数据异常:", error);
    }
  }

  // 渲染已执行指令表格
  function renderDoneInstrTable(page) {
    const tbody = document.getElementById("doneInstrTbody");
    // 计算起始索引
    const startIndex = (page - 1) * pageSize;
    const endIndex = startIndex + pageSize;
    const pageData = doneInstrs.slice(startIndex, endIndex);
//select instruction,start_time,result from task_result where task_id=%s and node_path=%s;
    tbody.innerHTML = "";
    // 插入行
    pageData.forEach((item, i) => {
      const tr = document.createElement("tr");

      // 第一列:序号
      const tdIndex = document.createElement("td");
      tdIndex.textContent = startIndex + i + 1;
      tr.appendChild(tdIndex);

      // 第二列:指令内容
      const tdInstr = document.createElement("td");
      tdInstr.textContent = item[0];
      tr.appendChild(tdInstr);

      // 第三列:开始时间(如果没有则显示空字符串)
      const tdStartTime = document.createElement("td");
      tdStartTime.textContent = item[1] || "";
      tr.appendChild(tdStartTime);

      // 第四列:执行结果
      const tdResult = document.createElement("td");
      tdResult.textContent = item[2] || "";
      tr.appendChild(tdResult);

      tbody.appendChild(tr);
    });

    // 若不足 10 行,补空行
    for (let i = pageData.length; i < pageSize; i++) {
      const tr = document.createElement("tr");
      tr.innerHTML = `
        <td>&nbsp;</td>
        <td>&nbsp;</td>
        <td>&nbsp;</td>
        <td>&nbsp;</td>
      `;
      tbody.appendChild(tr);
    }
  }

  // 渲染待执行指令表格
  function renderTodoInstrTable(page) {
    const tbody = document.getElementById("todoInstrTbody");
    const startIndex = (page - 1) * pageSize;
    const endIndex = startIndex + pageSize;
    const pageData = todoInstrs.slice(startIndex, endIndex);

    tbody.innerHTML = "";
    pageData.forEach((item, i) => {
      const tr = document.createElement("tr");
      const idx = startIndex + i + 1;
      // 第一列:序号
      const tdIndex = document.createElement("td");
      tdIndex.textContent = idx;
      tr.appendChild(tdIndex);

      // 第二列:指令文本内容(直接使用 textContent)
      const tdItem = document.createElement("td");
      tdItem.textContent = item;  // 使用 textContent 避免 HTML 解析
      tr.appendChild(tdItem);

      // 第三列:复制和删除按钮
      const tdAction = document.createElement("td");
      // const btn_cp = document.createElement("button");
      // btn_cp.className = "btn btn-primary btn-sm";
      // btn_cp.textContent = "复制";
      // btn_cp.style.marginRight = "2px"; // 设置间隔
      // btn_cp.onclick = () => confirmCopyTodoInstr(idx - 1);
      // tdAction.appendChild(btn_cp);
      const btn = document.createElement("button");
      btn.className = "btn btn-danger btn-sm";
      btn.textContent = "删除";
      btn.onclick = () => confirmDeleteTodoInstr(idx - 1);
      tdAction.appendChild(btn);
      tr.appendChild(tdAction);

      tbody.appendChild(tr);
    });

    // 补空行
    for (let i = pageData.length; i < pageSize; i++) {
      const tr = document.createElement("tr");
      tr.innerHTML = `
        <td>&nbsp;</td>
        <td>&nbsp;</td>
        <td>&nbsp;</td>
      `;
      tbody.appendChild(tr);
    }
  }

  // 分页事件
  document.getElementById("doneInstrPrev").addEventListener("click", (e) => {
    e.preventDefault();
    if (donePage > 1) {
      donePage--;
      renderDoneInstrTable(donePage);
    }
  });
  document.getElementById("doneInstrNext").addEventListener("click", (e) => {
    e.preventDefault();
    const maxPage = Math.ceil(doneInstrs.length / pageSize);
    if (donePage < maxPage) {
      donePage++;
      renderDoneInstrTable(donePage);
    }
  });
  document.getElementById("todoInstrPrev").addEventListener("click", (e) => {
    e.preventDefault();
    if (todoPage > 1) {
      todoPage--;
      renderTodoInstrTable(todoPage);
    }
  });
  document.getElementById("todoInstrNext").addEventListener("click", (e) => {
    e.preventDefault();
    const maxPage = Math.ceil(todoInstrs.length / pageSize);
    if (todoPage < maxPage) {
      todoPage++;
      renderTodoInstrTable(todoPage);
    }
  });

  // 导出当前页数据
  document.getElementById("btnExport").addEventListener("click", () => {
    // 判断当前是哪个 Tab
    const activeTab = document.querySelector("#instrTab button.nav-link.active");
    if (activeTab.id === "doneInstrTab") {
      exportCurrentPage(doneInstrs, donePage, ["序号", "执行指令", "执行时间", "执行结果"]);
    } else {
      exportCurrentPage(todoInstrs, todoPage, ["序号", "待执行指令"]);
    }
  });

  function exportCurrentPage(dataArr, page, headerArr) {
    const startIndex = (page - 1) * pageSize;
    const endIndex = startIndex + pageSize;
    const pageData = dataArr.slice(startIndex, endIndex);

    // 在 CSV 的开头加上 BOM,用于 Excel 识别 UTF-8 编码
    let csvContent = "\uFEFF" + headerArr.join(",") + "\n";
    pageData.forEach((item, i) => {
      const rowIndex = startIndex + i + 1;
      if (headerArr.length === 4) {
        // 已执行:序号,执行指令,执行时间,执行结果
        csvContent += rowIndex + "," +
                      (item.command || "") + "," +
                      (item.execTime || "") + "," +
                      (item.result || "") + "\n";
      } else {
        // 待执行:序号,待执行指令
        csvContent += rowIndex + "," + (item.command || "") + "\n";
      }
    });
    // 如果不足 pageSize 行,补足空行(根据列数进行适当补全)
    for (let i = pageData.length; i < pageSize; i++) {
      // 根据 headerArr.length 来设置空行的格式
      if (headerArr.length === 4) {
        csvContent += ",,,\n";
      } else {
        csvContent += ",\n";
      }
    }

    const blob = new Blob([csvContent], { type: "text/csv;charset=utf-8;" });
    const url = URL.createObjectURL(blob);
    const link = document.createElement("a");
    link.href = url;
    link.download = "指令导出.csv";
    link.click();
    URL.revokeObjectURL(url);
  }

//------------------测试数据和漏洞数据tab-------------------
// 复用:根据返回的数据数组渲染表格 tbody,保证固定 10 行
function renderTableRows(tbody, rowsData) {
  tbody.innerHTML = "";
  // 遍历数据行,生成 <tr>
  rowsData.forEach((row, index) => {
    const tr = document.createElement("tr");
    // 这里假设 row 为对象,包含各个字段;下标从1开始显示序号
    for (const cellData of Object.values(row)) {
      const td = document.createElement("td");
      td.textContent = cellData;
      tr.appendChild(td);
    }
    tbody.appendChild(tr);
  });
  // 补足空行
  const rowCount = rowsData.length;
  for (let i = rowCount; i < pageSize; i++) {
    const tr = document.createElement("tr");
    for (let j = 0; j < tbody.parentElement.querySelectorAll("th").length; j++) {
      const td = document.createElement("td");
      td.innerHTML = "&nbsp;";
      tr.appendChild(td);
    }
    tbody.appendChild(tr);
  }
}

//--------------------------测试指令-------------------------------
let allInstrs = [];
let currentInstrPage = 1;
function renderInstrPage(page) {
  currentInstrPage = page;
  const start = (page - 1) * pageSize;
  const end = start + pageSize;
  const pageData = allInstrs.slice(start, end);

  const tbody = document.querySelector("#instrTable tbody");
  renderTableRows(tbody, pageData);

  // 更新分页按钮
  document.getElementById("instrPrev").dataset.page = page > 1 ? page - 1 : 1;
  document.getElementById("instrNext").dataset.page = (end < allInstrs.length) ? page + 1 : page;
}

// 查询测试指令
async function searchInstructions(page = 1) {
  if(cur_task_id === 0){
    return;
  }
  const nodeName = document.getElementById("instrNodeName").value.trim();
  try {
    const res = await fetch("/api/task/getinstr", {
      method: "POST",
      headers: {
        "Content-Type": "application/json",
      },
      body: JSON.stringify({
        cur_task_id,
        nodeName
      }),
    });
    if (!res.ok) {
      const errorData = await res.json();
      throw new Error(errorData.error || `HTTP错误 ${res.status}`);
    }
    const data = await res.json();
    allInstrs = data.instrs;
    renderInstrPage(1); //显示第一页数据
  } catch (error) {
    console.error("获取测试指令失败:", error);
  }
}

//导出测试指令数据
async function ExportInstructions(){
  alert("导出指令功能实现中。。。")
}

// 绑定测试指令查询按钮事件
document.getElementById("instrSearchBtn").addEventListener("click", () => {
  searchInstructions();
});
// 绑定测试指令分页点击事件
document.getElementById("instrPrev").addEventListener("click", (e) => {
  const page = parseInt(e.target.dataset.page, 10);
  renderInstrPage(page);
});
document.getElementById("instrNext").addEventListener("click", (e) => {
  const page = parseInt(e.target.dataset.page, 10);
  renderInstrPage(page);;
});

//------------------漏洞数据---------------------------------
let allVuls = [];
let currentVulPage = 1;
function renderVulPage(page) {
  currentVulPage = page;
  const start = (page - 1) * pageSize;
  const end = start + pageSize;
  const pageData = allVuls.slice(start, end);

  const tbody = document.querySelector("#vulTable tbody");
  renderTableRows(tbody, pageData);

  // 更新分页按钮
  document.getElementById("vulPrev").dataset.page = page > 1 ? page - 1 : 1;
  document.getElementById("vulNext").dataset.page = (end < allVuls.length) ? page + 1 : page;
}

// 查询漏洞数据
async function searchVulnerabilities(page = 1) {
  if(cur_task_id === 0){return;}
  const nodeName = document.getElementById("vulNodeName").value.trim();
  const vulType = document.getElementById("vulType").value.trim();
  const vulLevel = document.getElementById("vulLevel").value;
  try {
    const res = await fetch("/api/task/getvul", {
      method: "POST",
      headers: {
        "Content-Type": "application/json",
      },
      body: JSON.stringify({
        cur_task_id,
        nodeName,
        vulType,
        vulLevel
      }),
    });
    if (!res.ok) {
      const errorData = await res.json();
      throw new Error(errorData.error || `HTTP错误 ${res.status}`);
    }
    const data = await res.json();
    allVuls = data.vuls;
    renderVulPage(1)
  } catch (error) {
    console.error("获取漏洞数据失败:", error);
  }
}

//导出漏洞数据
async function ExportVuls(){
  alert("导出漏洞功能实现中。。。")
}

// 绑定漏洞数据查询按钮事件
document.getElementById("vulSearchBtn").addEventListener("click", () => {
  searchVulnerabilities();
});
// 绑定漏洞数据分页点击事件
document.getElementById("vulPrev").addEventListener("click", (e) => {
  const page = parseInt(e.target.dataset.page, 10);
  renderVulPage(page);
});
document.getElementById("vulNext").addEventListener("click", (e) => {
  const page = parseInt(e.target.dataset.page, 10);
  renderVulPage(page);
});