/**
 * 实盘下单:填完币种与止盈止损后,在表单下方显示预估风险 / 预估盈利 / 预估盈亏比.
 * 以损定仓:风险 = 当前交易基数 × risk%.
 * 全仓杠杆:风险 = 可用保证金×缓冲 × 杠杆 × |SL-入场|/入场(与开仓 calc_risk_amount_from_plan 一致).
 */
(function (global) {
  "use strict";

  let debounceMs = 400;
  let minRr = 1.5;
  let debounceTimer = null;
  let fetchSeq = 0;

  function $(id) {
    return document.getElementById(id);
  }

  function num(v) {
    const n = Number(v);
    return Number.isFinite(n) ? n : null;
  }

  function formatRr(rr) {
    if (rr === null || typeof rr === "undefined") return "—";
    const n = Number(rr);
    if (!Number.isFinite(n)) return "—";
    const body = Number.isInteger(n) ? String(n) : String(parseFloat(n.toFixed(2)));
    return body + ":1";
  }

  function formatU(v) {
    if (v === null || typeof v === "undefined" || !Number.isFinite(Number(v))) return "—";
    return Number(v).toFixed(2) + "U";
  }

  function setMetric(el, label, valueText) {
    if (!el) return;
    el.innerHTML = label + ":<strong>" + valueText + "</strong>";
  }

  function sizingMode() {
    return (document.body && document.body.getAttribute("data-position-sizing-mode")) || "risk";
  }

  function isFullMarginMode() {
    return sizingMode() === "full_margin";
  }

  function fullMarginBuffer() {
    const n = Number(document.body && document.body.getAttribute("data-full-margin-buffer"));
    return Number.isFinite(n) && n > 0 ? n : 0.9;
  }

  function leverageForSymbol(sym) {
    const u = (sym || "").trim().toUpperCase();
    const btc = Number(document.body && document.body.getAttribute("data-btc-leverage"));
    const alt = Number(document.body && document.body.getAttribute("data-alt-leverage"));
    if (u.startsWith("BTC") || u.startsWith("ETH")) {
      return Number.isFinite(btc) && btc > 0 ? btc : 10;
    }
    return Number.isFinite(alt) && alt > 0 ? alt : 5;
  }

  function riskPercent() {
    const form = $("add-order-form");
    const raw =
      (form && form.getAttribute("data-risk-percent")) ||
      (document.body && document.body.getAttribute("data-risk-percent")) ||
      "";
    const n = Number(raw);
    return Number.isFinite(n) && n > 0 ? n : 1;
  }

  function calcRiskFraction(direction, entry, sl) {
    const e = num(entry);
    const s = num(sl);
    if (e === null || s === null || e <= 0 || s <= 0) return null;
    let risk = 0;
    if (direction === "short") {
      risk = s - e;
    } else {
      risk = e - s;
    }
    if (risk <= 0) return null;
    return risk / e;
  }

  function calcRr(direction, entry, sl, tp) {
    const e = num(entry);
    const s = num(sl);
    const t = num(tp);
    if (e === null || s === null || t === null) return null;
    if (direction === "short") {
      if (s <= e || t >= e) return null;
      return (e - t) / (s - e);
    }
    if (s >= e || t <= e) return null;
    return (t - e) / (e - s);
  }

  function calcRrFromPct(slPct, tpPct) {
    const sl = num(slPct);
    const tp = num(tpPct);
    if (sl === null || tp === null || sl <= 0 || tp <= 0) return null;
    return tp / sl;
  }

  function calcTpFromFixedRr(direction, entry, sl, rr) {
    const e = num(entry);
    const s = num(sl);
    const r = num(rr);
    if (e === null || s === null || r === null || r <= 0) return null;
    if (direction === "short") {
      if (s <= e) return null;
      return e - (s - e) * r;
    }
    if (s >= e) return null;
    return e + (e - s) * r;
  }

  function resolveSlPrice(mode, direction, entry) {
    if (mode === "pct") {
      const slPct = num($("order-sl-pct") && $("order-sl-pct").value);
      if (slPct === null || slPct <= 0) return null;
      if (direction === "short") return entry * (1 + slPct / 100);
      return entry * (1 - slPct / 100);
    }
    return num($("order-sl") && $("order-sl").value);
  }

  function currentMode() {
    return ($("sltp-mode") && $("sltp-mode").value) || "fixed_rr";
  }

  function currentDirection() {
    return ($("order-direction") && $("order-direction").value) || "long";
  }

  function currentSymbol() {
    return (($("order-symbol") && $("order-symbol").value) || "").trim();
  }

  function inputsComplete(m) {
    const dir = currentDirection();
    if (!currentSymbol() || !dir) return false;
    if (m === "pct") {
      const sl = num($("order-sl-pct") && $("order-sl-pct").value);
      const tp = num($("order-tp-pct") && $("order-tp-pct").value);
      return sl !== null && tp !== null && sl > 0 && tp > 0;
    }
    if (m === "fixed_rr") {
      const sl = num($("order-sl") && $("order-sl").value);
      const rr = num($("order-fixed-rr") && $("order-fixed-rr").value);
      return sl !== null && rr !== null && sl > 0 && rr > 0;
    }
    const sl = num($("order-sl") && $("order-sl").value);
    const tp = num($("order-tp") && $("order-tp").value);
    return sl !== null && tp !== null && sl > 0 && tp > 0;
  }

  function paintEmpty() {
    setMetric($("order-risk-preview"), "预估风险", "—");
    setMetric($("order-profit-preview"), "预估盈利", "—");
    setMetric($("order-rr-preview"), "预估盈亏比", "—");
  }

  function paintLoading() {
    setMetric($("order-risk-preview"), "预估风险", "计算中…");
    setMetric($("order-profit-preview"), "预估盈利", "计算中…");
    setMetric($("order-rr-preview"), "预估盈亏比", "计算中…");
  }

  function paintFail(kind) {
    const msg = kind === "fetch_fail" ? "取价失败" : "无效";
    setMetric($("order-risk-preview"), "预估风险", msg);
    setMetric($("order-profit-preview"), "预估盈利", msg);
    setMetric($("order-rr-preview"), "预估盈亏比", msg);
  }

  function paintOk(riskU, profitU, rr) {
    setMetric($("order-risk-preview"), "预估风险", formatU(riskU));
    setMetric($("order-profit-preview"), "预估盈利", formatU(profitU));
    const rrEl = $("order-rr-preview");
    const rrText = formatRr(rr);
    setMetric(rrEl, "预估盈亏比", rrText);
    if (rrEl && rr !== null && Number.isFinite(Number(rr))) {
      rrEl.classList.toggle("order-preview-rr-low", Number(rr) < minRr);
      rrEl.classList.toggle("order-preview-rr-ok", Number(rr) >= minRr);
    }
  }

  function plannedRiskFromRiskMode(capital) {
    const cap = num(capital);
    if (cap === null || cap <= 0) return null;
    return Math.round((cap * riskPercent()) / 100 * 100) / 100;
  }

  function plannedRiskFromFullMargin(availableUsdt, symbol, direction, entry, sl) {
    const avail = num(availableUsdt);
    if (avail === null || avail <= 0) return null;
    const slPx = num(sl);
    const entryPx = num(entry);
    if (slPx === null || entryPx === null) return null;
    const rf = calcRiskFraction(direction, entryPx, slPx);
    if (rf === null) return null;
    const margin = Math.round(avail * fullMarginBuffer() * 100) / 100;
    const lev = leverageForSymbol(symbol);
    return Math.round(margin * lev * rf * 100) / 100;
  }

  function resolvePreviewRr(m, dir, entry) {
    if (m === "pct") {
      return calcRrFromPct(
        $("order-sl-pct") && $("order-sl-pct").value,
        $("order-tp-pct") && $("order-tp-pct").value
      );
    }
    const sl = num($("order-sl") && $("order-sl").value);
    if (m === "fixed_rr") {
      const fixed = num($("order-fixed-rr") && $("order-fixed-rr").value);
      if (fixed !== null && fixed > 0) return fixed;
      const tp = calcTpFromFixedRr(dir, entry, sl, fixed);
      return calcRr(dir, entry, sl, tp);
    }
    const tp = num($("order-tp") && $("order-tp").value);
    return calcRr(dir, entry, sl, tp);
  }

  function refreshNow() {
    if (!$("order-plan-preview")) return;
    const m = currentMode();
    if (!inputsComplete(m)) {
      paintEmpty();
      return;
    }

    const sym = currentSymbol();
    const dir = currentDirection();
    const seq = ++fetchSeq;
    paintLoading();

    const defaultsP = fetch(
      "/api/order_defaults?symbol=" +
        encodeURIComponent(sym) +
        "&direction=" +
        encodeURIComponent(dir)
    ).then(function (r) {
      return r.json();
    });

    const capitalP = fetch("/api/account_snapshot").then(function (r) {
      return r.json();
    });

    Promise.all([defaultsP, capitalP])
      .then(function (results) {
        if (seq !== fetchSeq) return;
        const data = results[0];
        const account = results[1] || {};
        if (!data.ok) {
          paintFail("fetch_fail");
          return;
        }
        const entry = num(data.last_price != null ? data.last_price : data.price);
        if (entry === null) {
          paintFail("fetch_fail");
          return;
        }
        const rr = resolvePreviewRr(m, dir, entry);
        if (rr === null) {
          paintFail("invalid");
          return;
        }
        let riskU = null;
        if (isFullMarginMode()) {
          const slPx = resolveSlPrice(m, dir, entry);
          const avail =
            data.available_trading_usdt != null
              ? data.available_trading_usdt
              : account.available_trading_usdt;
          riskU = plannedRiskFromFullMargin(avail, sym, dir, entry, slPx);
        } else {
          riskU = plannedRiskFromRiskMode(account.current_capital);
        }
        if (riskU === null) {
          paintFail("fetch_fail");
          return;
        }
        const profitU = Math.round(riskU * rr * 100) / 100;
        paintOk(riskU, profitU, rr);
      })
      .catch(function () {
        if (seq !== fetchSeq) return;
        paintFail("fetch_fail");
      });
  }

  function schedule() {
    clearTimeout(debounceTimer);
    debounceTimer = setTimeout(refreshNow, debounceMs);
  }

  function wire(opts) {
    opts = opts || {};
    if (opts.minRr != null && Number.isFinite(Number(opts.minRr))) {
      minRr = Number(opts.minRr);
    }
    if (opts.debounceMs != null && Number.isFinite(Number(opts.debounceMs))) {
      debounceMs = Number(opts.debounceMs);
    }
    [
      "order-symbol",
      "order-direction",
      "sltp-mode",
      "order-sl",
      "order-tp",
      "order-sl-pct",
      "order-tp-pct",
      "order-fixed-rr",
      "order-leverage",
    ].forEach(function (id) {
      const el = $(id);
      if (!el || el._rrPreviewBound) return;
      el._rrPreviewBound = true;
      el.addEventListener("input", schedule);
      el.addEventListener("change", schedule);
    });
    schedule();
  }

  global.ManualOrderRrPreview = {
    wire: wire,
    schedule: schedule,
    refresh: refreshNow,
    calcRr: calcRr,
    calcRrFromPct: calcRrFromPct,
    calcRiskFraction: calcRiskFraction,
    formatRr: formatRr,
  };
})(typeof window !== "undefined" ? window : globalThis);
