/* sleeves.jsx — Tool12: forward-test pre-registrato a 4 sleeve meccaniche.
   Card per sleeve (NAV, cum vs target, posizioni, badge KILLED) + sparkline SVG,
   tabelle ordini/trade, storico settimanale. Refresh 5 min + run-now. */

(function () {
  const { useState, useEffect, useRef } = React;

  function Spark({ curve, capital, width = 260, height = 56 }) {
    if (!curve || curve.length < 2) return <div className="muted" style={{ fontSize: 12 }}>NAV in costruzione…</div>;
    const vals = curve.map(p => p.nav);
    const min = Math.min(...vals, capital), max = Math.max(...vals, capital);
    const span = (max - min) || 1;
    const pts = vals.map((v, i) =>
      `${(i / (vals.length - 1)) * width},${height - ((v - min) / span) * height}`).join(" ");
    const capY = height - ((capital - min) / span) * height;
    const up = vals[vals.length - 1] >= capital;
    return (
      <svg width="100%" viewBox={`0 0 ${width} ${height}`} preserveAspectRatio="none" style={{ display: "block" }}>
        <line x1="0" y1={capY} x2={width} y2={capY} stroke="var(--border)" strokeDasharray="3,3" />
        <polyline points={pts} fill="none" strokeWidth="1.6"
                  stroke={up ? "var(--green, #22c55e)" : "var(--red, #ef4444)"} />
      </svg>
    );
  }

  function SleeveCard({ s, target }) {
    const [open, setOpen] = useState(false);
    const killed = s.status === "KILLED";
    const cumOk = s.cum_pnl >= 0;
    const trades = s.trades || [];
    const orders = s.orders || [];
    const green = "var(--green, #22c55e)", red = "var(--red, #ef4444)";
    const shortTs  = (ts) => (ts || "").slice(5, 16).replace("T", " ");  // MM-DD HH:MM
    const shortDay = (ts) => (ts || "").slice(5, 10);                    // MM-DD
    const actLabel = (t) => t.action === "EXIT" ? "Chiudi" : (t.side === "SHORT" ? "Apri short" : "Apri long");
    const stColor  = (st) => st === "FILLED" ? green : st === "REJECTED" ? red : "var(--amber, #f59e0b)";

    return (
      <div className="card" style={{ opacity: killed ? 0.65 : 1 }}>
        <div onClick={() => setOpen(v => !v)} title="Clicca per trade e ordini"
             style={{ cursor: "pointer", display: "flex", justifyContent: "space-between", alignItems: "baseline" }}>
          <b>{open ? "▾ " : "▸ "}{s.key} · {s.name}</b>
          {killed
            ? <span className="badge" style={{ background: red, color: "#fff" }}>☠️ KILLED</span>
            : <span className="badge">{s.positions.length} pos</span>}
        </div>
        <div style={{ display: "flex", gap: 16, margin: "6px 0", alignItems: "baseline" }}>
          <span style={{ fontSize: 22, fontWeight: 700 }}>€{s.nav.toFixed(0)}</span>
          <span style={{ color: cumOk ? green : red, fontWeight: 600 }}>
            {s.cum_pnl >= 0 ? "+" : ""}{s.cum_pnl.toFixed(2)}€
          </span>
          {s.consec_below > 0 && !killed &&
            <span className="muted" style={{ fontSize: 12 }}>sotto soglia {s.consec_below}/8</span>}
        </div>
        <Spark curve={s.nav_curve} capital={s.capital} />
        {killed && s.kill_reason &&
          <div className="muted" style={{ fontSize: 12, marginTop: 6 }}>{s.kill_reason}</div>}
        {s.positions.length > 0 && (
          <table className="mini" style={{ width: "100%", marginTop: 8, fontSize: 12 }}>
            <thead><tr><th style={{ textAlign: "left" }}>Pos</th><th>Lato</th><th>Entry</th><th>Ultimo</th><th>P&L</th><th>Uscita</th></tr></thead>
            <tbody>
              {s.positions.map(p => (
                <tr key={p.symbol}>
                  <td className="mono">{p.symbol}{p.leverage > 1 ? ` ×${p.leverage}` : ""}</td>
                  <td style={{ textAlign: "center" }}>{p.side === "SHORT" ? "▼ short" : "▲ long"}</td>
                  <td style={{ textAlign: "right" }}>{p.entry}</td>
                  <td style={{ textAlign: "right" }}>{p.last}</td>
                  <td style={{ textAlign: "right", color: p.pnl_pct >= 0 ? green : red }}>
                    {p.pnl_pct >= 0 ? "+" : ""}{p.pnl_pct}%</td>
                  <td style={{ textAlign: "right" }} className="muted">{shortDay(p.planned_exit) || "—"}</td>
                </tr>))}
            </tbody>
          </table>
        )}
        {s.pending_orders.length > 0 && (
          <div className="muted" style={{ fontSize: 12, marginTop: 6 }}>
            ⏳ {s.pending_orders.length} ordini in attesa di fill: {s.pending_orders.map(o =>
              `${o.action === "EXIT" ? "chiudi" : (o.side === "SHORT" ? "short" : "compra")} ${o.symbol}`).join(", ")}
          </div>
        )}

        {!open && (
          <div className="muted" style={{ fontSize: 11.5, marginTop: 8, cursor: "pointer" }} onClick={() => setOpen(true)}>
            ▸ {trades.length} trade · {orders.length} ordini — clicca per il dettaglio
          </div>
        )}

        {open && (
          <div style={{ marginTop: 10, borderTop: "1px solid var(--border)", paddingTop: 8 }}>
            <div style={{ fontWeight: 600, fontSize: 12.5, margin: "2px 0 4px" }}>Trade eseguiti (a che prezzo)</div>
            {trades.length === 0
              ? <div className="muted" style={{ fontSize: 12 }}>Nessun trade ancora.</div>
              : <table className="mini" style={{ width: "100%", fontSize: 11.5 }}>
                  <thead><tr><th style={{ textAlign: "left" }}>Quando</th><th style={{ textAlign: "left" }}>Azione</th><th>Prezzo</th><th>Quote</th><th>P&L</th></tr></thead>
                  <tbody>
                    {trades.map((t, i) => (
                      <tr key={i}>
                        <td className="muted">{shortTs(t.timestamp)}</td>
                        <td><span className="mono">{t.symbol}</span> {actLabel(t)}</td>
                        <td style={{ textAlign: "right" }}>{t.price != null ? t.price.toFixed(2) : "—"}</td>
                        <td style={{ textAlign: "right" }}>{t.shares}</td>
                        <td style={{ textAlign: "right", color: t.pnl_eur == null ? "var(--text-muted)" : (t.pnl_eur >= 0 ? green : red) }}>
                          {t.pnl_eur == null ? "—" : (t.pnl_eur >= 0 ? "+" : "") + t.pnl_eur.toFixed(2) + "€"}</td>
                      </tr>))}
                  </tbody>
                </table>}

            <div style={{ fontWeight: 600, fontSize: 12.5, margin: "10px 0 4px" }}>Ordini</div>
            {orders.length === 0
              ? <div className="muted" style={{ fontSize: 12 }}>Nessun ordine.</div>
              : <table className="mini" style={{ width: "100%", fontSize: 11.5 }}>
                  <thead><tr><th style={{ textAlign: "left" }}>Quando</th><th style={{ textAlign: "left" }}>Ordine</th><th>Stato</th><th>Fill</th></tr></thead>
                  <tbody>
                    {orders.map((o, i) => (
                      <tr key={i} title={o.reject_reason || ""}>
                        <td className="muted">{shortTs(o.signal_ts)}</td>
                        <td><span className="mono">{o.symbol}</span> {o.action === "EXIT" ? "chiudi" : (o.side === "SHORT" ? "short" : "long")}</td>
                        <td style={{ textAlign: "center", color: stColor(o.status), fontWeight: 600 }}>{o.status}</td>
                        <td style={{ textAlign: "right" }}>{o.fill_price != null ? o.fill_price.toFixed(2) : (o.reject_reason ? "✗" : "—")}</td>
                      </tr>))}
                  </tbody>
                </table>}
            <div className="muted" style={{ fontSize: 10.5, marginTop: 6 }}>
              Sleeve meccaniche: l'uscita è per <b>tempo/segnale</b> (colonna "Uscita"), non con stop-loss.
              Fill al primo prezzo DOPO il segnale. ✗ = ordine scartato (vedi tooltip).
            </div>
          </div>
        )}
      </div>
    );
  }

  window.SleevesView = function SleevesView() {
    const [data, setData] = useState(null);
    const [weeks, setWeeks] = useState([]);
    const [err, setErr] = useState(null);
    const [running, setRunning] = useState(false);
    const timer = useRef(null);

    const load = () => {
      fetch("/api/sleeves").then(r => r.json()).then(d => {
        if (d.error) setErr(d.error); else { setData(d); setErr(null); }
      }).catch(e => setErr(String(e)));
      fetch("/api/sleeves/history").then(r => r.json())
        .then(d => setWeeks(d.weeks || [])).catch(() => {});
    };
    useEffect(() => {
      load();
      timer.current = setInterval(load, 5 * 60 * 1000);
      return () => clearInterval(timer.current);
    }, []);

    const runNow = () => {
      setRunning(true);
      fetch("/api/sleeves/run-now", { method: "POST" })
        .then(() => setTimeout(() => { setRunning(false); load(); }, 4000))
        .catch(() => setRunning(false));
    };

    if (err) return <div className="card">Errore: {err}</div>;
    if (!data) return <div className="card">Caricamento sleeve…</div>;

    const target = (data.weekly_target_total || 90) / Math.max(1, data.sleeves.length);
    const totNav = data.sleeves.reduce((a, s) => a + s.nav, 0);
    const totCum = data.sleeves.reduce((a, s) => a + s.cum_pnl, 0);
    const byWeek = {};
    weeks.forEach(w => { (byWeek[w.week_start] = byWeek[w.week_start] || []).push(w); });
    const weekKeys = Object.keys(byWeek).sort().reverse();

    return (
      <div className="view-scroll">
        {data.blocked && (
          <div className="card" style={{ borderColor: "var(--red, #ef4444)" }}>
            🚫 <b>MOTORE BLOCCATO</b>: config/sleeves.json modificato senza bump di versione.
            Il forward-test non sta girando.
          </div>
        )}
        <div className="card" style={{ display: "flex", gap: 18, alignItems: "baseline", flexWrap: "wrap" }}>
          <span><b>Forward-test</b> v{data.version} <span className="mono muted">({data.hash})</span></span>
          <span className="muted">registrato: {data.registered_at || "—"}</span>
          <span style={{ fontSize: 18, fontWeight: 700 }}>NAV €{totNav.toFixed(0)}</span>
          <span style={{ fontWeight: 600, color: totCum >= 0 ? "var(--green, #22c55e)" : "var(--red, #ef4444)" }}>
            cum {totCum >= 0 ? "+" : ""}{totCum.toFixed(2)}€</span>
          <span className="muted">target €{data.weekly_target_total}/sett (€{target.toFixed(2)}/sleeve)</span>
          <button className="btn btn-sm" onClick={runNow} disabled={running}>
            {running ? "In esecuzione…" : "▶ Run now"}</button>
        </div>
        <div style={{ display: "grid", gridTemplateColumns: "repeat(auto-fill, minmax(300px, 1fr))", gap: 12 }}>
          {data.sleeves.map(s => <SleeveCard key={s.key} s={s} target={target} />)}
        </div>
        {weekKeys.length > 0 && (
          <div className="card" style={{ marginTop: 12 }}>
            <b>Storico settimanale</b>
            <table className="mini" style={{ width: "100%", marginTop: 8, fontSize: 12 }}>
              <thead><tr><th style={{ textAlign: "left" }}>Settimana</th>
                {data.sleeves.map(s => <th key={s.key}>{s.key}</th>)}<th>TOT</th><th>Target cum</th></tr></thead>
              <tbody>
                {weekKeys.map(wk => {
                  const rows = byWeek[wk];
                  const get = k => rows.find(r => r.sleeve === k);
                  const tot = rows.reduce((a, r) => a + (r.pnl_eur || 0), 0);
                  const cumT = rows.reduce((a, r) => Math.max(a, r.cum_target_eur || 0), 0) * data.sleeves.length / 1;
                  return (
                    <tr key={wk}>
                      <td className="mono">{wk}</td>
                      {data.sleeves.map(s => {
                        const r = get(s.key);
                        const v = r ? r.pnl_eur : null;
                        return <td key={s.key} style={{ textAlign: "right",
                          color: v == null ? "inherit" : (v >= 0 ? "var(--green, #22c55e)" : "var(--red, #ef4444)") }}>
                          {v == null ? "—" : (v >= 0 ? "+" : "") + v.toFixed(1)}{r && r.status === "KILLED" ? " ☠️" : ""}</td>;
                      })}
                      <td style={{ textAlign: "right", fontWeight: 600,
                                   color: tot >= 0 ? "var(--green, #22c55e)" : "var(--red, #ef4444)" }}>
                        {(tot >= 0 ? "+" : "") + tot.toFixed(1)}</td>
                      <td style={{ textAlign: "right" }} className="muted">
                        {rows[0] ? (rows.reduce((a, r) => a + (r.cum_target_eur || 0), 0)).toFixed(0) : "—"}</td>
                    </tr>);
                })}
              </tbody>
            </table>
          </div>
        )}
        <div className="muted" style={{ fontSize: 12, marginTop: 10 }}>
          Regole pre-registrate in config/sleeves.json (hash verificato a ogni ciclo) ·
          fill al primo prezzo disponibile DOPO il segnale · costi €1 + 0.1% + 5bps per lato ·
          kill automatico: DD &gt;15% o 8 settimane sotto −50% del target pro-quota.
        </div>
      </div>
    );
  };
})();
