/* ============================================================
   Dinasty Control — mock data engine
   Deterministic (seeded) so the matrix is stable across reloads.
   ============================================================ */

function mulberry32(a) {
  return function () {
    a |= 0; a = (a + 0x6d2b79f5) | 0;
    let t = Math.imul(a ^ (a >>> 15), 1 | a);
    t = (t + Math.imul(t ^ (t >>> 7), 61 | t)) ^ t;
    return ((t ^ (t >>> 14)) >>> 0) / 4294967296;
  };
}

const SYMBOLS = ["XAUUSD", "EURUSD", "GBPUSD", "USDJPY", "XAGUSD", "US30", "BTCUSD", "AUDUSD"];
const ROLES   = ["Core", "Core", "Hedge", "Scout", "Grid", "Recovery", "Hedge", "Scout"];

// Two VPS, three trading accounts each.
const ACCOUNTS = {
  "VPS-1": ["#8842301", "#8851140", "#8907734"],
  "VPS-2": ["#8842318", "#8851199", "#8907788"],
};

const pad2 = (n) => String(n).padStart(2, "0");

function buildRows() {
  const rng = mulberry32(0x10A57);
  const rows = [];

  for (let g = 1; g <= 18; g++) {
    const vps = g <= 9 ? "VPS-1" : "VPS-2";
    const acctList = ACCOUNTS[vps];
    const account = acctList[(g - 1) % acctList.length];

    for (let s = 1; s <= 8; s++) {
      const id = `A${pad2(g)}-${pad2(s)}`;
      const role = ROLES[s - 1];
      const mode = rng() < 0.42 ? "REVERSAL" : "NORMAL";
      const symbol = SYMBOLS[Math.floor(rng() * SYMBOLS.length)];

      const maxPos = role === "Grid" ? 6 : role === "Recovery" ? 5 : 4;
      const openPos = Math.max(0, Math.floor(rng() * (maxPos + 1)) - (rng() < 0.28 ? maxPos : 0));
      const side = rng() < 0.5 ? "BUY" : "SELL";
      const lots = openPos > 0 ? Math.round((0.05 + rng() * 1.45) * 100) / 100 : 0;

      const winrate = Math.round((34 + rng() * 44) * 10) / 10; // 34–78%
      const pf = Math.round((0.55 + rng() * 1.95) * 100) / 100; // 0.55–2.50
      // P/L correlates loosely with PF, plus noise.
      const pl = Math.round((pf - 1) * (260 + rng() * 1700) + (rng() - 0.5) * 520);
      const floating = openPos > 0 ? Math.round((rng() - 0.46) * 1400) : 0;
      const drawdown = Math.round((1 + rng() * 14.5) * 10) / 10; // %
      const lossStreak = Math.floor(rng() * 8);

      const risky = pf < 0.9 || (drawdown > 11 && pf < 1.2) || (lossStreak >= 6 && pl < 0);

      let rec;
      if (pf < 0.82 || pl < -1600 || (drawdown > 12.5 && pf < 1.1)) rec = "PAUSE";
      else if (pf < 1.04 || pl < -250 || (risky && drawdown > 10.5)) rec = "REDUCE";
      else rec = "NORMAL";

      rows.push({
        id, group: g, slot: s, vps, account, role, mode, symbol,
        openPos, side, lots, winrate, pf, pl, floating, drawdown, lossStreak,
        risky, rec,
      });
    }
  }
  return rows;
}

function buildOverview(rows) {
  let dailyPL = 0, floatingPL = 0, buyLots = 0, sellLots = 0;
  let pause = 0, reduce = 0, normal = 0, riskyCount = 0, openSets = 0, openPositions = 0;
  let worstDD = 0;

  for (const r of rows) {
    dailyPL += r.pl;
    floatingPL += r.floating;
    if (r.openPos > 0) {
      openSets++;
      openPositions += r.openPos;
      if (r.side === "BUY") buyLots += r.lots * r.openPos;
      else sellLots += r.lots * r.openPos;
    }
    if (r.rec === "PAUSE") pause++;
    else if (r.rec === "REDUCE") reduce++;
    else normal++;
    if (r.risky) riskyCount++;
    if (r.drawdown > worstDD) worstDD = r.drawdown;
  }

  const baseEquity = 2_480_000;
  const totalEquity = baseEquity + floatingPL;
  // Portfolio-level drawdown (smoothed, not the single worst set).
  const ddPct = Math.round((worstDD * 0.62) * 10) / 10;
  const ddAmount = Math.round((ddPct / 100) * totalEquity);

  let aiStatus;
  if (pause > 24) aiStatus = "PAUSE";
  else if (pause > 14 || reduce > 50) aiStatus = "REDUCE";
  else if (pause > 6 || riskyCount > 26) aiStatus = "WATCH";
  else aiStatus = "NORMAL";

  return {
    totalEquity, floatingPL, dailyPL,
    ddPct, ddAmount,
    buyLots: Math.round(buyLots * 10) / 10,
    sellLots: Math.round(sellLots * 10) / 10,
    aiStatus,
    counts: { pause, reduce, normal, risky: riskyCount, openSets, openPositions, total: rows.length },
  };
}

// 24h equity sparkline points (seeded, gently trending up with intraday dip).
function buildEquityCurve(end) {
  const rng = mulberry32(0x5EED2);
  const pts = [];
  const n = 96; // 15-min buckets over 24h
  let v = end - 38000;
  for (let i = 0; i < n; i++) {
    const drift = 420;
    const dip = i > 40 && i < 58 ? -1400 : 0;
    v += (rng() - 0.42) * 2600 + drift + dip;
    pts.push(v);
  }
  pts.push(end);
  return pts;
}

// Recent AI activity feed for the overview.
function buildAlerts(rows) {
  const pauses = rows.filter((r) => r.rec === "PAUSE");
  const reduces = rows.filter((r) => r.rec === "REDUCE");
  const pick = (arr, i) => arr[i % arr.length];
  return [
    { t: "09:41:22", level: "pause",  set: pick(pauses, 2).id,  msg: `loss streak ${pick(pauses,2).lossStreak} · PF ${pick(pauses,2).pf.toFixed(2)} — trading halted` },
    { t: "09:38:07", level: "reduce", set: pick(reduces, 5).id, msg: `drawdown ${pick(reduces,5).drawdown}% — lots scaled 0.5×` },
    { t: "09:33:54", level: "watch",  set: "VPS-2",             msg: "latency 214ms — flagged for watch" },
    { t: "09:27:11", level: "pause",  set: pick(pauses, 7).id,  msg: `PF ${pick(pauses,7).pf.toFixed(2)} below floor — trading halted` },
    { t: "09:19:48", level: "reduce", set: pick(reduces, 1).id, msg: `exposure cap hit — new entries blocked` },
    { t: "09:12:30", level: "normal", set: "ALL",               msg: "session opened — 144 sets armed" },
  ];
}

// Per-symbol reference prices for synthesizing open positions.
const PX = {
  XAUUSD: [2310, 2398, 0.1], EURUSD: [1.071, 1.094, 0.00001], GBPUSD: [1.252, 1.279, 0.00001],
  USDJPY: [148.2, 152.6, 0.001], XAGUSD: [27.4, 30.8, 0.001], US30: [37800, 39600, 0.1],
  BTCUSD: [61200, 67800, 1], AUDUSD: [0.642, 0.668, 0.00001],
};
function buildPositions(rows) {
  const rng = mulberry32(0x9F1CE);
  const out = [];
  let ticket = 740219;
  for (const r of rows) {
    if (r.openPos <= 0) continue;
    const [lo, hi, prec] = PX[r.symbol];
    const digits = prec < 0.001 ? 5 : prec < 0.1 ? 3 : 1;
    let remaining = r.floating;
    for (let k = 0; k < r.openPos; k++) {
      ticket += Math.floor(1 + rng() * 40);
      const entry = lo + rng() * (hi - lo);
      const lots = Math.round((0.05 + rng() * 0.9) * 100) / 100;
      // last position absorbs the remainder so positions sum to row.floating
      const pl = k === r.openPos - 1 ? remaining : Math.round((rng() - 0.45) * (r.floating / r.openPos) * 2);
      remaining -= pl;
      const dir = r.side === "BUY" ? 1 : -1;
      const contract = r.symbol === "BTCUSD" ? 1 : r.symbol === "US30" ? 1 : r.symbol.includes("JPY") ? 1000 : r.symbol.startsWith("XAU") ? 100 : r.symbol.startsWith("XAG") ? 5000 : 100000;
      const move = pl / (dir * contract * lots);
      const cur = entry + move;
      const pips = Math.round((cur - entry) / (prec * 10) * dir);
      const hrs = Math.floor(rng() * 9), mins = Math.floor(rng() * 60);
      out.push({
        ticket, set: r.id, vps: r.vps, account: r.account, symbol: r.symbol,
        side: r.side, lots, entry: entry.toFixed(digits), cur: cur.toFixed(digits),
        pips, pl: Math.round(pl), swap: Math.round((rng() - 0.6) * 14),
        age: `${hrs}h ${String(mins).padStart(2, "0")}m`, mode: r.mode,
      });
    }
  }
  return out;
}

const HEDGE_COLORS = ["#ECBA5A", "#5ED1C7", "#D9A6E2", "#36D98F", "#F2A35E", "#7FB2F0"];
function buildMonitor() {
  const rng = mulberry32(0x4ED93);
  const out = [];
  const pairSymbols = ["XAUUSD", "EURUSD", "US30", "BTCUSD", "GBPUSD", "XAGUSD"];

  const mkRow = (sym, dir, entry, riskDist, prec, hedge) => {
    const digits = prec < 0.001 ? 5 : prec < 0.1 ? 3 : 1;
    const rr = 1.3 + rng() * 2.1; // reward:risk
    const sl = dir === "BUY" ? entry - riskDist : entry + riskDist;
    const tp = dir === "BUY" ? entry + riskDist * rr : entry - riskDist * rr;
    let r = Math.round((-1.6 + rng() * 4.3) * 10) / 10; // -1.6R .. 2.7R
    let trail = r >= 1.0 ? "trailing" : r >= 0.45 ? "armed" : "idle";
    return {
      sym, dir, lot: Math.round((0.05 + rng() * 1.45) * 100) / 100,
      entry: entry.toFixed(digits), sl: sl.toFixed(digits), tp: tp.toFixed(digits),
      r, trail, hedge,
    };
  };

  pairSymbols.forEach((sym, i) => {
    const [lo, hi, prec] = PX[sym];
    const entry = lo + rng() * (hi - lo);
    const riskDist = (hi - lo) * (0.04 + rng() * 0.05);
    const gid = `H${i + 1}`, color = HEDGE_COLORS[i % HEDGE_COLORS.length];
    out.push(mkRow(sym, "BUY", entry, riskDist, prec, { id: gid, color, partner: "SELL" }));
    out.push(mkRow(sym, "SELL", entry + riskDist * (rng() - 0.5) * 0.4, riskDist, prec, { id: gid, color, partner: "BUY" }));
  });

  const soloSyms = ["USDJPY", "AUDUSD", "XAUUSD", "EURUSD", "BTCUSD", "GBPUSD", "US30", "XAGUSD"];
  soloSyms.forEach((sym) => {
    const [lo, hi, prec] = PX[sym];
    const entry = lo + rng() * (hi - lo);
    const riskDist = (hi - lo) * (0.04 + rng() * 0.05);
    out.push(mkRow(sym, rng() < 0.5 ? "BUY" : "SELL", entry, riskDist, prec, null));
  });

  // shuffle but keep hedge partners adjacent: interleave pairs, then solos
  const pairs = [];
  for (let i = 0; i < 12; i += 2) pairs.push([out[i], out[i + 1]]);
  const solos = out.slice(12);
  const seq = [];
  // weave some solos between pairs for a natural blotter feel
  const order = [0, 1, "s", "s", 2, 3, "s", "s", 4, "s", 5, "s", "s", "s"];
  let pi = 0, si = 0;
  for (const o of order) {
    if (o === "s") { if (si < solos.length) seq.push(solos[si++]); }
    else if (pi < pairs.length && o === pi) { seq.push(pairs[pi][0], pairs[pi][1]); pi++; }
  }
  while (pi < pairs.length) { seq.push(pairs[pi][0], pairs[pi][1]); pi++; }
  while (si < solos.length) seq.push(solos[si++]);
  return seq.map((row, idx) => ({ ...row, ticket: 752100 + idx * 7 }));
}

const DINASTY = (() => {
  const rows = buildRows();
  const overview = buildOverview(rows);
  const equityCurve = buildEquityCurve(overview.totalEquity);
  const alerts = buildAlerts(rows);

  // Per-VPS health rollup
  const vpsHealth = ["VPS-1", "VPS-2"].map((vps) => {
    const rs = rows.filter((r) => r.vps === vps);
    const pl = rs.reduce((a, r) => a + r.pl, 0);
    const risky = rs.filter((r) => r.risky).length;
    const open = rs.filter((r) => r.openPos > 0).length;
    return { vps, sets: rs.length, pl, risky, open };
  });

  return { rows, overview, equityCurve, alerts, vpsHealth, positions: buildPositions(rows), monitor: buildMonitor() };
})();

window.DINASTY = DINASTY;
