import { useCallback, useEffect, useState } from "react";
import { apiFetch, type NodeCard } from "../api";

function pickStrategy(n: NodeCard) {
  const fleet = (n.fleet || {}) as Record<string, unknown>;
  const health = (n.health || {}) as Record<string, unknown>;
  const strat =
    (fleet.strategy as Record<string, unknown> | undefined) ||
    (health.strategy as Record<string, unknown> | undefined) ||
    {};
  const position =
    (fleet.position as Record<string, unknown> | undefined) || {};
  return {
    mode: String(fleet.mode || health.mode || "-"),
    running: strat.running,
    phase: String(strat.phase ?? "-"),
    rounds: strat.rounds_done,
    market: fleet.market_connected ?? health.market_connected,
    exchange: String(fleet.exchange || health.exchange || "-"),
    strat,
    position,
    pair: fleet.pair as Record<string, unknown> | null | undefined,
    index_px: fleet.index_px,
  };
}

function fmt(v: unknown, digits = 4): string {
  if (v == null || v === "") return "—";
  const n = Number(v);
  if (!Number.isFinite(n)) return String(v);
  return n.toFixed(digits);
}

function pnlClass(v: unknown): string {
  const n = Number(v);
  if (!Number.isFinite(n) || n === 0) return "pnl-flat";
  return n > 0 ? "pnl-pos" : "pnl-neg";
}

export default function MonitorPage() {
  const [nodes, setNodes] = useState<NodeCard[]>([]);
  const [err, setErr] = useState("");
  const [busy, setBusy] = useState<Record<number, string>>({});
  const [selected, setSelected] = useState<Set<number>>(new Set());
  const [pollSec, setPollSec] = useState(8);
  const [detailId, setDetailId] = useState<number | null>(null);

  const refresh = useCallback(async () => {
    try {
      const r = await apiFetch<{ nodes: NodeCard[] }>("/api/nodes/status/all");
      setNodes(r.nodes || []);
      setErr("");
    } catch (ex) {
      setErr(ex instanceof Error ? ex.message : String(ex));
    }
  }, []);

  useEffect(() => {
    apiFetch<{ poll_interval_sec?: number }>("/api/auth/me")
      .then((m) => {
        if (m.poll_interval_sec) setPollSec(m.poll_interval_sec);
      })
      .catch(() => undefined);
    void refresh();
    const id = window.setInterval(() => void refresh(), pollSec * 1000);
    return () => window.clearInterval(id);
  }, [refresh, pollSec]);

  async function act(id: number, action: "start" | "pause" | "update" | "login") {
    if (action === "update") {
      const node = nodes.find((x) => x.id === id);
      const name = node?.name || `#${id}`;
      const ok = window.confirm(
        `确认更新「${name}」代码？\n\n将 git pull 并 reload 策略进程，短暂中断 API；不会自动启动策略。\n请勿误点。`,
      );
      if (!ok) return;
    }
    setBusy((b) => ({ ...b, [id]: action }));
    setErr("");
    try {
      if (action === "login") {
        const r = await apiFetch<{ url: string }>(`/api/nodes/${id}/login-url`, {
          method: "POST",
        });
        window.open(r.url, "_blank", "noopener,noreferrer");
      } else {
        await apiFetch(`/api/nodes/${id}/${action === "pause" ? "pause" : action}`, {
          method: "POST",
        });
        await refresh();
      }
    } catch (ex) {
      setErr(ex instanceof Error ? ex.message : String(ex));
    } finally {
      setBusy((b) => {
        const n = { ...b };
        delete n[id];
        return n;
      });
    }
  }

  async function batchUpdate() {
    const ids = [...selected];
    if (!ids.length) return;
    const names = nodes
      .filter((n) => ids.includes(n.id))
      .map((n) => n.name)
      .join("、");
    const ok = window.confirm(
      `确认批量更新 ${ids.length} 台策略机？\n\n${names}\n\n将分别 git pull 并 reload，短暂中断；不会自动启动策略。`,
    );
    if (!ok) return;
    setErr("");
    try {
      await apiFetch("/api/nodes/update-batch", {
        method: "POST",
        body: JSON.stringify({ ids }),
      });
      await refresh();
    } catch (ex) {
      setErr(ex instanceof Error ? ex.message : String(ex));
    }
  }

  function toggle(id: number) {
    setSelected((prev) => {
      const n = new Set(prev);
      if (n.has(id)) n.delete(id);
      else n.add(id);
      return n;
    });
  }

  const detailNode = detailId != null ? nodes.find((x) => x.id === detailId) : null;
  const detail = detailNode ? pickStrategy(detailNode) : null;
  const detailRunning =
    detail != null && (detail.running === true || detail.running === 1);
  const detailLegs = Array.isArray(detail?.position?.legs)
    ? (detail!.position.legs as Record<string, unknown>[])
    : [];

  return (
    <div>
      <div className="toolbar">
        <h2>监控区</h2>
        <div className="toolbar-actions">
          <button type="button" className="btn ghost" onClick={() => void refresh()}>
            刷新
          </button>
          <button
            type="button"
            className="btn"
            disabled={!selected.size}
            onClick={() => void batchUpdate()}
          >
            勾选更新 ({selected.size})
          </button>
        </div>
      </div>
      {err ? <div className="err">{err}</div> : null}
      <div className="card-grid">
        {nodes.map((n) => {
          const s = pickStrategy(n);
          const running = s.running === true || s.running === 1;
          return (
            <article
              key={n.id}
              className={`node-card ${n.online ? "online" : "offline"} ${
                running ? "running" : ""
              }`}
              onClick={() => setDetailId(n.id)}
              role="button"
              tabIndex={0}
              onKeyDown={(e) => {
                if (e.key === "Enter" || e.key === " ") {
                  e.preventDefault();
                  setDetailId(n.id);
                }
              }}
            >
              <header className="node-card-head">
                <label
                  className="check"
                  onClick={(e) => e.stopPropagation()}
                  onKeyDown={(e) => e.stopPropagation()}
                >
                  <input
                    type="checkbox"
                    checked={selected.has(n.id)}
                    onChange={() => toggle(n.id)}
                  />
                  <strong>{n.name}</strong>
                </label>
                <span className={`pill ${n.online ? "ok" : "bad"}`}>
                  {n.online ? "在线" : "离线"}
                </span>
              </header>
              <div className="node-meta mono">{n.base_url}</div>
              <dl className="kv">
                <div>
                  <dt>模式</dt>
                  <dd>{s.mode}</dd>
                </div>
                <div>
                  <dt>交易所</dt>
                  <dd>{s.exchange}</dd>
                </div>
                <div>
                  <dt>策略</dt>
                  <dd>
                    {running ? "运行中" : "已停"} · {s.phase}
                  </dd>
                </div>
                <div>
                  <dt>轮次</dt>
                  <dd>{s.rounds ?? "-"}</dd>
                </div>
                <div>
                  <dt>行情</dt>
                  <dd>{s.market ? "已连接" : "断开"}</dd>
                </div>
                <div>
                  <dt>Token</dt>
                  <dd>
                    {n.token_configured
                      ? n.fleet_ok === false
                        ? "配对失败"
                        : "已配对"
                      : "未配对"}
                  </dd>
                </div>
              </dl>
              {n.fleet_error ? <div className="err soft">{n.fleet_error}</div> : null}
              {n.error ? <div className="err soft">{n.error}</div> : null}
              <div className="node-actions" onClick={(e) => e.stopPropagation()}>
                <button
                  type="button"
                  className={`btn ${running ? "btn-running" : ""}`}
                  disabled={!!busy[n.id] || !n.token_configured || running}
                  onClick={() => void act(n.id, "start")}
                >
                  {running ? "运行中" : "启动"}
                </button>
                <button
                  type="button"
                  className="btn ghost"
                  disabled={!!busy[n.id] || !n.token_configured}
                  onClick={() => void act(n.id, "pause")}
                >
                  停止
                </button>
                <button
                  type="button"
                  className="btn"
                  disabled={!!busy[n.id] || !n.token_configured}
                  onClick={() => void act(n.id, "login")}
                >
                  登录策略机
                </button>
                <button
                  type="button"
                  className="btn ghost"
                  disabled={!!busy[n.id] || !n.token_configured}
                  onClick={() => void act(n.id, "update")}
                >
                  更新代码
                </button>
              </div>
            </article>
          );
        })}
      </div>
      {!nodes.length ? (
        <p className="meta">暂无策略机。请到「系统设置」添加并生成 Token。</p>
      ) : null}

      {detailNode && detail ? (
        <div
          className="modal-backdrop"
          onClick={() => setDetailId(null)}
          role="presentation"
        >
          <div
            className={`modal-panel ${detailRunning ? "running" : ""}`}
            onClick={(e) => e.stopPropagation()}
            role="dialog"
            aria-modal="true"
            aria-label={`${detailNode.name} 详情`}
          >
            <header className="modal-head">
              <div>
                <h3>{detailNode.name}</h3>
                <div className="mono meta">{detailNode.base_url}</div>
              </div>
              <button
                type="button"
                className="btn ghost"
                onClick={() => setDetailId(null)}
              >
                关闭
              </button>
            </header>

            <section className="modal-section">
              <h4>策略详情</h4>
              <dl className="kv detail-kv">
                <div>
                  <dt>状态</dt>
                  <dd>
                    {detailRunning ? "运行中" : "已停"} · {detail.phase}
                  </dd>
                </div>
                <div>
                  <dt>模式 / 交易所</dt>
                  <dd>
                    {detail.mode} / {detail.exchange}
                  </dd>
                </div>
                <div>
                  <dt>轮次</dt>
                  <dd>{detail.rounds ?? "—"}</dd>
                </div>
                <div>
                  <dt>组 ID</dt>
                  <dd className="mono">
                    {String(detail.strat.group_id || detail.position.group_id || "—")}
                  </dd>
                </div>
                <div>
                  <dt>杠杆 / 保证金</dt>
                  <dd>
                    {fmt(detail.strat.leverage, 1)}x /{" "}
                    {String(detail.strat.perp_margin_mode || "—")}
                  </dd>
                </div>
                <div>
                  <dt>名义 永续/期权</dt>
                  <dd>
                    {fmt(detail.strat.perp_qty_eth, 4)} /{" "}
                    {fmt(detail.strat.option_qty_eth, 4)} ETH
                  </dd>
                </div>
                <div>
                  <dt>出场目标</dt>
                  <dd>{fmt(detail.strat.exit_target_usdt, 2)} USDT</dd>
                </div>
                <div>
                  <dt>定仓</dt>
                  <dd>
                    {String(detail.strat.sizing_mode || "—")}
                    {detail.strat.risk_last_k != null
                      ? ` · k=${fmt(detail.strat.risk_last_k, 2)}`
                      : ""}
                  </dd>
                </div>
                <div>
                  <dt>指数</dt>
                  <dd>{fmt(detail.index_px, 2)}</dd>
                </div>
                <div>
                  <dt>合约对</dt>
                  <dd className="mono">
                    {detail.pair
                      ? `${detail.pair.expiry_ymd || "?"} @ ${detail.pair.strike ?? "?"}`
                      : "—"}
                  </dd>
                </div>
                {detail.strat.last_error ? (
                  <div className="span-2">
                    <dt>最近错误</dt>
                    <dd className="err soft">{String(detail.strat.last_error)}</dd>
                  </div>
                ) : null}
              </dl>
            </section>

            <section className="modal-section">
              <h4>持仓</h4>
              <p className="meta">
                状态：{String(detail.position.status || "flat")}
                {detail.position.net_pnl != null ? (
                  <>
                    {" · 净浮盈 "}
                    <span className={pnlClass(detail.position.net_pnl)}>
                      {fmt(detail.position.net_pnl, 2)} USDT
                    </span>
                  </>
                ) : null}
                {detail.position.expiry_ymd
                  ? ` · 到期 ${String(detail.position.expiry_ymd)} @ ${fmt(detail.position.strike, 0)}`
                  : ""}
              </p>
              {detailLegs.length ? (
                <div className="legs-table-wrap">
                  <table className="legs-table">
                    <thead>
                      <tr>
                        <th>腿</th>
                        <th>方向</th>
                        <th>合约</th>
                        <th>数量</th>
                        <th>均价</th>
                        <th>标记</th>
                        <th>浮盈</th>
                      </tr>
                    </thead>
                    <tbody>
                      {detailLegs.map((lg, i) => (
                        <tr key={`${lg.inst_id || i}`}>
                          <td>{String(lg.kind || "—")}</td>
                          <td>{String(lg.side || "—")}</td>
                          <td className="mono">{String(lg.inst_id || "—")}</td>
                          <td>{fmt(lg.qty, 4)}</td>
                          <td>{fmt(lg.avg_px, 4)}</td>
                          <td>{fmt(lg.mark_px, 4)}</td>
                          <td className={pnlClass(lg.upl)}>{fmt(lg.upl, 2)}</td>
                        </tr>
                      ))}
                    </tbody>
                  </table>
                </div>
              ) : (
                <p className="meta">当前无持仓腿</p>
              )}
            </section>

            <div className="node-actions">
              <button
                type="button"
                className={`btn ${detailRunning ? "btn-running" : ""}`}
                disabled={
                  !!busy[detailNode.id] ||
                  !detailNode.token_configured ||
                  detailRunning
                }
                onClick={() => void act(detailNode.id, "start")}
              >
                {detailRunning ? "运行中" : "启动"}
              </button>
              <button
                type="button"
                className="btn ghost"
                disabled={!!busy[detailNode.id] || !detailNode.token_configured}
                onClick={() => void act(detailNode.id, "pause")}
              >
                停止
              </button>
              <button
                type="button"
                className="btn"
                disabled={!!busy[detailNode.id] || !detailNode.token_configured}
                onClick={() => void act(detailNode.id, "login")}
              >
                登录策略机
              </button>
            </div>
          </div>
        </div>
      ) : null}
    </div>
  );
}
