const state = {
  history: [],
  lastTables: [],
  liveTrace: [],
  selectedToolName: ""
};

const els = {
  messages: document.querySelector("#messages"),
  form: document.querySelector("#chatForm"),
  input: document.querySelector("#messageInput"),
  inputCount: document.querySelector("#inputCount"),
  sendBtn: document.querySelector("#sendBtn"),
  statusDot: document.querySelector("#statusDot"),
  sessionStatus: document.querySelector("#sessionStatus"),
  mcpStatus: document.querySelector("#mcpStatus"),
  mcpEndpoint: document.querySelector("#mcpEndpoint"),
  toolCount: document.querySelector("#toolCount"),
  toolList: document.querySelector("#toolList"),
  traceList: document.querySelector("#traceList"),
  refreshBtn: document.querySelector("#refreshBtn")
};

boot();

function boot() {
  addAssistantMessage(
    "你好，我是市民请集合智能助手 Web 测试版。你可以直接问业务系统里的订单、商品、会员、物流、月结等问题；我会先判断是否需要调用 MCP、数据库只读查询或 DeepSeek，再把结果整理成结论、依据和表格。"
  );
  bindEvents();
  refreshStatus();
}

function bindEvents() {
  els.form.addEventListener("submit", (event) => {
    event.preventDefault();
    sendMessage();
  });
  els.input.addEventListener("input", () => {
    updateInputCount();
  });
  els.input.addEventListener("keydown", (event) => {
    if (event.key === "Enter" && (event.ctrlKey || event.metaKey)) {
      event.preventDefault();
      sendMessage();
    }
  });
  if (els.refreshBtn) {
    els.refreshBtn.addEventListener("click", refreshStatus);
  }
  document.querySelector("[data-scroll-tools]").addEventListener("click", () => {
    document.querySelector("#toolsPanel").scrollIntoView({ behavior: "smooth" });
  });
  document.querySelector("[data-scroll-trace]").addEventListener("click", () => {
    document.querySelector("#tracePanel").scrollIntoView({ behavior: "smooth" });
  });
}

async function refreshStatus() {
  setStatus("checking", "检查中", "MCP 连接检测中");
  try {
    const health = await getJson("/api/health");
    const tools = await getJson("/api/tools");
    const mcp = health.mcp || {};
    if (els.mcpEndpoint) {
      els.mcpEndpoint.textContent = mcp.path ? `${mcp.name || "mcp"} ${mcp.path}` : "-";
    }
    if (els.toolCount) {
      els.toolCount.textContent = `${tools.tools?.length || 0} 个`;
    }
    renderTools(tools.tools || []);
    if (health.ok) {
      setStatus("ok", "已连接", `${mcp.environmentName || "MCP"} 可用`);
    } else {
      setStatus("error", "未连接", mcp.message || "MCP 不可用");
    }
  } catch (error) {
    setStatus("error", "未连接", error.message || "状态检查失败");
  }
}

function setStatus(mode, title, detail) {
  els.statusDot.classList.toggle("ok", mode === "ok");
  els.statusDot.classList.toggle("error", mode === "error");
  els.sessionStatus.textContent = title;
  els.mcpStatus.textContent = detail;
}

async function sendMessage() {
  const message = els.input.value.trim();
  if (!message) {
    return;
  }

  addUserMessage(message);
  els.input.value = "";
  updateInputCount();
  state.liveTrace = [];
  setBusy(true);
  const progressId = addProgressMessage("正在分析这个需求", "我会先判断是否需要查业务系统、数据库或外部工具。");

  try {
    let result;
    try {
      result = await streamChat(message, state.history.slice(-12), progressId);
    } catch (streamError) {
      updateProgressMessage(progressId, "流式连接不可用", "正在切换为普通请求完成本次回答。");
      const response = await postJson("/api/chat", {
        message,
        history: state.history.slice(-12)
      });
      if (!response.ok) {
        throw new Error(response.message || "请求失败");
      }
      result = response.result;
    }

    removeMessage(progressId);
    addAssistantMessage(result.content, result.tables || []);
    renderTrace(result.trace || state.liveTrace, result.toolCalls || []);
    state.history.push({ role: "user", content: message });
    state.history.push({ role: "assistant", content: result.content });
  } catch (error) {
    removeMessage(progressId);
    addAssistantMessage(`暂时无法完成：${error.message || error}`);
  } finally {
    setBusy(false);
  }
}

async function streamChat(message, history, progressId) {
  const response = await fetch("/api/chat/stream", {
    method: "POST",
    headers: {
      "Content-Type": "application/json"
    },
    body: JSON.stringify({ message, history })
  });
  if (!response.ok) {
    const payload = await response.json().catch(() => ({}));
    throw new Error(payload.message || `HTTP ${response.status}`);
  }
  if (!response.body) {
    throw new Error("当前浏览器不支持流式响应");
  }

  const reader = response.body.getReader();
  const decoder = new TextDecoder("utf-8");
  let buffer = "";
  let resultPayload = null;

  while (true) {
    const { done, value } = await reader.read();
    if (done) {
      break;
    }
    buffer += decoder.decode(value, { stream: true });
    const lines = buffer.split(/\r?\n/);
    buffer = lines.pop() || "";
    for (const line of lines) {
      if (!line.trim()) {
        continue;
      }
      const event = JSON.parse(line);
      if (event.type === "status") {
        updateProgressMessage(progressId, event.payload?.title || "正在处理", event.payload?.detail || "");
      } else if (event.type === "trace") {
        const trace = event.payload || {};
        state.liveTrace.push(trace);
        updateProgressMessage(progressId, trace.title || "正在处理", trace.detail || "");
        renderTrace(state.liveTrace, []);
      } else if (event.type === "result") {
        resultPayload = event.payload;
      } else if (event.type === "error") {
        throw new Error(event.payload?.message || "流式请求失败");
      }
    }
  }

  if (!resultPayload) {
    throw new Error("没有收到 Agent 结果");
  }
  return resultPayload;
}

function setBusy(busy) {
  els.sendBtn.disabled = busy;
  els.sendBtn.querySelector(".send-text").textContent = busy ? "处理中" : "发送";
}

function addUserMessage(content) {
  appendMessage({ role: "user", content });
}

function addAssistantMessage(content, tables = []) {
  appendMessage({ role: "assistant", content, tables });
}

function addProgressMessage(title, detail) {
  const id = `msg-${Date.now()}-${Math.random().toString(16).slice(2)}`;
  const row = document.createElement("div");
  row.className = "message-row assistant";
  row.dataset.messageId = id;

  const avatar = document.createElement("div");
  avatar.className = "avatar";
  const img = document.createElement("img");
  img.src = "/assets/logo.png";
  img.alt = "";
  avatar.appendChild(img);

  const bubble = document.createElement("div");
  bubble.className = "bubble progress-bubble";
  const titleNode = document.createElement("strong");
  titleNode.className = "progress-title";
  titleNode.textContent = title;
  const detailNode = document.createElement("span");
  detailNode.className = "progress-detail";
  detailNode.textContent = detail;
  const dots = document.createElement("span");
  dots.className = "typing";
  dots.innerHTML = "<i></i><i></i><i></i>";
  bubble.append(titleNode, detailNode, dots);

  row.append(avatar, bubble);
  els.messages.appendChild(row);
  els.messages.scrollTop = els.messages.scrollHeight;
  return id;
}

function updateProgressMessage(id, title, detail) {
  const node = document.querySelector(`[data-message-id="${id}"]`);
  if (!node) {
    return;
  }
  const titleNode = node.querySelector(".progress-title");
  const detailNode = node.querySelector(".progress-detail");
  if (titleNode && title) {
    titleNode.textContent = title;
  }
  if (detailNode) {
    detailNode.textContent = detail || "";
  }
  els.messages.scrollTop = els.messages.scrollHeight;
}

function removeMessage(id) {
  const node = document.querySelector(`[data-message-id="${id}"]`);
  node?.remove();
}

function appendMessage({ id = "", role, content, tables = [] }) {
  const row = document.createElement("div");
  row.className = `message-row ${role}`;
  if (id) {
    row.dataset.messageId = id;
  }

  const avatar = document.createElement("div");
  avatar.className = "avatar";
  if (role === "assistant") {
    const img = document.createElement("img");
    img.src = "/assets/logo.png";
    img.alt = "";
    avatar.appendChild(img);
  } else {
    avatar.textContent = "我";
  }

  const bubble = document.createElement("div");
  bubble.className = "bubble";
  bubble.textContent = content;

  if (tables.length) {
    state.lastTables = tables;
    tables.forEach((table, index) => {
      bubble.appendChild(renderTable(table, index));
    });
  }

  row.append(avatar, bubble);
  els.messages.appendChild(row);
  els.messages.scrollTop = els.messages.scrollHeight;
}

function renderTable(table, index) {
  const card = document.createElement("div");
  card.className = "table-card";

  const head = document.createElement("div");
  head.className = "table-head";
  const title = document.createElement("strong");
  title.textContent = table.title || "结果表格";
  const download = document.createElement("button");
  download.type = "button";
  download.textContent = "下载 CSV";
  download.addEventListener("click", () => downloadCsv(table, index));
  head.append(title, download);

  const wrap = document.createElement("div");
  wrap.className = "table-wrap";
  const el = document.createElement("table");
  const thead = document.createElement("thead");
  const tr = document.createElement("tr");
  for (const column of table.columns || []) {
    const th = document.createElement("th");
    th.textContent = column;
    tr.appendChild(th);
  }
  thead.appendChild(tr);
  el.appendChild(thead);

  const tbody = document.createElement("tbody");
  for (const row of table.rows || []) {
    const bodyTr = document.createElement("tr");
    for (const column of table.columns || []) {
      const td = document.createElement("td");
      td.textContent = row[column] ?? "";
      bodyTr.appendChild(td);
    }
    tbody.appendChild(bodyTr);
  }
  el.appendChild(tbody);
  wrap.appendChild(el);
  card.append(head, wrap);
  return card;
}

function downloadCsv(table, index) {
  const rows = [
    table.columns,
    ...(table.rows || []).map((row) => table.columns.map((column) => row[column] ?? ""))
  ];
  const csv = rows.map((row) => row.map(csvCell).join(",")).join("\r\n");
  const blob = new Blob(["\ufeff", csv], { type: "text/csv;charset=utf-8" });
  const url = URL.createObjectURL(blob);
  const link = document.createElement("a");
  link.href = url;
  link.download = `${safeFileName(table.title || "agent-table")}-${index + 1}.csv`;
  link.click();
  URL.revokeObjectURL(url);
}

function csvCell(value) {
  const text = String(value ?? "");
  return `"${text.replace(/"/g, '""')}"`;
}

function safeFileName(value) {
  return String(value).replace(/[\\/:*?"<>|]+/g, "_").slice(0, 60);
}

function renderTools(tools) {
  els.toolList.innerHTML = "";
  for (const tool of tools) {
    const item = document.createElement("button");
    item.type = "button";
    item.className = "tool-item";
    item.dataset.toolName = tool.name;
    item.title = "点击后将工具调用意图填入输入框";
    if (state.selectedToolName === tool.name) {
      item.classList.add("active");
    }
    const title = document.createElement("strong");
    title.textContent = tool.title || tool.name;
    const desc = document.createElement("span");
    desc.textContent = `${tool.name}${tool.description ? ` - ${tool.description}` : ""}`;
    const params = document.createElement("small");
    params.textContent = summarizeToolParams(tool);
    item.append(title, desc, params);
    item.addEventListener("click", () => selectTool(tool));
    els.toolList.appendChild(item);
  }
}

function selectTool(tool) {
  state.selectedToolName = tool.name;
  els.toolList.querySelectorAll(".tool-item").forEach((node) => {
    node.classList.toggle("active", node.dataset.toolName === tool.name);
  });

  els.input.value = buildToolPrompt(tool);
  updateInputCount();
  els.input.focus();
  addAssistantMessage(buildToolSelectionMessage(tool));
}

function summarizeToolParams(tool) {
  const schema = tool.inputSchema || {};
  const properties = schema.properties || {};
  const keys = Object.keys(properties);
  if (!keys.length) {
    return "无参数，点击后可直接发送";
  }
  const required = new Set(schema.required || []);
  const requiredKeys = keys.filter((key) => required.has(key));
  const optionalKeys = keys.filter((key) => !required.has(key));
  const parts = [];
  if (requiredKeys.length) {
    parts.push(`必填：${requiredKeys.join("、")}`);
  }
  if (optionalKeys.length) {
    parts.push(`可选：${optionalKeys.join("、")}`);
  }
  return parts.join("；");
}

function buildToolPrompt(tool) {
  const schema = tool.inputSchema || {};
  const properties = schema.properties || {};
  const keys = Object.keys(properties);
  const title = tool.title || tool.name;
  if (!keys.length) {
    return `使用「${title}」`;
  }
  const required = new Set(schema.required || []);
  const params = keys.map((key) => {
    const label = required.has(key) ? "必填" : "可选";
    const description = properties[key]?.description || "";
    return `${key}（${label}：${description}）=`;
  });
  return `使用「${title}」，${params.join("；")}`;
}

function buildToolSelectionMessage(tool) {
  const schema = tool.inputSchema || {};
  const properties = schema.properties || {};
  const keys = Object.keys(properties);
  const title = tool.title || tool.name;
  const lines = [
    `已选择工具：${title}`,
    tool.description || "",
    `工具名：${tool.name}`
  ].filter(Boolean);

  if (keys.length) {
    const required = new Set(schema.required || []);
    const params = keys.map((key) => {
      const label = required.has(key) ? "必填" : "可选";
      const description = properties[key]?.description || properties[key]?.type || "";
      return `- ${key}（${label}）：${description}`;
    });
    lines.push(`参数：\n${params.join("\n")}`);
    lines.push("我已把参数模板放到输入框，补齐后发送即可。");
  } else {
    lines.push("这个工具不需要参数，我已把可直接发送的指令放到输入框。");
  }
  return lines.join("\n\n");
}

function updateInputCount() {
  els.inputCount.textContent = `${els.input.value.trim().length} 字`;
}

function renderTrace(trace, toolCalls) {
  els.traceList.innerHTML = "";
  const rows = trace.length ? trace : toolCalls.map((item) => ({
    phase: item.ok ? "tool" : "error",
    title: item.name,
    detail: item.error || `${item.durationMs || 0}ms`
  }));

  for (const item of rows.slice(-12).reverse()) {
    const node = document.createElement("div");
    node.className = `trace-item phase-${item.phase}`;
    const title = document.createElement("strong");
    title.textContent = item.title || item.phase;
    const detail = document.createElement("span");
    detail.textContent = item.detail || item.at || "";
    node.append(title, detail);
    els.traceList.appendChild(node);
  }
}

async function getJson(url) {
  const response = await fetch(url);
  const payload = await response.json();
  if (!response.ok) {
    throw new Error(payload.message || `HTTP ${response.status}`);
  }
  return payload;
}

async function postJson(url, body) {
  const response = await fetch(url, {
    method: "POST",
    headers: {
      "Content-Type": "application/json"
    },
    body: JSON.stringify(body)
  });
  const payload = await response.json();
  if (!response.ok) {
    throw new Error(payload.message || `HTTP ${response.status}`);
  }
  return payload;
}
