/**
 * 实例数据看板:拉 /api/instance/dashboard 渲染只读表格.
 * 各区块无数据时不展示;有数据按表格展示.
 */
(function (global) {
  const SECTION_ORDER = ["orders", "keys", "strategy", "options", "hedge_plan"];
  let loading = false;
  let timer = null;

  function root() {
    const active = document.querySelector('.embed-tab-pane.is-active-pane [data-inst-dashboard="1"]');
    if (active) return active;
    return document.getElementById("instance-dashboard");
  }

  function escapeHtml(s) {
    return String(s == null ? "" : s)
      .replace(/&/g, "&amp;")
      .replace(/</g, "&lt;")
      .replace(/>/g, "&gt;")
      .replace(/"/g, "&quot;");
  }

  function fmtNum(v) {
    if (v == null || v === "") return "—";
    const n = Number(v);
    if (!Number.isFinite(n)) return escapeHtml(v);
    return String(n);
  }

  function fmtPnl(v) {
    if (v == null || v === "") return "—";
    const n = Number(v);
    if (!Number.isFinite(n)) return "—";
    const cls = n > 0 ? "pos-pnl-profit" : n < 0 ? "pos-pnl-loss" : "";
    const sign = n > 0 ? "+" : "";
    return '<span class="' + cls + '">' + sign + n.toFixed(2) + "U</span>";
  }

  function fmtPnlPlain(v) {
    if (v == null || v === "") return "—";
    const n = Number(v);
    if (!Number.isFinite(n)) return "—";
    const cls = n > 0 ? "pos-pnl-profit" : n < 0 ? "pos-pnl-loss" : "";
    return '<span class="' + cls + '">' + n.toFixed(2) + "</span>";
  }

  function dirCell(it) {
    const d = String(it.direction || "").toLowerCase();
    const label = it.direction_label || (d === "short" ? "做空" : d === "long" ? "做多" : "-");
    const cls = d === "short" ? "inst-dash-dir-short" : d === "long" ? "inst-dash-dir-long" : "";
    return '<td class="' + cls + '">' + escapeHtml(label) + "</td>";
  }

  function fmtExpiry(ms) {
    const n = Number(ms);
    if (!Number.isFinite(n) || n <= 0) return "—";
    let fallback = "—";
    try {
      const d = new Date(n);
      if (!Number.isNaN(d.getTime())) {
        const pad = function (x) {
          return String(x).padStart(2, "0");
        };
        fallback =
          d.getFullYear() +
          "-" +
          pad(d.getMonth() + 1) +
          "-" +
          pad(d.getDate()) +
          " " +
          pad(d.getHours()) +
          ":" +
          pad(d.getMinutes());
      }
    } catch (_) {}
    return (
      '<span class="opt-expiry-cd" data-opt-exp-ms="' +
      escapeHtml(String(Math.floor(n))) +
      '">' +
      escapeHtml(fallback) +
      "</span>"
    );
  }

  function goTab(tab) {
    if (!tab) return;
    if (global.InstanceEmbed && typeof global.InstanceEmbed.loadTab === "function") {
      global.InstanceEmbed.loadTab(tab);
      return;
    }
    const pathMap = {
      trade: "/trade",
      key_monitor: "/key_monitor",
      strategy: "/strategy",
      options: "/options",
      hedge_plan: "/hedge-plan",
    };
    const path = pathMap[tab] || "/" + tab;
    location.href = path;
  }

  function tableWrap(headers, rowsHtml) {
    return (
      '<div class="inst-dash-table-wrap">' +
      '<table class="inst-dash-table">' +
      "<thead><tr>" +
      headers
        .map(function (h) {
          return "<th>" + escapeHtml(h) + "</th>";
        })
        .join("") +
      "</tr></thead>" +
      "<tbody>" +
      rowsHtml +
      "</tbody></table></div>"
    );
  }

  function rowClickAttrs(tab) {
    return ' class="inst-dash-row" data-dash-tab="' + escapeHtml(tab || "") + '" role="link" tabindex="0"';
  }

  function mergeOrderLive(items, orderPrices) {
    const map = {};
    (orderPrices || []).forEach(function (p) {
      if (p && p.id != null) map[String(p.id)] = p;
    });
    return (items || []).map(function (it) {
      const live = map[String(it.id)] || {};
      const mark =
        live.exchange_mark_price != null
          ? live.exchange_mark_price
          : live.price != null
            ? live.price
            : it.mark_price;
      const contracts =
        live.contracts != null
          ? live.contracts
          : live.order_amount != null
            ? live.order_amount
            : it.contracts;
      const entry =
        live.avg_entry_price != null
          ? live.avg_entry_price
          : it.entry;
      return Object.assign({}, it, {
        entry: entry,
        mark_price: mark,
        mark_display: live.price_display || null,
        contracts: contracts,
        tp_profit: live.reward_at_tp_usdt != null ? live.reward_at_tp_usdt : it.tp_profit,
        float_pnl: live.float_pnl != null ? live.float_pnl : it.float_pnl,
      });
    });
  }

  function renderOrdersTable(items) {
    const rows = items
      .map(function (it) {
        const sym = it.symbol || "-";
        const mark =
          it.mark_display != null && it.mark_display !== ""
            ? escapeHtml(it.mark_display)
            : fmtNum(it.mark_price);
        const tpProfit =
          it.tp_profit != null && Number.isFinite(Number(it.tp_profit))
            ? '<span class="pos-tp-profit">' + Number(it.tp_profit).toFixed(2) + "U</span>"
            : "—";
        return (
          "<tr" +
          rowClickAttrs(it.tab || "trade") +
          ">" +
          '<td class="td-symbol"><span class="inst-dash-sym-link">' +
          escapeHtml(sym) +
          "</span></td>" +
          dirCell(it) +
          "<td>" +
          fmtNum(it.entry) +
          "</td>" +
          "<td>" +
          mark +
          "</td>" +
          "<td>" +
          fmtNum(it.contracts) +
          "</td>" +
          "<td>" +
          tpProfit +
          "</td>" +
          "<td>" +
          fmtPnlPlain(it.float_pnl) +
          "</td>" +
          "<td>—</td>" +
          "</tr>"
        );
      })
      .join("");
    return tableWrap(
      ["合约", "方向", "开仓价", "标记价", "张数", "盈利金额", "浮盈", "操作"],
      rows
    );
  }

  function renderKeysTable(items) {
    const rows = items
      .map(function (it) {
        return (
          "<tr" +
          rowClickAttrs(it.tab || "key_monitor") +
          ">" +
          "<td>" +
          escapeHtml(it.symbol || "-") +
          "</td>" +
          dirCell(it) +
          "<td>" +
          escapeHtml(it.subtitle || "—") +
          "</td>" +
          "<td>" +
          fmtNum(it.upper) +
          "</td>" +
          "<td>" +
          fmtNum(it.lower) +
          "</td>" +
          "</tr>"
        );
      })
      .join("");
    return tableWrap(["合约", "方向", "信号", "上沿", "下沿"], rows);
  }

  function renderStrategyTable(items) {
    const rows = items
      .map(function (it) {
        const kindLabel = it.kind === "roll" ? "顺势加仓" : it.kind === "trend" ? "趋势回调" : "策略";
        return (
          "<tr" +
          rowClickAttrs(it.tab || "strategy") +
          ">" +
          "<td>" +
          escapeHtml(kindLabel) +
          "</td>" +
          "<td>" +
          escapeHtml(it.symbol || "-") +
          "</td>" +
          dirCell(it) +
          "<td>" +
          escapeHtml(it.status || "—") +
          "</td>" +
          "<td>" +
          fmtNum(it.entry) +
          "</td>" +
          "</tr>"
        );
      })
      .join("");
    return tableWrap(["类型", "合约", "方向", "状态", "入场"], rows);
  }

  function renderOptionsTable(items) {
    const rows = items
      .map(function (it) {
        const opt = it.opt_type_label ||
          (String(it.opt_type || "").toUpperCase() === "C"
            ? "Call"
            : String(it.opt_type || "").toUpperCase() === "P"
              ? "Put"
              : it.opt_type || "—");
        return (
          "<tr" +
          rowClickAttrs(it.tab || "options") +
          ">" +
          "<td>" +
          escapeHtml(it.inst_id || it.title || "-") +
          "</td>" +
          "<td>" +
          escapeHtml(it.source_label || "纯期权") +
          "</td>" +
          "<td>" +
          escapeHtml(opt) +
          "</td>" +
          "<td>" +
          fmtNum(it.pos) +
          "</td>" +
          "<td>" +
          fmtExpiry(it.exp_time_ms) +
          "</td>" +
          "<td>" +
          escapeHtml(it.target_monitor || "—") +
          "</td>" +
          "<td>" +
          fmtPnl(it.pnl) +
          "</td>" +
          "</tr>"
        );
      })
      .join("");
    return tableWrap(["合约", "来源", "类型", "张数", "到期时间", "目标监控", "盈亏"], rows);
  }

  function renderHedgeTable(items) {
    const rows = items
      .map(function (it) {
        const stCls = it.status_active ? "inst-dash-status-active" : "";
        const stText = it.status_label || (it.status_active ? "进行中" : it.status || "—");
        return (
          "<tr" +
          rowClickAttrs(it.tab || "hedge_plan") +
          ">" +
          "<td>#" +
          escapeHtml(it.id != null ? it.id : "—") +
          "</td>" +
          "<td>" +
          escapeHtml(it.underlying || "-") +
          "</td>" +
          "<td>" +
          escapeHtml(it.plan_type_label || it.plan_type || "—") +
          "</td>" +
          '<td class="' +
          stCls +
          '">' +
          escapeHtml(stText) +
          "</td>" +
          "<td>" +
          escapeHtml(it.contracts_summary || it.subtitle || "—") +
          "</td>" +
          "</tr>"
        );
      })
      .join("");
    return tableWrap(["ID", "标的", "计划类型", "状态", "说明"], rows);
  }

  function renderTable(key, items) {
    if (key === "orders") return renderOrdersTable(items);
    if (key === "keys") return renderKeysTable(items);
    if (key === "strategy") return renderStrategyTable(items);
    if (key === "options") return renderOptionsTable(items);
    if (key === "hedge_plan") return renderHedgeTable(items);
    return "";
  }

  function sectionHasData(sec) {
    if (!sec) return false;
    const count = Number(sec.count);
    if (Number.isFinite(count) && count > 0) return true;
    return Array.isArray(sec.items) && sec.items.length > 0;
  }

  function renderSection(key, sec) {
    if (!sectionHasData(sec)) return "";
    const items = sec.items || [];
    const count = Number(sec.count) || items.length;
    return (
      '<section class="inst-dash-section" data-dash-section="' +
      escapeHtml(key) +
      '">' +
      '<div class="inst-dash-section-head">' +
      "<h3>" +
      escapeHtml(sec.title || key) +
      ' <span class="inst-dash-count">' +
      count +
      "</span></h3>" +
      '<button type="button" class="btn-sm inst-dash-goto" data-dash-tab="' +
      escapeHtml(sec.tab || "") +
      '">打开</button>' +
      "</div>" +
      renderTable(key, items) +
      "</section>"
    );
  }

  function bindClicks(el) {
    if (!el) return;
    el.querySelectorAll("[data-dash-tab]").forEach(function (node) {
      const handler = function () {
        goTab(node.getAttribute("data-dash-tab"));
      };
      node.addEventListener("click", handler);
      node.addEventListener("keydown", function (ev) {
        if (ev.key === "Enter" || ev.key === " ") {
          ev.preventDefault();
          handler();
        }
      });
    });
  }

  async function load(opts) {
    const el = root();
    if (!el) return;
    const status = el.querySelector("#inst-dash-status") || document.getElementById("inst-dash-status");
    const sections = el.querySelector("#inst-dash-sections") || document.getElementById("inst-dash-sections");
    const updated = el.querySelector("#inst-dash-updated") || document.getElementById("inst-dash-updated");
    if (loading) return;
    loading = true;
    if (status && !(opts && opts.silent)) status.textContent = "加载中…";
    try {
      const [dashRes, priceRes] = await Promise.all([
        fetch("/api/instance/dashboard", { credentials: "same-origin" }),
        fetch("/api/price_snapshot", { credentials: "same-origin" }).catch(function () {
          return null;
        }),
      ]);
      const data = await dashRes.json().catch(function () {
        return {};
      });
      if (!dashRes.ok || !data.ok) {
        throw new Error(data.msg || dashRes.statusText || "加载失败");
      }
      let orderPrices = [];
      if (priceRes && priceRes.ok) {
        try {
          const snap = await priceRes.json();
          orderPrices = snap.order_prices || [];
        } catch (_) {}
      }
      if (data.orders && Array.isArray(data.orders.items)) {
        data.orders.items = mergeOrderLive(data.orders.items, orderPrices);
        data.orders.count = data.orders.items.length;
      }
      if (updated) updated.textContent = "更新 " + (data.updated_at || "—");
      if (sections) {
        const html = SECTION_ORDER.map(function (k) {
          return renderSection(k, data[k]);
        }).join("");
        sections.innerHTML =
          html || '<p class="inst-dash-empty muted">当前无活跃监控与持仓</p>';
        bindClicks(sections);
        if (global.OptionsExpiryCountdown) {
          if (typeof global.OptionsExpiryCountdown.tick === "function") {
            global.OptionsExpiryCountdown.tick(sections);
          }
          if (typeof global.OptionsExpiryCountdown.ensureTimer === "function") {
            global.OptionsExpiryCountdown.ensureTimer();
          }
        }
      }
      if (status) status.textContent = "";
    } catch (e) {
      if (status) status.textContent = e.message || "加载失败";
    } finally {
      loading = false;
    }
  }

  function stopAuto() {
    if (timer) {
      clearInterval(timer);
      timer = null;
    }
  }

  function startAuto() {
    stopAuto();
    timer = setInterval(function () {
      const el = root();
      if (!el) return;
      const pane = el.closest(".embed-tab-pane");
      if (pane && !pane.classList.contains("is-active-pane")) return;
      load({ silent: true });
    }, 15000);
  }

  function init(force) {
    const el = root();
    if (!el) return;
    if (!force && el.getAttribute("data-dash-booted") === "1") {
      load({ silent: true });
      startAuto();
      return;
    }
    el.setAttribute("data-dash-booted", "1");
    const btn = el.querySelector("#inst-dash-refresh") || document.getElementById("inst-dash-refresh");
    if (btn && !btn.getAttribute("data-bound")) {
      btn.setAttribute("data-bound", "1");
      btn.addEventListener("click", function () {
        load({});
      });
    }
    load({});
    startAuto();
  }

  function refreshSoft(opts) {
    load(Object.assign({ silent: true }, opts || {}));
  }

  global.InstanceDashboard = {
    init: init,
    refreshSoft: refreshSoft,
    load: load,
    stopAuto: stopAuto,
  };
})(window);
