// Dashboard view — chart + forecast cards rail

// ── Landscape touch-coordinate transformer ──────────────────────────────────
// CSS rotate(90deg) trasforma i pixel visivi ma NON le coordinate dei touch event.
// Questo componente intercetta i touch, ruota le coordinate di 90° CW inverso,
// e le ridispatcha come PointerEvent al canvas di LightweightCharts.
function LandscapeEventFix({ active, children }) {
  const ref = useRef(null);

  useEffect(() => {
    if (!active) return;
    const el = ref.current;
    if (!el) return;

    // Per rotate(90deg) CW: screen(sx,sy) → chart(sy, innerWidth-sx)
    const fire = (type, sx, sy, pid) => {
      const canvas = el.querySelector('canvas');
      if (!canvas) return;
      canvas.dispatchEvent(new PointerEvent(type, {
        bubbles: true, cancelable: true,
        clientX: sy,
        clientY: window.innerWidth - sx,
        pointerId: pid,
        pointerType: 'touch',
        isPrimary: pid === 1,
        pressure: type === 'pointerup' ? 0 : 0.5,
      }));
    };

    const onStart = e => { e.preventDefault(); Array.from(e.changedTouches).forEach((t,i) => fire('pointerdown', t.clientX, t.clientY, i+1)); };
    const onMove  = e => { e.preventDefault(); Array.from(e.changedTouches).forEach((t,i) => fire('pointermove',  t.clientX, t.clientY, i+1)); };
    const onEnd   = e => { e.preventDefault(); Array.from(e.changedTouches).forEach((t,i) => fire('pointerup',   t.clientX, t.clientY, i+1)); };

    el.addEventListener('touchstart', onStart, { passive: false });
    el.addEventListener('touchmove',  onMove,  { passive: false });
    el.addEventListener('touchend',   onEnd,   { passive: false });
    return () => {
      el.removeEventListener('touchstart', onStart);
      el.removeEventListener('touchmove',  onMove);
      el.removeEventListener('touchend',   onEnd);
    };
  }, [active]);

  return (
    <div ref={ref} style={{position:'absolute', inset:0}}>
      {children}
    </div>
  );
}

// Default info vuota — usata quando un tool non ha dati per il simbolo
const _EMPTY_T2 = { signal:"—", confidence:0, confidence_real:0, trend_1h:"—", expected_1h:0, expected_3h:0, expected_6h:0, expected_24h:0, expected_2w:0, timestamp:"", mode:"—" };
const _EMPTY_T3 = { signal:"—", score_total:0, method:"—", sample_size:0, h01:0, h03:0, h06:0, h24:0, h2w:0, timestamp:"" };
const _EMPTY_T4 = { signal:"—", news_impact:"—", sentiment:0, fc_1h:0, fc_3h:0, fc_6h:0, fc_24h:0, confidence:0, timestamp:"" };

// Earnings breakdown card (Integrazione 3) — pesca /api/earnings-breakdown
function EarningsCard({ sym }) {
  const [bd, setBd] = useState(null);
  useEffect(() => {
    let on = true;
    fetch("/api/earnings-breakdown")
      .then(r => r.json())
      .then(d => { if (on) setBd(d.breakdowns || {}); })
      .catch(() => {});
    return () => { on = false; };
  }, []);
  const e = bd && bd[sym];
  if (!e) return null;
  const hist = e.eps_history || [];
  if (!hist.length && e.next_earnings_days == null && e.pe_ttm == null) return null;
  const ned = e.next_earnings_days;
  const f = (v, suf = "") => (v == null ? "n/d" : `${Math.round(v * 10) / 10}${suf}`);
  return (
    <div className="fc-card earn-card">
      <div className="fc-head">
        <div className="fc-title">
          <span className="fc-dot" style={{ background: "var(--teal)" }}></span>
          <span className="fc-name">Earnings</span>
        </div>
        {ned != null && (
          <span className="signal HOLD" style={{ textTransform: "none" }}>
            tra {ned}g{e.beats_streak ? ` · ${e.beats_streak}/4 beat` : ""}
          </span>
        )}
      </div>
      <div className="fc-body">
        <div className="fc-meta" style={{ borderTop: "none", paddingTop: 0, marginTop: 0 }}>
          <span>P/E <strong>{f(e.pe_ttm)}</strong></span>
          <span>Crescita <strong>{f(e.rev_growth_yoy, "%")}</strong></span>
          <span>Margine <strong>{f(e.net_margin, "%")}</strong></span>
        </div>
        {hist.length > 0 && (
          <div className="earn-hist">
            {hist.slice(0, 4).map((h, i) => {
              const sp = h.surprise_pct;
              return (
                <div key={i} className="earn-row">
                  <span className="earn-date mono">{h.period}</span>
                  <span className="mono">{h.estimate != null ? h.estimate : "?"}→{h.actual != null ? h.actual : "?"}</span>
                  <span className={`mono ${sp >= 0 ? "earn-pos" : "earn-neg"}`}>
                    {sp != null ? `${sp >= 0 ? "+" : ""}${Math.round(sp)}%` : "n/d"}
                  </span>
                </div>
              );
            })}
          </div>
        )}
        <div className="fc-meta"><span style={{ color: "var(--text-faint)", fontSize: 11 }}>segmenti/opzioni: n/d (free)</span></div>
      </div>
    </div>
  );
}

function Dashboard({ refreshTick, initSym: initSymProp }) {
  const defaultSym = initSymProp || (window.WATCHLIST || [])[0]?.symbol || "AMZN";
  const [sym, setSym] = useState(defaultSym);
  const [interval, setInterval] = useState("5m");
  const data = (window.ALL_DATA || {})[sym];
  const meta = (window.WATCHLIST || []).find(w => w.symbol === sym) || { name: sym, price: 0, deltaPct: 0 };

  if (!data) {
    return (
      <div style={{display:"flex", alignItems:"center", justifyContent:"center", height:"100%", color:"var(--text-muted)", flexDirection:"column", gap:8}}>
        <Icon name="candles" size={32} strokeWidth={1.2}/>
        <span>Nessun dato disponibile per <strong>{sym}</strong>. Avvia il daemon e attendi il primo ciclo.</span>
      </div>
    );
  }

  // Merge con default vuoto per evitare crash se un tool non ha ancora dati
  const t2i = (data.tool2_info && data.tool2_info.signal) ? data.tool2_info : _EMPTY_T2;
  const t3i = (data.tool3_info && data.tool3_info.signal) ? data.tool3_info : _EMPTY_T3;
  const t4i = (data.tool4_info && data.tool4_info.signal) ? data.tool4_info : _EMPTY_T4;
  const show = (typeof window !== "undefined" && window.DASH_SHOW) || {};

  const [fullscreen, setFullscreen] = useState(false);
  const [landscape,  setLandscape]  = useState(false);

  return (
    <div className="dash" data-screen-label="01 Dashboard">

      {/* ── Fullscreen overlay — portrait o landscape in base allo stato ── */}
      {fullscreen && (
        <div className={landscape ? "chart-fs-landscape" : "chart-fs-overlay"}>
          <div className="chart-fs-header">
            <div className="chart-symbol" style={{gap:8}}>
              <span className="sym">{sym}</span>
              <span className="price mono">${meta.price.toFixed(2)}</span>
              <span className={`delta mono ${meta.deltaPct>=0 ? "delta-pos" : "delta-neg"}`}>
                {meta.deltaPct>=0 ? "+" : ""}{meta.deltaPct.toFixed(2)}%
              </span>
            </div>
            <div className="chart-legend" style={{marginLeft:"auto"}}>
              <span className="legend-item"><span className="legend-dash t2"></span>AI</span>
              <span className="legend-item"><span className="legend-dash t3"></span>Tecnico</span>
              <span className="legend-item"><span className="legend-dash t4"></span>News</span>
            </div>
            {/* Toggle portrait/landscape — solo mobile */}
            <button className="btn btn-sm dash-landscape-btn" onClick={() => setLandscape(l => !l)}
                    title={landscape ? "Vista verticale" : "Vista orizzontale"}>
              <Icon name={landscape ? "maximize" : "landscape"} size={13}/>
              {landscape ? "Verticale" : "Orizzontale"}
            </button>
            <button className="icon-btn" style={{marginLeft:4}} title="Chiudi"
                    onClick={() => { setFullscreen(false); setLandscape(false); }}>
              <Icon name="x" size={18}/>
            </button>
          </div>
          <div className="chart-fs-body">
            <LandscapeEventFix active={landscape}>
              <LWChart symbol={sym} interval={interval} refreshTick={refreshTick}/>
            </LandscapeEventFix>
          </div>
        </div>
      )}

      <section className="dash-main">
        <DashToolbar sym={sym} setSym={setSym} onFullscreen={() => setFullscreen(true)} interval={interval} onIntervalChange={setInterval}/>
        <div className="dash-chart-header">
          <div className="chart-symbol">
            <span className="sym">{sym}</span>
            <span className="price mono">${meta.price.toFixed(2)}</span>
            <span className={`delta mono ${meta.deltaPct>=0 ? "delta-pos" : "delta-neg"}`}>
              {meta.deltaPct>=0 ? "+" : ""}{meta.deltaPct.toFixed(2)}%
            </span>
          </div>
          <div className="chart-meta mono">{meta.name} · 5m · NYSE</div>
          <div className="chart-legend" style={{marginLeft:"auto"}}>
            <span className="legend-item"><span className="legend-dash t2"></span>AI</span>
            <span className="legend-item"><span className="legend-dash t3"></span>Tecnico</span>
            <span className="legend-item"><span className="legend-dash t4"></span>News</span>
          </div>
        </div>
        <div className="dash-chart">
          <LWChart symbol={sym} interval={interval} refreshTick={refreshTick}/>
        </div>
      </section>

      <aside className="dash-rail">
        {show.tool2 !== false && <ForecastCard tool="t2" name="AI · Tool 2"  info={t2i} keys={[
          { k: "expected_1h", l: "1h"   },
          { k: "expected_3h", l: "3h"   },
          { k: "expected_6h", l: "6h"   },
          { k: "expected_24h",l: "24h"  },
        ]} meta={[
          { l: "Trend 1h", v: t2i.trend_1h },
          { l: "Conf. reale", v: `${t2i.confidence_real}%` },
          { l: "Mode", v: t2i.mode },
        ]}/>}

        {show.tool3 !== false && <ForecastCard tool="t3" name="Tecnico · Tool 3" info={t3i} keys={[
          { k: "h01", l: "1h" },
          { k: "h03", l: "3h" },
          { k: "h06", l: "6h" },
          { k: "h24", l: "24h" },
        ]} confidenceKey="score_total" meta={[
          { l: "Score", v: `${t3i.score_total}/100` },
          { l: "Metodo", v: t3i.method },
          { l: "n campioni", v: t3i.sample_size },
        ]}/>}

        {show.tool4 !== false && <ForecastCard tool="t4" name="News · Tool 4" info={t4i} keys={[
          { k: "fc_1h",  l: "1h" },
          { k: "fc_3h",  l: "3h" },
          { k: "fc_6h",  l: "6h" },
          { k: "fc_24h", l: "24h" },
        ]} confidenceKey="confidence" meta={[
          { l: "Impact", v: t4i.news_impact },
          { l: "Sentiment", v: typeof t4i.sentiment === "number" ? t4i.sentiment.toFixed(2) : "—" },
        ]}/>}

        <ConvergenceCard t2={t2i} t3={t3i} t4={t4i}/>
        <EarningsCard sym={sym}/>
      </aside>
    </div>
  );
}

function DashToolbar({ sym, setSym, onFullscreen, interval, onIntervalChange }) {
  const wl = window.WATCHLIST || [];
  const [refreshing, setRefreshing] = useState(false);

  const handleRefresh = async () => {
    if (refreshing) return;
    setRefreshing(true);
    try {
      await (window.refreshDashboard?.() || Promise.resolve());
    } finally {
      setRefreshing(false);
    }
  };

  return (
    <div className="dash-toolbar">
      <div className="ticker-switcher" role="tablist">
        {wl.map(w => (
          <button key={w.symbol}
                  className={`ticker-tab ${sym===w.symbol ? "active":""}`}
                  onClick={()=>setSym(w.symbol)}>
            <span>{w.symbol}</span>
            <span className={`delta ${(w.deltaPct||0)>=0?"delta-pos":"delta-neg"}`}>
              {(w.deltaPct||0)>=0?"+":""}{(w.deltaPct||0).toFixed(2)}%
            </span>
          </button>
        ))}
      </div>
      <div className="dash-toolbar-actions">
        <div className="interval-toggle">
          {["5m","1h","1d"].map(iv => (
            <button key={iv}
              className={`btn${interval === iv ? " btn-primary" : ""}`}
              onClick={() => onIntervalChange(iv)}
              title={`Candele ${iv}`}
            >{iv}</button>
          ))}
        </div>
        <button className="btn btn-sm" onClick={handleRefresh} disabled={refreshing}
                title="Ricarica i dati dal DB">
          <Icon name="refresh" size={13} style={refreshing ? {animation:"spin 1s linear infinite"} : {}}/>
          {refreshing ? " …" : " Aggiorna"}
        </button>
        <button className="btn btn-sm" title="Grafico a schermo intero" onClick={onFullscreen}>
          <Icon name="maximize" size={13}/> Schermo intero
        </button>
      </div>
    </div>
  );
}

function ForecastCard({ tool, name, info, keys, meta, confidenceKey="confidence" }) {
  const conf = info[confidenceKey] || 0;
  return (
    <div className={`fc-card ${tool}`}>
      <div className="fc-head">
        <div className="fc-title">
          <span className="fc-dot"></span>
          <span className="fc-name">{name}</span>
        </div>
        <span style={{display:"flex",alignItems:"center",gap:6}}>
          {info.sample_size != null && info.sample_size < 50 && (
            <span title={`Bassa affidabilità statistica (campione ${info.sample_size} < 50)`}
              style={{fontSize:10,color:"var(--amber)",border:"1px solid var(--amber)",
                      borderRadius:4,padding:"1px 5px",whiteSpace:"nowrap"}}>bassa affid.</span>
          )}
          <span className={`signal ${info.signal}`}>{info.signal}</span>
        </span>
      </div>
      <div className="fc-body">
        <div className="fc-confidence">
          <span className="fc-conf-label">{confidenceKey === "score_total" ? "Score" : "Conf."}</span>
          <div className="fc-conf-bar"><div className="fc-conf-fill" style={{width:`${Math.min(100,conf)}%`}}></div></div>
          <span className="fc-conf-val mono">{conf}{confidenceKey === "score_total" ? "" : "%"}</span>
        </div>

        <div className="fc-horizons">
          {keys.map(({k, l}) => {
            const v = typeof info[k] === "number" ? info[k] : 0;
            return (
              <div className="fc-horizon" key={k}>
                <span className="fc-horizon-label">+{l}</span>
                <span className={`fc-horizon-val mono ${v>=0 ? "pos":"neg"}`}>
                  {v>=0?"+":""}{v.toFixed(2)}%
                </span>
              </div>
            );
          })}
        </div>

        {meta && (
          <div className="fc-meta">
            {meta.map(m => (
              <span key={m.l}>{m.l}: <strong>{m.v}</strong></span>
            ))}
          </div>
        )}
      </div>
    </div>
  );
}

function ConvergenceCard({ t2, t3, t4 }) {
  const signals = [t2.signal, t3.signal, t4.signal];
  const buy  = signals.filter(s=>s==="BUY").length;
  const sell = signals.filter(s=>s==="SELL").length;
  const hold = signals.filter(s=>s==="HOLD").length;
  const max  = Math.max(buy, sell, hold);
  const consensus = buy===max ? "BUY" : sell===max ? "SELL" : "HOLD";
  const agreement = Math.round((max/3)*100);

  // average %  for 24h
  const avg = (((t2.expected_24h || 0) + (t3.h24 || 0) + (t4.fc_24h || 0)) / 3);

  return (
    <div className="fc-card fc-convergence">
      <div className="fc-head">
        <div className="fc-title">
          <span className="fc-dot" style={{background:"var(--text-faint)"}}></span>
          <span className="fc-name">Convergenza</span>
        </div>
        <span className={`signal ${consensus}`}>{consensus} · {agreement}%</span>
      </div>
      <div className="fc-body">
        <div style={{display:"flex", gap:8, marginBottom:10}}>
          <span className="signal BUY"  style={{flex:1, justifyContent:"center"}}>{buy} BUY</span>
          <span className="signal HOLD" style={{flex:1, justifyContent:"center"}}>{hold} HOLD</span>
          <span className="signal SELL" style={{flex:1, justifyContent:"center"}}>{sell} SELL</span>
        </div>
        <div className="fc-meta" style={{borderTop:"none", paddingTop:0}}>
          <span>Media 24h: <strong style={{color: avg>=0?"var(--green)":"var(--red)"}}>{avg>=0?"+":""}{avg.toFixed(2)}%</strong></span>
        </div>
      </div>
    </div>
  );
}

// ── Lightweight Charts wrapper ──
function LWChart({ symbol, interval = "5m", refreshTick }) {
  const containerRef = useRef(null);
  const chartRef     = useRef(null);
  const seriesRef    = useRef({});
  const cacheRef     = useRef({});   // chiave: `${symbol}|${interval}`
  const [loading, setLoading] = useState(false);

  // Crea il grafico una volta sola al mount
  useEffect(() => {
    if (!containerRef.current || !window.LightweightCharts) return;
    const container = containerRef.current;
    let chart;
    try {
      chart = LightweightCharts.createChart(container, {
        width:  Math.max(100, container.clientWidth),
        height: Math.max(100, container.clientHeight),
        layout: {
          background: { color: 'transparent' },
          textColor: '#8892a4',
          fontFamily: 'JetBrains Mono, monospace',
        },
        grid: {
          vertLines: { color: 'rgba(255,255,255,0.022)' },
          horzLines: { color: 'rgba(255,255,255,0.05)' },
        },
        crosshair: {
          mode: LightweightCharts.CrosshairMode.Normal,
          vertLine: { color: 'rgba(150,164,196,0.35)', width: 1, style: LightweightCharts.LineStyle.Dashed, labelBackgroundColor: '#2b3442' },
          horzLine: { color: 'rgba(150,164,196,0.35)', width: 1, style: LightweightCharts.LineStyle.Dashed, labelBackgroundColor: '#2b3442' },
        },
        rightPriceScale: { borderColor: 'rgba(255,255,255,0.07)' },
        timeScale: { borderColor: 'rgba(255,255,255,0.07)', timeVisible: true, secondsVisible: false },
      });
    } catch(e) { console.warn('Dashboard chart init failed:', e); return; }

    chart.priceScale('right').applyOptions({ scaleMargins: { top: 0.06, bottom: 0.06 } });

    const candles = chart.addCandlestickSeries({
      upColor: '#22c55e', downColor: '#ef4444',
      borderUpColor: '#22c55e', borderDownColor: '#ef4444',
      wickUpColor:   '#22c55e', wickDownColor: '#ef4444',
      lastValueVisible: false, priceLineVisible: false,
    });
    const t2 = chart.addLineSeries({ color: '#6ea8fe', lineWidth: 2, lineStyle: LightweightCharts.LineStyle.Dotted,       priceLineVisible:false, lastValueVisible:false });
    const t3 = chart.addLineSeries({ color: '#f59e0b', lineWidth: 2, lineStyle: LightweightCharts.LineStyle.Dashed,        priceLineVisible:false, lastValueVisible:false });
    const t4 = chart.addLineSeries({ color: '#a78bfa', lineWidth: 2, lineStyle: LightweightCharts.LineStyle.SparseDotted,  priceLineVisible:false, lastValueVisible:false });

    chartRef.current  = chart;
    seriesRef.current = { candles, t2, t3, t4 };

    const ro = new ResizeObserver(() => {
      chart.applyOptions({ width: container.clientWidth, height: container.clientHeight });
    });
    ro.observe(container);

    return () => { ro.disconnect(); chart.remove(); chartRef.current = null; };
  }, []);

  // Aggiorna i dati quando cambiano symbol / interval / refreshTick
  useEffect(() => {
    if (!chartRef.current) return;

    const _apply = (candles) => {
      if (!candles || !candles.length) return;
      chartRef.current.priceScale('right').applyOptions({ autoScale: true });
      seriesRef.current.candles.setData(candles);

      const showForecast = interval === "5m";
      const d = (window.ALL_DATA || {})[symbol] || {};

      if (showForecast) {
        const milestonePct = (anchor, val) => {
          if (!anchor) return '';
          const pct = (val - anchor) / anchor * 100;
          return (pct >= 0 ? '+' : '') + pct.toFixed(1) + '%';
        };
        // Prezzo della candela più vicina a un dato istante (entro 30 min).
        const nearestClose = (t) => {
          let best = null, bd = Infinity;
          for (const c of candles) { const dd = Math.abs(c.time - t); if (dd < bd) { bd = dd; best = c; } }
          return (best && bd <= 1800) ? best.close : null;
        };
        // Ancora il forecast all'ORA in cui il tool ha girato (dai punti del backend,
        // pts[0].time) — NON all'ultima candela — col prezzo della candela a quell'ora.
        // Così la previsione appare quando è stata calcolata (es. 21:31), non alle 01:55.
        const buildLineAt = (pts, info, keys) => {
          if (!Array.isArray(pts) || pts.length < 2) return [];   // tool nascosto/assente → niente linea
          const baseT = pts[0].time;
          const baseP = nearestClose(baseT) || pts[0].value;
          const deltas = [3600, 3*3600, 6*3600, 24*3600];
          const out = [{ time: baseT, value: baseP }];
          deltas.forEach((delta, i) => {
            const pct = info[keys[i]] || 0;
            out.push({ time: baseT + delta, value: +(baseP * (1 + pct/100)).toFixed(4) });
          });
          return out;
        };
        // Etichetta % SOLO sul punto finale (24h) per non accavallare i marker.
        const _isMobile = (typeof window !== 'undefined') && window.innerWidth < 760;
        const addMarkers = (series, pts, color, position) => {
          if (!pts.length) { series.setMarkers([]); return; }
          const fpts = pts.slice(1);
          // Pallini piccoli e discreti per i passi intermedi; il punto finale (24h)
          // resta leggermente più visibile perché porta l'etichetta %.
          series.setMarkers(fpts.map((pt, i) => {
            const isLast = i === fpts.length - 1;
            return {
              time: pt.time, position, color, shape: 'circle',
              text: isLast ? milestonePct(pts[0].value, pt.value) : '',
              size: _isMobile ? (isLast ? 0.45 : 0.3) : (isLast ? 0.6 : 0.4),
            };
          }));
        };

        const t2pts = buildLineAt(d.tool2, d.tool2_info || {}, ["expected_1h","expected_3h","expected_6h","expected_24h"]);
        const t3pts = buildLineAt(d.tool3, d.tool3_info || {}, ["h01","h03","h06","h24"]);
        const t4pts = buildLineAt(d.tool4, d.tool4_info || {}, ["fc_1h","fc_3h","fc_6h","fc_24h"]);

        seriesRef.current.t2.setData(t2pts);
        seriesRef.current.t3.setData(t3pts);
        seriesRef.current.t4.setData(t4pts);
        addMarkers(seriesRef.current.t2, t2pts, '#6ea8fe', 'inBar');
        addMarkers(seriesRef.current.t3, t3pts, '#f59e0b', 'aboveBar');
        addMarkers(seriesRef.current.t4, t4pts, '#a78bfa', 'belowBar');

        // Range visibile: dall'ancora del forecast (ora del run) a +25h, con un po' di
        // contesto prima. Fallback all'ultimo blocco contiguo di candele se non c'è forecast.
        const fAnchor = t3pts[0] || t2pts[0] || t4pts[0] || null;
        if (fAnchor) {
          chartRef.current.timeScale().setVisibleRange({
            from: fAnchor.time - 2 * 3600,
            to:   fAnchor.time + 25 * 3600,
          });
        } else {
          let fromIdx = candles.length - 1;
          const _GAP = 40 * 60, _MAXBACK = 24;
          while (fromIdx > 0
                 && (candles.length - fromIdx) < _MAXBACK
                 && (candles[fromIdx].time - candles[fromIdx - 1].time) <= _GAP) {
            fromIdx--;
          }
          chartRef.current.timeScale().setVisibleRange({
            from: candles[fromIdx].time,
            to:   candles[candles.length-1].time,
          });
        }
      } else {
        // Nascondi forecast lines per 1h/1d
        seriesRef.current.t2.setData([]);
        seriesRef.current.t3.setData([]);
        seriesRef.current.t4.setData([]);
        seriesRef.current.t2.setMarkers([]);
        seriesRef.current.t3.setMarkers([]);
        seriesRef.current.t4.setMarkers([]);

        // Range visibile: 1h → ~2gg (48 candele), 1d → ~3 mesi (90 candele)
        const tail = interval === "1h" ? 48 : 90;
        const fromIdx = Math.max(0, candles.length - tail);
        chartRef.current.timeScale().setVisibleRange({
          from: candles[fromIdx].time,
          to:   candles[candles.length-1].time,
        });
      }
    };

    const cacheKey = `${symbol}|${interval}`;

    if (interval === "5m") {
      // 5m: usa direttamente window.ALL_DATA (già in memoria)
      const d = (window.ALL_DATA || {})[symbol];
      _apply(d?.candles || []);
    } else if (cacheRef.current[cacheKey]) {
      // Hit cache
      _apply(cacheRef.current[cacheKey]);
    } else {
      // Fetch 1h/1d dall'API
      setLoading(true);
      fetch(`/api/candles/${encodeURIComponent(symbol)}?interval=${interval}`)
        .then(r => r.json())
        .then(data => {
          const candles = data.candles || [];
          cacheRef.current[cacheKey] = candles;
          _apply(candles);
        })
        .catch(e => console.warn(`LWChart fetch ${symbol} ${interval}:`, e))
        .finally(() => setLoading(false));
    }
  }, [symbol, interval, refreshTick]);

  return (
    <div ref={containerRef} style={{position:"absolute", inset:0}}>
      {loading && (
        <div style={{
          position:"absolute", top:8, left:"50%", transform:"translateX(-50%)",
          background:"var(--bg-elevated)", border:"1px solid var(--border)",
          borderRadius:"var(--radius-sm)", padding:"4px 10px",
          fontSize:11.5, color:"var(--text-muted)", zIndex:10,
          fontFamily:"var(--mono)",
        }}>
          Caricamento {interval}…
        </div>
      )}
    </div>
  );
}

window.Dashboard = Dashboard;
