// ── ChainView (Tool10 — Lead-Lag) ────────────────────────────────────────────
// "Quando il leader A sale, i follower B/C tendono a seguire nei giorni dopo."
// Esplorativo, NON un backtest: la correlazione lead-lag è associazione
// statistica, il movimento del leader può essere già prezzato.

function ChainView() {
  const [chains, setChains]       = useState([]);
  const [date, setDate]           = useState("");
  const [generatedAt, setGeneratedAt] = useState(null);
  const [loading, setLoading]     = useState(true);
  const [error, setError]         = useState(null);
  const [expanded, setExpanded]   = useState(null);
  const [runStatus, setRunStatus] = useState(null);
  const [showLegend, setShowLegend] = useState(false);
  const [filterText, setFilterText] = useState("");

  const load = async (showSpinner) => {
    if (showSpinner) setLoading(true);
    try {
      const r = await fetch("/api/chain").then(r => r.json());
      setChains(r.chains || []);
      setDate(r.date || "");
      setGeneratedAt(r.generated_at || null);
      setError(r.error || null);
    } catch (e) { setError(String(e)); }
    finally { if (showSpinner) setLoading(false); }
  };

  useEffect(() => {
    load(true);
    const t = setInterval(() => load(false), 5 * 60 * 1000);
    return () => clearInterval(t);
  }, []);

  const runNow = async () => {
    setRunStatus("running");
    try {
      await fetch("/api/chain/run-now", { method: "POST" });
      // Dopo il lancio, poll ogni 30s finché il timestamp cambia (max 15 min)
      const prevTs = generatedAt;
      let attempts = 0;
      const poll = setInterval(async () => {
        attempts++;
        try {
          const r = await fetch("/api/chain").then(r => r.json());
          if (r.generated_at && r.generated_at !== prevTs) {
            clearInterval(poll);
            setChains(r.chains || []);
            setDate(r.date || "");
            setGeneratedAt(r.generated_at);
            setRunStatus("ok");
            setTimeout(() => setRunStatus(null), 5000);
          }
        } catch {}
        if (attempts >= 30) { clearInterval(poll); setRunStatus("ok"); setTimeout(() => setRunStatus(null), 3000); }
      }, 30000);
    } catch { setRunStatus("err"); }
  };

  const pct = (v) => v == null ? "—" : `${v > 0 ? "+" : ""}${(v * 100).toFixed(2)}%`;
  const prob = (v) => v == null ? "—" : `${(v * 100).toFixed(0)}%`;

  const scoreColor = (v) => {
    if (v == null) return "var(--text-muted)";
    if (v >= 70) return "var(--green)";
    if (v >= 55) return "var(--amber)";
    return "var(--text-muted)";
  };
  const liftColor = (v) => v == null ? "var(--text-muted)" : (v > 0 ? "var(--green)" : "var(--red)");

  // Mini-sparkline della corr per lag 1..5
  const Sparkline = ({ byLag, best }) => {
    if (!byLag) return null;
    const lags = Object.keys(byLag).sort((a, b) => +a - +b);
    if (!lags.length) return null;
    const vals = lags.map(k => byLag[k]);
    const maxAbs = Math.max(0.05, ...vals.map(Math.abs));
    const W = 54, H = 18, bw = W / lags.length;
    return (
      <svg width={W} height={H} style={{verticalAlign: "middle"}}>
        <line x1="0" y1={H/2} x2={W} y2={H/2} stroke="var(--border)" strokeWidth="1"/>
        {vals.map((v, i) => {
          const h = Math.abs(v) / maxAbs * (H/2 - 1);
          const up = v >= 0;
          const isBest = (+lags[i]) === best;
          return (
            <rect key={i} x={i*bw + 1} y={up ? H/2 - h : H/2} width={bw - 2} height={h}
              fill={isBest ? "var(--accent)" : (up ? "var(--green)" : "var(--red)")}
              opacity={isBest ? 1 : 0.55}/>
          );
        })}
      </svg>
    );
  };

  const LEGEND = [
    { name: "Leader",   desc: "Titolo che si muove per primo." },
    { name: "Follower", desc: "Titolo che tende a seguire il leader." },
    { name: "Lag",      desc: "Ritardo ottimale in giorni di borsa: il follower segue dopo N giorni (best_lag tra 1 e 5)." },
    { name: "Corr",     desc: "Correlazione ritardata sui RENDIMENTI (non sui prezzi) al lag ottimale. Segno = direzione." },
    { name: "Lag chart", desc: "Barre della correlazione per ciascun lag 1→5; la barra evidenziata è il lag ottimale." },
    { name: "P(su)",    desc: "Probabilità che il follower salga nei giorni successivi quando il leader sale ≥ soglia (default +2%)." },
    { name: "Lift",     desc: "Extra-rendimento medio del follower rispetto al suo drift naturale (baseline). Metrica chiave: lift>0 = il leader anticipa davvero." },
    { name: "Hit",      desc: "Frazione di eventi in cui il follower batte la sua baseline (il leader aggiunge segnale)." },
    { name: "Granger",  desc: "p-value del test di causalità di Granger sui rendimenti. Più basso = relazione statisticamente più solida (gate p≤0.01)." },
    { name: "N",        desc: "Numero di eventi (giorni in cui il leader è salito sopra soglia) usati per le statistiche." },
    { name: "Stab ✓",   desc: "Validazione out-of-sample: la relazione regge in ENTRAMBE le metà temporali della storia (stesso segno e magnitudo). ✓ = pattern stabile, non una coincidenza statistica. Passa il mouse per vedere la corr nelle due metà." },
    { name: "Score",    desc: "Punteggio 0-100 dell'edge: fonde |corr|, P(su), lift e bonus Granger." },
  ];

  // Filtra per leader o per qualsiasi follower
  const q = filterText.trim().toUpperCase();
  const visibleChains = q
    ? chains.filter(c =>
        c.leader.includes(q) ||
        (c.followers || []).some(f => f.follower.includes(q))
      ).map(c => {
        // se il filtro matcha solo un follower, espandi automaticamente il leader
        if (!c.leader.includes(q)) return { ...c, _autoExpand: true };
        return c;
      })
    : chains;

  if (loading) return (
    <div style={{padding: 32, color: "var(--text-muted)", textAlign: "center"}}>Caricamento chain…</div>
  );
  if (error && !chains.length) return (
    <div style={{padding: 32, color: "var(--red)"}}>Errore: {error}</div>
  );
  if (!chains.length) return (
    <div style={{padding: 32, color: "var(--text-muted)", textAlign: "center"}}>
      <p>Nessuno snapshot lead-lag disponibile.</p>
      <p style={{fontSize: 13, marginTop: 4}}>Avvia il primo run (richiede qualche minuto) oppure da CLI con <code>python -m tool10_chain.chain</code></p>
      <div style={{marginTop: 16}}>
        <button className="btn" onClick={runNow} disabled={runStatus === "running"}>
          <Icon name="chain" size={14}/>
          {runStatus === "running" ? " In corso…" : runStatus === "ok" ? " Avviato! Aggiorna tra qualche min" : runStatus === "err" ? " Errore (sei loggato?)" : " Avvia primo run"}
        </button>
      </div>
    </div>
  );

  const renderChain = (c) => {
    const isOpen = expanded === c.leader || !!c._forceExpand;
    const followers = c.followers || [];
    return (
      <React.Fragment key={c.leader}>
        <tr className={`chain-row ${isOpen ? "open" : ""}`} onClick={() => setExpanded(isOpen ? null : c.leader)}
            style={{cursor: "pointer"}}>
          <td style={{fontWeight: 700, fontFamily: "monospace", color: "var(--accent)"}}>
            {c.leader}
          </td>
          <td style={{fontSize: 12, color: "var(--text-muted)"}}>{c.leader_sector || "—"}</td>
          <td style={{textAlign: "center"}}>{c.n_followers}</td>
          <td style={{textAlign: "right", fontWeight: 600, color: scoreColor(c.chain_score)}}>
            {c.chain_score != null ? c.chain_score.toFixed(0) : "—"}
          </td>
          <td style={{fontSize: 12, color: "var(--text-muted)", maxWidth: 280, overflow: "hidden", textOverflow: "ellipsis", whiteSpace: "nowrap"}}>
            {followers.slice(0, 4).map(f => `${f.follower}(+${f.best_lag}g)`).join(" · ") || "—"}
          </td>
        </tr>
        {isOpen && (
          <tr className="chain-expand">
            <td colSpan={5}>
              <div style={{padding: "10px 14px", background: "var(--surface2)", borderRadius: 6, margin: "4px 0", overflowX: "auto"}}>
                <table style={{width: "100%", borderCollapse: "collapse", fontSize: 12}}>
                  <thead>
                    <tr style={{color: "var(--text-muted)", fontSize: 11, textAlign: "right"}}>
                      <th style={{textAlign: "left", padding: "4px 6px"}}>Follower</th>
                      <th style={{textAlign: "center"}}>Lag</th>
                      <th>Corr</th>
                      <th style={{textAlign: "center"}}>Lag chart</th>
                      <th>P(su)</th>
                      <th>Lift</th>
                      <th>Hit</th>
                      <th>Granger</th>
                      <th>N</th>
                      <th style={{textAlign: "center"}}>Stab</th>
                      <th>Score</th>
                    </tr>
                  </thead>
                  <tbody>
                    {followers.map(f => (
                      <tr key={f.follower} style={{borderTop: "1px solid var(--border)", textAlign: "right"}}>
                        <td style={{textAlign: "left", padding: "5px 6px", fontFamily: "monospace", fontWeight: 600}}>
                          {f.follower}
                          {f.follower_sector ? <span style={{color: "var(--text-muted)", fontWeight: 400, marginLeft: 6, fontSize: 11}}>{f.follower_sector}</span> : null}
                        </td>
                        <td style={{textAlign: "center"}}>+{f.best_lag}g</td>
                        <td style={{color: (f.corr || 0) >= 0 ? "var(--green)" : "var(--red)"}}>{f.corr != null ? f.corr.toFixed(2) : "—"}</td>
                        <td style={{textAlign: "center"}}><Sparkline byLag={f.corr_by_lag} best={f.best_lag}/></td>
                        <td>{prob(f.cond_prob_up)}</td>
                        <td style={{color: liftColor(f.lift), fontWeight: 600}}>{pct(f.lift)}</td>
                        <td>{prob(f.hit_rate)}</td>
                        <td style={{color: "var(--text-muted)"}}>{f.granger_p == null ? "—" : f.granger_p < 0.001 ? "<0.001" : f.granger_p.toFixed(3)}</td>
                        <td style={{color: "var(--text-muted)"}}>{f.sample_size}</td>
                        <td style={{textAlign: "center"}}
                            title={f.corr_h1 != null ? `Corr 1ª metà: ${f.corr_h1.toFixed(2)} · 2ª metà: ${f.corr_h2 != null ? f.corr_h2.toFixed(2) : "—"}` : "Non validato"}>
                          {f.stable ? <span style={{color: "var(--green)", fontWeight: 700}}>✓</span>
                            : f.stable === false ? <span style={{color: "var(--text-muted)"}}>—</span>
                            : <span style={{color: "var(--text-muted)"}}>·</span>}
                        </td>
                        <td style={{fontWeight: 600, color: scoreColor(f.edge_score)}}>{f.edge_score != null ? f.edge_score.toFixed(0) : "—"}</td>
                      </tr>
                    ))}
                  </tbody>
                </table>
              </div>
            </td>
          </tr>
        )}
      </React.Fragment>
    );
  };

  return (
    <div style={{flex: 1, minHeight: 0, overflowY: "auto", padding: "16px 20px"}}>
      <div style={{display: "flex", alignItems: "center", gap: 12, marginBottom: 12, flexWrap: "wrap"}}>
        <div style={{display: "flex", flexDirection: "column", gap: 1}}>
          <div>
            <span style={{fontSize: 13, color: "var(--text-muted)"}}>Snapshot: </span>
            <span style={{fontSize: 13, fontWeight: 600}}>{date || "—"}</span>
          </div>
          {generatedAt && (
            <div style={{fontSize: 11, color: "var(--text-muted)"}}>
              Generato: {generatedAt.replace("T", " ").slice(0, 16)}
            </div>
          )}
        </div>
        <div style={{position: "relative"}}>
          <input
            type="text"
            placeholder="Cerca ticker…"
            value={filterText}
            onChange={e => setFilterText(e.target.value)}
            style={{
              fontFamily: "var(--font-mono, monospace)", fontSize: 13,
              padding: "4px 28px 4px 8px", borderRadius: 6,
              border: "1px solid var(--border)", background: "var(--surface2)",
              color: "var(--text)", width: 140, outline: "none",
            }}
          />
          {filterText && (
            <button onClick={() => setFilterText("")} style={{
              position: "absolute", right: 6, top: "50%", transform: "translateY(-50%)",
              background: "none", border: "none", cursor: "pointer",
              color: "var(--text-muted)", fontSize: 14, lineHeight: 1, padding: 0,
            }}>✕</button>
          )}
        </div>
        {q && (
          <span style={{fontSize: 12, color: "var(--text-muted)"}}>
            {visibleChains.length} risultat{visibleChains.length === 1 ? "o" : "i"}
          </span>
        )}
        <div style={{marginLeft: "auto", display: "flex", gap: 8, alignItems: "center"}}>
          <div style={{position: "relative"}}>
            <button className="btn btn-sm" onClick={() => setShowLegend(v => !v)} title="Legenda colonne">
              <Icon name="info" size={13}/>
            </button>
            {showLegend && (
              <>
                <div onClick={() => setShowLegend(false)} style={{position:"fixed", inset:0, zIndex:199}}/>
                <div style={{
                  position: window.innerWidth <= 760 ? "fixed" : "absolute",
                  ...(window.innerWidth <= 760
                    ? { bottom: 70, left: "50%", transform: "translateX(-50%)", width: "calc(100vw - 32px)", maxWidth: 400 }
                    : { top: "calc(100% + 6px)", right: 0, width: 380 }),
                  zIndex: 200, background: "var(--bg-elevated)", border: "1px solid var(--border)",
                  borderRadius: "var(--radius-lg)", padding: "12px 14px", boxShadow: "var(--shadow-lg)",
                  fontSize: 12, maxHeight: "70vh", overflowY: "auto",
                }}>
                  <div style={{display:"flex", justifyContent:"space-between", alignItems:"center", marginBottom: 10}}>
                    <span style={{fontWeight: 700, fontSize: 13}}>Legenda</span>
                    <button className="icon-btn" onClick={() => setShowLegend(false)}>✕</button>
                  </div>
                  {LEGEND.map(c => (
                    <div key={c.name} style={{display: "flex", gap: 8, marginBottom: 7}}>
                      <span style={{fontFamily:"monospace", fontWeight:600, minWidth:78, color:"var(--accent)", flexShrink:0, fontSize:11}}>{c.name}</span>
                      <span style={{color:"var(--text-muted)", lineHeight:1.4}}>{c.desc}</span>
                    </div>
                  ))}
                </div>
              </>
            )}
          </div>
          <button className="btn btn-sm" onClick={() => load(false)} title="Aggiorna">
            <Icon name="refresh" size={13}/> Aggiorna
          </button>
          <button className="btn btn-sm" onClick={runNow} disabled={runStatus === "running"} title="Avvia un nuovo run Tool10">
            <Icon name="chain" size={13}/>
            {runStatus === "running" ? " In corso… (aggiorna auto)" : runStatus === "ok" ? " ✓ Aggiornato!" : " Run now"}
          </button>
        </div>
      </div>

      <div style={{fontSize: 12, color: "var(--text-muted)", marginBottom: 14, lineHeight: 1.5,
                   background: "var(--surface2)", padding: "8px 12px", borderRadius: 6}}>
        <strong>Come leggerlo:</strong> ogni riga è un <em>leader</em>; espandila per vedere i <em>follower</em> che
        storicamente salgono N giorni dopo. Correlazioni sui rendimenti (non sui prezzi), filtrate per causalità di
        Granger e <strong>validate out-of-sample</strong> (✓ Stab = il pattern regge in entrambe le metà della storia,
        quindi non è una coincidenza). <em>Strumento esplorativo, non un backtest tradabile.</em>
      </div>

      <div style={{overflowX: "auto"}}>
        <table className="chain-table" style={{width: "100%", borderCollapse: "collapse", fontSize: 13}}>
          <thead>
            <tr style={{borderBottom: "1px solid var(--border)", color: "var(--text-muted)", fontSize: 11}}>
              <th style={{padding: "6px 8px", textAlign: "left"}}>Leader</th>
              <th style={{padding: "6px 8px", textAlign: "left"}}>Settore</th>
              <th style={{padding: "6px 8px", textAlign: "center"}} title="Numero di follower">#Foll</th>
              <th style={{padding: "6px 8px", textAlign: "right"}} title="Punteggio catena (media top-5 edge)">Score</th>
              <th style={{padding: "6px 8px", textAlign: "left"}}>Follower (lag)</th>
            </tr>
          </thead>
          <tbody>
            {visibleChains.length === 0 && q ? (
              <tr><td colSpan={5} style={{padding: "20px 8px", color: "var(--text-muted)", textAlign: "center"}}>
                Nessuna chain trovata per «{q}»
              </td></tr>
            ) : visibleChains.map(c => renderChain({
                ...c,
                // auto-espandi se il filtro ha trovato solo un follower (non il leader)
                _forceExpand: c._autoExpand
              }))}
          </tbody>
        </table>
      </div>

      <style>{`
        .chain-row:hover td { background: var(--surface2); }
        .chain-row td { padding: 7px 8px; border-bottom: 1px solid var(--border); transition: background 0.1s; }
        .chain-row.open td { background: var(--surface2); }
        .chain-expand td { padding: 0 8px 8px; }
      `}</style>
    </div>
  );
}

window.ChainView = ChainView;
