/**
 * 中控振幅统计:OKX ETH/BTC + 波动点数振幅占比 + 周末筛选.
 */
(function () {
  const page = document.getElementById("page-amp-stats");
  if (!page) return;

  let lastResult = null;
  let pageNo = 1;
  let bound = false;
  let reframeTimer = null;

  const el = (id) => document.getElementById(id);

  async function apiFetch(url, opts) {
    const r = await fetch(url, { credentials: "same-origin", ...(opts || {}) });
    const ct = (r.headers.get("content-type") || "").toLowerCase();
    if (ct.includes("application/json")) {
      const data = await r.json();
      if (!r.ok) throw new Error((data && (data.detail || data.msg)) || r.statusText || "请求失败");
      return data;
    }
    if (!r.ok) throw new Error(r.statusText || "请求失败");
    return r;
  }

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

  function pct(ratio) {
    if (ratio == null || ratio === "") return "—";
    const n = Number(ratio);
    if (!Number.isFinite(n)) return "—";
    return (n * 100).toFixed(1) + "%";
  }

  function readMovePoints() {
    const raw = (el("amp-move-points")?.value || "").trim();
    if (!raw) return null;
    const n = Number(raw);
    if (!Number.isFinite(n) || n <= 0) return null;
    return n;
  }

  function readWeekend() {
    return el("amp-weekend-filter")?.value || "all";
  }

  function setStatus(msg) {
    const s = el("amp-status");
    if (s) s.textContent = msg || "";
  }

  function setView(view) {
    const isHist = view === "history";
    el("amp-panel-stats")?.classList.toggle("hidden", isHist);
    el("amp-panel-history")?.classList.toggle("hidden", !isHist);
    page.querySelectorAll(".amp-view-tab").forEach((btn) => {
      const on = btn.getAttribute("data-view") === view;
      btn.classList.toggle("is-active", on);
      btn.setAttribute("aria-selected", on ? "true" : "false");
    });
    if (isHist) void loadHistory();
  }

  function syncCustomDays() {
    const period = el("amp-period")?.value || "2m";
    const wrap = el("amp-custom-wrap");
    if (wrap) wrap.classList.toggle("hidden", period !== "custom");
  }

  function fillMetaControls() {
    const hourSel = el("amp-start-hour");
    if (hourSel && !hourSel.options.length) {
      for (let h = 0; h < 24; h++) {
        const opt = document.createElement("option");
        opt.value = String(h);
        opt.textContent = String(h).padStart(2, "0") + ":00";
        if (h === 16) opt.selected = true;
        hourSel.appendChild(opt);
      }
    }
  }

  function renderSummary(summary, result) {
    const box = el("amp-summary");
    if (!box) return;
    const s = summary || {};
    if (!s.sample_count) {
      box.innerHTML = '<p class="amp-empty">暂无汇总</p>';
      renderMoveStats(null);
      return;
    }
    box.innerHTML =
      `<div class="amp-sum-grid">` +
      `<div><span class="amp-sum-k">样本</span><span class="amp-sum-v">${esc(s.sample_count)}</span></div>` +
      `<div><span class="amp-sum-k">最大振幅</span><span class="amp-sum-v">${esc(s.max_amplitude)} <small>(${esc(s.max_amplitude_day)})</small></span></div>` +
      `<div><span class="amp-sum-k">振幅均值</span><span class="amp-sum-v">${esc(s.avg_amplitude)}</span></div>` +
      `<div><span class="amp-sum-k">振幅中位</span><span class="amp-sum-v">${esc(s.median_amplitude)}</span></div>` +
      `<div><span class="amp-sum-k">两日最大振幅</span><span class="amp-sum-v">${esc(s.max_amplitude_2d)} <small>(${esc(s.max_amplitude_2d_day)})</small></span></div>` +
      `<div><span class="amp-sum-k">两日振幅均值/中位</span><span class="amp-sum-v">${esc(s.avg_amplitude_2d)} / ${esc(s.median_amplitude_2d)}</span></div>` +
      `<div><span class="amp-sum-k">开→高最大/均</span><span class="amp-sum-v">${esc(s.max_up_points)} / ${esc(s.avg_up_points)}</span></div>` +
      `<div><span class="amp-sum-k">开→低最大/均</span><span class="amp-sum-v">${esc(s.max_down_points)} / ${esc(s.avg_down_points)}</span></div>` +
      `<div><span class="amp-sum-k">涨/跌窗占比</span><span class="amp-sum-v">${esc(s.up_day_ratio)} / ${esc(s.down_day_ratio)}</span></div>` +
      `<div><span class="amp-sum-k">价源</span><span class="amp-sum-v">${esc(result && result.price_source)}</span></div>` +
      `</div>`;
    renderMoveStats(s.move_points_stats);
  }

  function renderMoveStats(ms) {
    const box = el("amp-move-stats");
    if (!box) return;
    if (!ms) {
      box.innerHTML = '<p class="amp-empty">填写「波动点数」后计算，可看振幅≥该点数的天数占比</p>';
      return;
    }
    box.innerHTML =
      `<div class="amp-sum-grid">` +
      `<div><span class="amp-sum-k">对照点数</span><span class="amp-sum-v">${esc(ms.move_points)}</span></div>` +
      `<div><span class="amp-sum-k">振幅≥点数</span><span class="amp-sum-v">${esc(ms.amp_hit_days)} 天 · <strong>${esc(pct(ms.amp_hit_ratio))}</strong></span></div>` +
      `<div><span class="amp-sum-k">两日振幅≥点数</span><span class="amp-sum-v">${esc(ms.amp_2d_hit_days)} 天 · <strong>${esc(pct(ms.amp_2d_hit_ratio))}</strong></span></div>` +
      `<div><span class="amp-sum-k">开→高≥点数</span><span class="amp-sum-v">${esc(ms.up_hit_days)} 天 · ${esc(pct(ms.up_hit_ratio))}</span></div>` +
      `<div><span class="amp-sum-k">开→低≥点数</span><span class="amp-sum-v">${esc(ms.down_hit_days)} 天 · ${esc(pct(ms.down_hit_ratio))}</span></div>` +
      `<div><span class="amp-sum-k">|涨跌|≥点数</span><span class="amp-sum-v">${esc(ms.abs_change_hit_days)} 天 · ${esc(pct(ms.abs_change_hit_ratio))}</span></div>` +
      `</div>`;
  }

  function dayLabel(r) {
    const day = esc(r.settlement_day);
    if (r.is_weekend && r.weekday_label) {
      return `${day}<span class="amp-wd-tag">${esc(r.weekday_label)}</span>`;
    }
    return day;
  }

  function hitCell(r) {
    if (r.move_points == null) return "—";
    if (r.amp_hit) return '<span class="amp-pnl is-pos">是</span>';
    return '<span class="amp-pnl is-neg">否</span>';
  }

  function renderTable(pagePayload) {
    const body = el("amp-table-body");
    const pager = el("amp-pager");
    if (!body) return;
    const rows = (pagePayload && pagePayload.rows) || [];
    if (!rows.length) {
      body.innerHTML = '<tr><td colspan="12" class="amp-empty">暂无数据</td></tr>';
    } else {
      body.innerHTML = rows
        .map((r) => {
          const trClass = r.is_weekend ? ' class="amp-row-weekend"' : "";
          const upCls = r.hit_up ? ' class="amp-pnl is-pos"' : "";
          const downCls = r.hit_down ? ' class="amp-pnl is-pos"' : "";
          const ampCls = r.amp_hit ? ' class="amp-pnl is-pos"' : "";
          const amp2Cls = r.amp_hit_2d ? ' class="amp-pnl is-pos"' : "";
          const amp2 =
            r.amplitude_2d == null || r.amplitude_2d === ""
              ? "—"
              : `<span title="${esc(r.window2_start || "")} → ${esc(r.window2_end || "")}">${esc(r.amplitude_2d)}</span>`;
          return (
            `<tr${trClass}>` +
            `<td>${dayLabel(r)}</td>` +
            `<td>${esc(r.window_start)}</td>` +
            `<td>${esc(r.open)}</td>` +
            `<td>${esc(r.high)}</td>` +
            `<td>${esc(r.low)}</td>` +
            `<td>${esc(r.close)}</td>` +
            `<td${upCls}>${esc(r.up_points)}</td>` +
            `<td${downCls}>${esc(r.down_points)}</td>` +
            `<td${ampCls}><strong>${esc(r.amplitude)}</strong></td>` +
            `<td${amp2Cls}><strong>${amp2}</strong></td>` +
            `<td>${esc(r.change)}</td>` +
            `<td>${hitCell(r)}</td>` +
            `</tr>`
          );
        })
        .join("");
    }
    if (pager && pagePayload) {
      pager.innerHTML =
        `<button type="button" class="ghost" id="amp-page-prev" ${pagePayload.page <= 1 ? "disabled" : ""}>上一页</button>` +
        `<span class="amp-pager-meta">第 ${esc(pagePayload.page)} / ${esc(pagePayload.total_pages)} 页 · 共 ${esc(pagePayload.total)} 天</span>` +
        `<button type="button" class="ghost" id="amp-page-next" ${pagePayload.page >= pagePayload.total_pages ? "disabled" : ""}>下一页</button>`;
      el("amp-page-prev")?.addEventListener("click", () => {
        if (pageNo > 1) {
          pageNo -= 1;
          void reframe(false);
        }
      });
      el("amp-page-next")?.addEventListener("click", () => {
        if (pagePayload.page < pagePayload.total_pages) {
          pageNo += 1;
          void reframe(false);
        }
      });
    }
  }

  function rowsAllFromLast() {
    if (!lastResult) return [];
    if (Array.isArray(lastResult.rows_all) && lastResult.rows_all.length) return lastResult.rows_all;
    return lastResult.rows || [];
  }

  async function reframe(resetPage) {
    if (!lastResult) {
      renderMoveStats(null);
      return;
    }
    if (resetPage) pageNo = 1;
    const rowsAll = rowsAllFromLast();
    if (!rowsAll.length) return;
    try {
      const data = await apiFetch("/api/amp-stats/reframe", {
        method: "POST",
        headers: { "Content-Type": "application/json" },
        body: JSON.stringify({
          rows_all: rowsAll,
          symbol: lastResult.symbol || el("amp-symbol")?.value || "eth",
          start_hour: lastResult.start_hour ?? Number(el("amp-start-hour")?.value || 16),
          period: lastResult.period || el("amp-period")?.value || "2m",
          sample_days: lastResult.sample_days_requested || 60,
          move_points: readMovePoints(),
          weekend_filter: readWeekend(),
          price_source: lastResult.price_source || "",
          inst_id: lastResult.inst_id || "",
          page: pageNo,
          page_size: 20,
        }),
      });
      const prevAll = rowsAll;
      lastResult = data.result || lastResult;
      if (!lastResult.rows_all || !lastResult.rows_all.length) lastResult.rows_all = prevAll;
      renderSummary(lastResult.summary, lastResult);
      renderTable(data.page);
      setStatus(`完成 · 样本 ${(lastResult.summary || {}).sample_count || 0}`);
    } catch (e) {
      setStatus(String(e && e.message ? e.message : e));
    }
  }

  function scheduleReframe() {
    if (!lastResult) return;
    if (reframeTimer) clearTimeout(reframeTimer);
    reframeTimer = setTimeout(() => void reframe(true), 280);
  }

  async function compute(resetPage) {
    if (resetPage) pageNo = 1;
    const symbol = el("amp-symbol")?.value || "eth";
    const startHour = Number(el("amp-start-hour")?.value || 16);
    const period = el("amp-period")?.value || "2m";
    const customDays = Number(el("amp-custom-days")?.value || 60);
    setStatus("计算中…(长周期会分页拉 OKX，遇限频会自动重试，请稍候)");
    try {
      const data = await apiFetch("/api/amp-stats/compute", {
        method: "POST",
        headers: { "Content-Type": "application/json" },
        body: JSON.stringify({
          symbol,
          start_hour: startHour,
          period,
          custom_days: period === "custom" ? customDays : null,
          move_points: readMovePoints(),
          weekend_filter: readWeekend(),
          page: pageNo,
          page_size: 20,
        }),
      });
      lastResult = data.result || null;
      renderSummary(lastResult && lastResult.summary, lastResult);
      renderTable(data.page);
      const miss = (lastResult && lastResult.missing_count) || 0;
      setStatus(
        miss
          ? `完成 · 样本 ${(lastResult.summary || {}).sample_count || 0} · 缺 ${miss} 天`
          : `完成 · 样本 ${(lastResult.summary || {}).sample_count || 0}`
      );
    } catch (e) {
      setStatus(String(e && e.message ? e.message : e));
    }
  }

  async function saveHistory() {
    if (!lastResult) {
      setStatus("请先计算");
      return;
    }
    try {
      await apiFetch("/api/amp-stats/history", {
        method: "POST",
        headers: { "Content-Type": "application/json" },
        body: JSON.stringify({ result: lastResult }),
      });
      setStatus("已保存到历史");
    } catch (e) {
      setStatus(String(e && e.message ? e.message : e));
    }
  }

  function downloadCurrent() {
    if (!lastResult) {
      setStatus("请先计算");
      return;
    }
    const symbol = el("amp-symbol")?.value || "eth";
    const startHour = Number(el("amp-start-hour")?.value || 16);
    const period = el("amp-period")?.value || "2m";
    const customDays = Number(el("amp-custom-days")?.value || 60);
    const mp = readMovePoints();
    const q = new URLSearchParams({
      symbol,
      start_hour: String(startHour),
      period,
      weekend_filter: readWeekend(),
    });
    if (period === "custom") q.set("custom_days", String(customDays));
    if (mp != null) q.set("move_points", String(mp));
    window.location.href = "/api/amp-stats/export?" + q.toString();
  }

  async function loadHistory() {
    const box = el("amp-history-list");
    if (!box) return;
    box.innerHTML = '<p class="amp-empty">加载中…</p>';
    try {
      const data = await apiFetch("/api/amp-stats/history?limit=50");
      const items = data.items || [];
      if (!items.length) {
        box.innerHTML = '<p class="amp-empty">暂无历史</p>';
        return;
      }
      box.innerHTML = items
        .map(
          (it) =>
            `<div class="amp-hist-card" data-id="${esc(it.id)}">` +
            `<div class="amp-hist-main">` +
            `<strong>${esc(it.symbol_label || it.symbol)}</strong> · ${esc(String(it.start_hour).padStart(2, "0"))}:00→16:00 · ${esc(it.period)}` +
            `<div class="amp-hist-sub">${esc(it.created_at)} · 样本 ${esc(it.sample_count)} · 最大振幅 ${esc(it.max_amplitude)} (${esc(it.max_amplitude_day)})</div>` +
            `</div>` +
            `<div class="amp-hist-actions">` +
            `<button type="button" class="ghost amp-hist-view">查看</button>` +
            `<button type="button" class="ghost amp-hist-dl">下载</button>` +
            `<button type="button" class="danger amp-hist-del">删除</button>` +
            `</div></div>`
        )
        .join("");
      box.querySelectorAll(".amp-hist-card").forEach((card) => {
        const id = card.getAttribute("data-id");
        card.querySelector(".amp-hist-view")?.addEventListener("click", () => void openHistory(id));
        card.querySelector(".amp-hist-dl")?.addEventListener("click", () => {
          const mp = readMovePoints();
          const q = new URLSearchParams({
            history_id: id,
            weekend_filter: readWeekend(),
          });
          if (mp != null) q.set("move_points", String(mp));
          window.location.href = "/api/amp-stats/export?" + q.toString();
        });
        card.querySelector(".amp-hist-del")?.addEventListener("click", async () => {
          if (!confirm("删除该历史记录?")) return;
          await apiFetch("/api/amp-stats/history/" + encodeURIComponent(id), { method: "DELETE" });
          void loadHistory();
        });
      });
    } catch (e) {
      box.innerHTML = `<p class="amp-empty">${esc(String(e && e.message ? e.message : e))}</p>`;
    }
  }

  async function openHistory(id) {
    try {
      const data = await apiFetch("/api/amp-stats/history/" + encodeURIComponent(id));
      lastResult = data.item || null;
      setView("stats");
      if (lastResult) {
        if (el("amp-symbol")) el("amp-symbol").value = lastResult.symbol || "eth";
        if (el("amp-start-hour")) el("amp-start-hour").value = String(lastResult.start_hour ?? 16);
        if (lastResult.move_points != null && el("amp-move-points")) {
          el("amp-move-points").value = String(lastResult.move_points);
        }
        if (lastResult.weekend_filter && el("amp-weekend-filter")) {
          el("amp-weekend-filter").value = lastResult.weekend_filter;
        }
        pageNo = 1;
        setStatus("已载入历史 " + id);
        await reframe(true);
      }
    } catch (e) {
      setStatus(String(e && e.message ? e.message : e));
    }
  }

  function bind() {
    if (bound) return;
    bound = true;
    fillMetaControls();
    page.querySelectorAll(".amp-view-tab").forEach((btn) => {
      btn.addEventListener("click", () => setView(btn.getAttribute("data-view")));
    });
    el("amp-period")?.addEventListener("change", syncCustomDays);
    el("amp-btn-compute")?.addEventListener("click", () => void compute(true));
    el("amp-btn-save")?.addEventListener("click", () => void saveHistory());
    el("amp-btn-download")?.addEventListener("click", downloadCurrent);
    el("amp-move-points")?.addEventListener("input", scheduleReframe);
    el("amp-weekend-filter")?.addEventListener("change", () => void reframe(true));
    syncCustomDays();
  }

  window.hubAmpStatsPage = {
    init() {
      bind();
      setView("stats");
      setStatus("");
      renderMoveStats(null);
    },
  };
})();
