/* QUANTA · Detail enrichments + Alerts panel
   - QAlertsPanel: slide-in side panel listing recent edge events
   - QKellyCard: best-edge → Kelly/3 stake suggestion
   - QEventLog: recent ticks/score events for a match
   - QEvolutionChart: multi-bookmaker line chart per side
   Loads after quanta-app.jsx and assigns components on window. */

const { useEffect: useEffect_d, useState: useState_d, useMemo: useMemo_d, useRef: useRef_d } = React;

/* ──────────────────────────────────────────────────────────
   ALERTS PANEL
   ────────────────────────────────────────────────────────── */
function QAlertsPanel({ open, onClose, alerts, tick, onOpenMatch }) {
  const closeRef = useRef_d(null);
  // Lock body scroll while open
  useEffect_d(() => {
    if (open) {
      const prev = document.body.style.overflow;
      document.body.style.overflow = "hidden";
      return () => { document.body.style.overflow = prev; };
    }
  }, [open]);

  // Close on Esc
  useEffect_d(() => {
    if (!open) return;
    const onKey = (e) => { if (e.key === "Escape") onClose(); };
    window.addEventListener("keydown", onKey);
    return () => window.removeEventListener("keydown", onKey);
  }, [open, onClose]);

  // Focus trap: transfer focus to the close button on open so keyboard
  // users land inside the dialog instead of the trigger button outside.
  useEffect_d(() => {
    if (open && closeRef.current) closeRef.current.focus();
  }, [open]);

  return (
    <>
      <div className={"q-alerts-backdrop" + (open ? " is-open" : "")} onClick={onClose}></div>
      <aside
        className={"q-alerts" + (open ? " is-open" : "")}
        role="dialog"
        aria-modal={open ? "true" : "false"}
        aria-hidden={!open}
        aria-label="Alertes value-bets"
      >
        <div className="q-alerts-head">
          <div className="q-alerts-h-title">Alertes · {alerts.length}</div>
          <button ref={closeRef} className="q-alerts-close" onClick={onClose} aria-label="Close">
            <svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2"><path d="M18 6L6 18M6 6l12 12"/></svg>
          </button>
        </div>
        <div className="q-alerts-tools">
          <span>SEUIL</span>
          <b>≥ 3%</b>
          <span style={{color: "var(--ink-3)"}}>·</span>
          <span>SOURCES</span>
          <b>ALL</b>
          <span style={{color: "var(--ink-3)"}}>·</span>
          <span style={{marginLeft: "auto", color: "var(--ink-3)"}}>LIVE FEED</span>
        </div>
        <div className="q-alerts-list">
          {alerts.length === 0 ? (
            <div className="q-alerts-empty">
              En attente d'un nouvel edge…<br/>
              <span style={{color: "var(--ink-4)"}}>Les value-bets ≥ seuil apparaîtront ici.</span>
            </div>
          ) : alerts.map(ev => {
            const age = Date.now() / 1000 - ev.ts;
            const ageText = age < 1 ? "now" : age < 60 ? `${Math.round(age)}s` : `${Math.round(age/60)}m`;
            const isStrong = (ev.edge || 0) >= 0.05;
            const oddsText = ev.odds && ev.odds > 0 ? `@ ${ev.odds.toFixed(2)}` : "";
            const tournamentLabel = (ev.tournament || "").toString().toUpperCase();
            return (
              <div key={ev.id} className="q-alert" onClick={() => onOpenMatch(ev.matchKey)}>
                <div className={"q-alert-edge" + (isStrong ? "" : " warn")}>
                  {((ev.edge || 0) * 100).toFixed(1)}%
                </div>
                <div className="q-alert-body">
                  <div className="q-alert-players">
                    {ev.p1} vs {ev.p2}
                  </div>
                  <div className="q-alert-meta">
                    {tournamentLabel} · <b>{(ev.bm || "").toUpperCase()}</b> sur <b>{(ev.pick||"").split(",")[0]}</b> {oddsText}
                  </div>
                </div>
                <div className="q-alert-time">{ageText}</div>
              </div>
            );
          })}
        </div>
      </aside>
    </>
  );
}

/* ──────────────────────────────────────────────────────────
   KELLY / 3 STAKE CARD
   ────────────────────────────────────────────────────────── */
function QKellyCard({ match, divisor = 3 }) {
  // Find best positive edge across all BMs and both sides.
  // Kelly fraction = edge / (odds - 1). We display Kelly/divisor (user-set).
  const candidates = [];
  for (const [name, b] of Object.entries(match.bm)) {
    if (b.e1 != null && b.e1 > 0 && b.p1 != null) candidates.push({ bm: name, side: "p1", odds: b.p1, edge: b.e1 });
    if (b.e2 != null && b.e2 > 0 && b.p2 != null) candidates.push({ bm: name, side: "p2", odds: b.p2, edge: b.e2 });
    // Football 1X2 markets expose a draw side. Tennis dicts never carry
    // eDraw so this branch is a natural no-op there.
    if (b.eDraw != null && b.eDraw > 0 && b.draw != null) candidates.push({ bm: name, side: "draw", odds: b.draw, edge: b.eDraw });
  }
  candidates.sort((a, b) => b.edge - a.edge);
  const best = candidates[0];

  if (!best) {
    return (
      <div className="q-kelly no-edge">
        <div className="q-kelly-h">Kelly / {divisor} · stake suggéré</div>
        <div className="q-kelly-main">
          <div className="q-kelly-val">0%</div>
          <div className="q-kelly-sub">Aucun edge positif disponible — ne rien parier.</div>
        </div>
        <div className="q-kelly-formula">
          Le système ne recommande de mise que lorsqu'un BM offre une cote au-dessus de la baseline <b>Betfair LAY</b>.
        </div>
      </div>
    );
  }

  const pickName = best.side === "draw"
    ? "Match nul"
    : (best.side === "p1" ? match.p1 : match.p2);
  const pickShortName = best.side === "draw" ? "X (match nul)" : pickName.split(",")[0];
  const kelly = best.edge / (best.odds - 1);
  const kellyDiv = kelly / divisor;
  const bfBaseline = match.bf ? (best.side === "draw" ? match.bf.draw : (best.side === "p1" ? match.bf.p1 : match.bf.p2)) : null;
  // HelpTip lives on window (defined in quanta-app.jsx, assigned globally by babel).
  const Help = (typeof HelpTip !== "undefined") ? HelpTip : (({children}) => children);
  return (
    <div className="q-kelly">
      <div className="q-kelly-h">
        <Help label="Kelly = mise optimale théorique. /N = on divise pour réduire variance & drawdown. /3 est le compromis croissance/risque recommandé.">
          Kelly / {divisor} · stake suggéré
        </Help>
      </div>
      <div className="q-kelly-main">
        <div className="q-kelly-val">{(kellyDiv * 100).toFixed(2)}%</div>
        <div className="q-kelly-sub">de la bankroll · {pickShortName} @ <b>{best.odds.toFixed(2)}</b> chez {best.bm}</div>
      </div>
      <div className="q-kelly-row">
        <div className="q-kelly-cell">
          <div className="lbl">Edge</div>
          <div className="v">+{(best.edge * 100).toFixed(2)}%</div>
        </div>
        <div className="q-kelly-cell">
          <div className="lbl">Kelly full</div>
          <div className="v">{(kelly * 100).toFixed(2)}%</div>
        </div>
        <div className="q-kelly-cell">
          <div className="lbl">Sur 1000 €</div>
          <div className="v">{(kellyDiv * 1000).toFixed(2)} €</div>
        </div>
        <div className="q-kelly-cell">
          <div className="lbl">Profit attendu</div>
          <div className="v">+{(kellyDiv * 1000 * (best.odds - 1)).toFixed(2)} €</div>
        </div>
      </div>
      <div className="q-kelly-formula">
        <b>f* = edge / (odds − 1)</b> · on prend f* / {divisor} (modifiable dans ton profil) · base : BF LAY {bfBaseline != null ? bfBaseline.toFixed(2) : "—"}
      </div>
    </div>
  );
}

/* ──────────────────────────────────────────────────────────
   EVENT LOG
   ────────────────────────────────────────────────────────── */
function QEventLog({ match, tick }) {
  const events = match.events || [];
  return (
    <div className="q-events">
      <div className="q-events-h">Event log</div>
      {events.length === 0 ? (
        <div style={{color: "var(--ink-3)", fontFamily: "IBM Plex Mono, monospace", fontSize: 12}}>—</div>
      ) : events.map((ev, i) => {
        const age = Math.max(0, Date.now() / 1000 - ev.ts);
        const t = age < 60 ? `${Math.round(age)}s` : `${Math.round(age/60)}m`;
        return (
          <div key={i} className="q-event">
            <div className="q-event-time">{t}</div>
            <div className="q-event-body">
              <span className={"q-event-tag " + (ev.kind === "edge" ? "edge" : ev.kind === "score" ? "score" : "")}>{ev.kind || "tick"}</span>
              <span className="q-event-text">{ev.text}</span>
            </div>
          </div>
        );
      })}
    </div>
  );
}

/* ──────────────────────────────────────────────────────────
   EVOLUTION CHART (multi-bookmaker line chart per side)
   ────────────────────────────────────────────────────────── */
function QEvolutionChart({ match, side, height = 220 }) {
  // Collect all series for this side; BF goes dashed as baseline.
  const series = match.history[side];
  const names = Object.keys(series);
  if (!names.length) return null;
  const allPts = names.flatMap(n => series[n]);
  const min = Math.min(...allPts);
  const max = Math.max(...allPts);
  const pad = 0.04 * (max - min || 1);
  const yMin = min - pad;
  const yMax = max + pad;
  const range = yMax - yMin;
  const n = series[names[0]].length;
  const w = 520, h = height;
  const padding = { l: 38, r: 8, t: 8, b: 22 };
  const innerW = w - padding.l - padding.r;
  const innerH = h - padding.t - padding.b;
  const xFor = (i) => padding.l + (i / Math.max(1, n - 1)) * innerW;
  const yFor = (v) => padding.t + innerH - ((v - yMin) / range) * innerH;
  // y-axis ticks
  const ySteps = 4;
  const yTicks = [];
  for (let k = 0; k <= ySteps; k++) {
    const v = yMin + (range * k / ySteps);
    yTicks.push({ v, y: yFor(v) });
  }
  const playerName = side === "p1" ? match.p1.split(",")[0] : match.p2.split(",")[0];
  const currentVal = match.bf[side];
  return (
    <div className="q-chart-block">
      <div className="q-chart-title">
        <span className="who">{playerName} · cotes</span>
        <span className="now">BF {currentVal != null ? currentVal.toFixed(2) : "—"}</span>
      </div>
      <div className="q-chart-svg">
        <svg viewBox={`0 0 ${w} ${h}`} preserveAspectRatio="none">
          {/* y gridlines */}
          {yTicks.map((t, i) => (
            <g key={i}>
              <line
                x1={padding.l} y1={t.y} x2={w - padding.r} y2={t.y}
                stroke="var(--line)" strokeWidth="1" strokeDasharray={i === 0 || i === ySteps ? "0" : "2 3"}
              />
              <text
                x={padding.l - 6} y={t.y + 3} textAnchor="end"
                fontSize="9.5" fontFamily="IBM Plex Mono, monospace"
                fill="var(--ink-3)"
              >{t.v.toFixed(2)}</text>
            </g>
          ))}
          {/* x labels (only first / last) */}
          <text x={padding.l} y={h - 6} fontSize="9.5" fontFamily="IBM Plex Mono, monospace" fill="var(--ink-3)">-24t</text>
          <text x={w - padding.r} y={h - 6} textAnchor="end" fontSize="9.5" fontFamily="IBM Plex Mono, monospace" fill="var(--ink-3)">now</text>

          {/* Lines */}
          {names.map(name => {
            const isBF = name === "Betfair";
            const color = isBF ? "var(--warn)" : (window.MOCK.BMS[name] || {}).color;
            const pts = series[name].map((v, i) => `${xFor(i).toFixed(1)},${yFor(v).toFixed(1)}`).join(" ");
            return (
              <polyline
                key={name}
                points={pts}
                fill="none"
                stroke={color}
                strokeWidth={isBF ? "2" : "1.6"}
                strokeDasharray={isBF ? "5 4" : "0"}
                vectorEffect="non-scaling-stroke"
              />
            );
          })}

          {/* Dot at last point of BF */}
          <circle cx={xFor(n - 1)} cy={yFor(series.Betfair[n-1])} r="3" fill="var(--warn)" />
        </svg>
      </div>
      <div className="q-chart-legend">
        <span className="leg bf"><span className="swatch"></span>BF LAY</span>
        {Object.keys(match.bm).map(name => (
          <span key={name} className="leg" style={{color: (window.MOCK.BMS[name] || {}).color}}>
            <span className="swatch"></span>{name}
          </span>
        ))}
      </div>
    </div>
  );
}

function QChartPanel({ match }) {
  const [chartSide, setChartSide] = useState_d("both"); // 'both' | 'p1' | 'p2'
  return (
    <div className="q-chart-panel">
      <div className="q-chart-h">
        <div className="q-chart-h-title">Évolution des cotes · 24 derniers ticks</div>
        <div className="q-chart-tabs">
          <button className={"q-chart-tab" + (chartSide === "both" ? " is-active" : "")} onClick={() => setChartSide("both")}>P1 + P2</button>
          <button className={"q-chart-tab" + (chartSide === "p1" ? " is-active" : "")} onClick={() => setChartSide("p1")}>{match.p1.split(",")[0]}</button>
          <button className={"q-chart-tab" + (chartSide === "p2" ? " is-active" : "")} onClick={() => setChartSide("p2")}>{match.p2.split(",")[0]}</button>
        </div>
      </div>
      <div className="q-chart-grid" style={chartSide === "both" ? {} : { gridTemplateColumns: "1fr" }}>
        {(chartSide === "both" || chartSide === "p1") && <QEvolutionChart match={match} side="p1" />}
        {(chartSide === "both" || chartSide === "p2") && <QEvolutionChart match={match} side="p2" />}
      </div>
    </div>
  );
}

Object.assign(window, { QAlertsPanel, QKellyCard, QEventLog, QEvolutionChart, QChartPanel });
