// Costi — costi delle chiamate API a pagamento (Anthropic + Perplexity).
// Legge /api/costs (aggregati per provider/mese/tool/modello + ultime chiamate).
// Importi in USD dal backend; mostriamo anche € (× eur_per_usd).

const _PROVIDER_COLOR = { anthropic: "#d39a6a", perplexity: "#6ea8fe" };
const _PROVIDER_LABEL = { anthropic: "Anthropic (Claude)", perplexity: "Perplexity" };

function _costUsd(v) {
  const n = Number(v) || 0;
  return "$" + (Math.abs(n) < 1 ? n.toFixed(4) : n.toFixed(2));
}
function _costEur(v, rate) {
  const n = (Number(v) || 0) * (Number(rate) || 0.92);
  return "€" + (Math.abs(n) < 1 ? n.toFixed(4) : n.toFixed(2));
}
function _costTs(iso) {
  if (!iso) return "—";
  const m = String(iso).match(/(\d{4})-(\d{2})-(\d{2})T(\d{2}):(\d{2})/);
  if (!m) return String(iso);
  const [, , mo, d, hh, mm] = m;
  return `${d}/${mo} ${hh}:${mm}`;
}

// Barre orizzontali (per provider / per tool)
function CostHBars({ rows, rate, colorFor }) {
  const max = Math.max(...rows.map(r => r.usd || 0), 0.000001);
  return (
    <div style={{ display: "flex", flexDirection: "column", gap: 8 }}>
      {rows.map((r, i) => {
        const w = Math.max(2, Math.round((r.usd || 0) / max * 100));
        const col = colorFor ? colorFor(r) : "#6ea8fe";
        return (
          <div key={i} style={{ display: "flex", alignItems: "center", gap: 10 }}>
            <div style={{ width: 120, fontSize: 12, color: "var(--text-muted)", overflow: "hidden", textOverflow: "ellipsis", whiteSpace: "nowrap" }}>{r.label}</div>
            <div style={{ flex: 1, background: "var(--surface2)", borderRadius: 5, height: 20, position: "relative", minWidth: 0 }}>
              <div style={{ width: w + "%", background: col, height: "100%", borderRadius: 5, transition: "width 200ms" }} />
            </div>
            <div className="mono" style={{ width: 92, textAlign: "right", fontSize: 12, fontWeight: 600 }}>{_costUsd(r.usd)}</div>
            <div className="mono" style={{ width: 78, textAlign: "right", fontSize: 11, color: "var(--text-faint)" }}>{_costEur(r.usd, rate)}</div>
            <div className="mono" style={{ width: 54, textAlign: "right", fontSize: 11, color: "var(--text-faint)" }}>{r.calls} ch.</div>
          </div>
        );
      })}
    </div>
  );
}

// Barre verticali per mese (stack anthropic + perplexity)
function CostMonthChart({ months, rate }) {
  const data = [...months].reverse();   // backend DESC → cronologico
  if (!data.length) return <div style={{ color: "var(--text-faint)", fontSize: 12, fontStyle: "italic" }}>Ancora nessun dato mensile.</div>;
  const max = Math.max(...data.map(m => m.usd || 0), 0.000001);
  const H = 160, barW = Math.max(18, Math.min(48, Math.floor(560 / data.length) - 8));
  return (
    <div style={{ display: "flex", alignItems: "flex-end", gap: 8, height: H + 40, overflowX: "auto", paddingTop: 6 }}>
      {data.map((m, i) => {
        const a = m.anthropic_usd || 0, p = m.perplexity_usd || 0;
        const hA = Math.round(a / max * H), hP = Math.round(p / max * H);
        return (
          <div key={i} style={{ display: "flex", flexDirection: "column", alignItems: "center", gap: 4, flex: "0 0 auto" }}>
            <div className="mono" style={{ fontSize: 10.5, color: "var(--text)", fontWeight: 600 }}>{_costUsd(m.usd)}</div>
            <div style={{ width: barW, height: H, display: "flex", flexDirection: "column", justifyContent: "flex-end" }}
                 title={`Anthropic ${_costUsd(a)} · Perplexity ${_costUsd(p)}`}>
              <div style={{ height: hP, background: _PROVIDER_COLOR.perplexity, borderRadius: "4px 4px 0 0" }} />
              <div style={{ height: hA, background: _PROVIDER_COLOR.anthropic }} />
            </div>
            <div style={{ fontSize: 11, color: "var(--text-muted)" }}>{m.month?.slice(5)}/{m.month?.slice(2, 4)}</div>
          </div>
        );
      })}
    </div>
  );
}

function _CostCard({ title, totals, rate, nPayers }) {
  const usd = totals?.usd || 0;
  return (
    <div className="card" style={{ flex: "1 1 200px", minWidth: 170 }}>
      <div style={{ fontSize: 11, textTransform: "uppercase", color: "var(--text-muted)", marginBottom: 4 }}>{title}</div>
      <div className="mono" style={{ fontSize: 22, fontWeight: 700 }}>{_costUsd(usd)}</div>
      <div style={{ fontSize: 12, color: "var(--text-muted)" }}>{_costEur(usd, rate)} · {totals?.calls || 0} chiamate</div>
      {nPayers > 0 && (
        <div style={{ fontSize: 11.5, color: "var(--text-faint)", marginTop: 3 }}>
          {_costUsd(usd / nPayers)} / pagante <span style={{ opacity: 0.7 }}>({nPayers})</span>
        </div>
      )}
    </div>
  );
}

// ── Analisi & proiezioni (capacity planning) ────────────────────────────────
const _SCALE_LABEL = {
  "ticker+interval": { t: "↑ticker · ↑frequenza", c: "#d39a6a" },
  "ticker":          { t: "↑ticker", c: "#e0b341" },
  "fixed":           { t: "fisso", c: "#7a8aa0" },
};

function CostProjection({ p, rate }) {
  // Hooks SEMPRE chiamati per primi (Rules of Hooks): il guard viene dopo.
  const tools = (p && p.by_tool) || [];
  const wl = Math.max(1, (p && p.watchlist_size) || 1);
  const curInt = (p && p.intraday_interval_min) || 30;
  const mkt = (p && p.market_minutes) || 780;
  const tdpm = (p && p.trading_days_per_month) || 21;
  const [nTick, setNTick] = useState(wl);
  const [interval, setIv] = useState(curInt);
  if (!p || !tools.length) return null;

  // Modello lineare di primo ordine: ogni tool scala con ticker e/o cadenza.
  const estDaily = (nt, iv) => tools.reduce((s, t) => {
    let v = t.daily_avg || 0;
    const sc = t.scaling || "fixed";
    if (sc.includes("ticker")) v *= nt / wl;
    if (sc.includes("interval")) v *= curInt / Math.max(1, iv);
    return s + v;
  }, 0);

  const baseDaily = estDaily(wl, curInt);
  const projDaily = estDaily(nTick, interval);
  const projMonthly = projDaily * tdpm;
  const deltaDaily = projDaily - baseDaily;

  // costo per ticker/giorno = solo tool che scalano con la watchlist
  const tickerDaily = tools.filter(t => (t.scaling || "").includes("ticker")).reduce((s, t) => s + (t.daily_avg || 0), 0);
  const perTicker = tickerDaily / wl;
  const cycles = iv => Math.max(1, Math.round(mkt / Math.max(1, iv)));

  const deltaCol = deltaDaily > 0.0005 ? "var(--red)" : deltaDaily < -0.0005 ? "var(--green)" : "var(--text-muted)";
  const sign = v => (v >= 0 ? "+" : "−");
  const fmtD = v => sign(v) + _costUsd(Math.abs(v));

  const statBox = (title, big, sub) => (
    <div className="card" style={{ flex: "1 1 170px", minWidth: 150 }}>
      <div style={{ fontSize: 10.5, textTransform: "uppercase", color: "var(--text-muted)", marginBottom: 3 }}>{title}</div>
      <div className="mono" style={{ fontSize: 19, fontWeight: 700 }}>{big}</div>
      <div style={{ fontSize: 11, color: "var(--text-faint)", marginTop: 2 }}>{sub}</div>
    </div>
  );
  const sliderStyle = { width: "100%", accentColor: "var(--accent)" };

  return (
    <div className="card" style={{ marginBottom: 12 }}>
      <div style={{ fontSize: 11, textTransform: "uppercase", letterSpacing: 0.5, color: "var(--text-muted)", marginBottom: 4 }}>Analisi &amp; proiezioni</div>
      <div style={{ fontSize: 11.5, color: "var(--text-faint)", marginBottom: 12, maxWidth: 640 }}>
        Stime di <b>primo ordine</b> dalle medie reali ({p.days_window || 0}g di dati). I costi sono guidati dagli eventi news (le chiamate Claude sono filtrate "a evento"), quindi variano molto giorno&nbsp;per&nbsp;giorno — guarda il range.
      </div>

      <div style={{ display: "flex", flexWrap: "wrap", gap: 10, marginBottom: 14 }}>
        {statBox("Spesa media / giorno", _costUsd(p.daily_avg), `range ${_costUsd(p.daily_min)}–${_costUsd(p.daily_max)}`)}
        {statBox("Stima / mese", _costUsd((p.daily_avg || 0) * tdpm), `${_costEur((p.daily_avg || 0) * tdpm, rate)} · ≈${tdpm}g mercato`)}
        {statBox("Ticker watchlist", String(wl), `${_costUsd(perTicker)}/ticker/giorno`)}
        {statBox("Cadenza Tool4", `ogni ${curInt}′`, `~${cycles(curInt)} cicli/giorno`)}
      </div>

      {/* Dettaglio per tool */}
      <div style={{ overflowX: "auto", marginBottom: 14 }}>
        <table style={{ width: "100%", borderCollapse: "collapse", fontSize: 12 }}>
          <thead>
            <tr style={{ color: "var(--text-muted)", textAlign: "left" }}>
              <th style={{ padding: "4px 8px" }}>Tool</th>
              <th style={{ padding: "4px 8px" }}>Scala con</th>
              <th style={{ padding: "4px 8px", textAlign: "right" }}>$/giorno</th>
              <th style={{ padding: "4px 8px", textAlign: "right" }}>$/chiamata</th>
              <th style={{ padding: "4px 8px", textAlign: "right" }}>chiamate/g</th>
              <th style={{ padding: "4px 8px", textAlign: "right" }}>ticker</th>
            </tr>
          </thead>
          <tbody>
            {tools.map((t, i) => {
              const sl = _SCALE_LABEL[t.scaling] || _SCALE_LABEL.fixed;
              return (
                <tr key={i} style={{ borderTop: "1px solid var(--border)" }}>
                  <td style={{ padding: "4px 8px", fontWeight: 600 }}>{(t.tool || "?").toUpperCase()}</td>
                  <td style={{ padding: "4px 8px" }}><span style={{ fontSize: 11, color: sl.c }}>{sl.t}</span></td>
                  <td className="mono" style={{ padding: "4px 8px", textAlign: "right", fontWeight: 600 }}>{_costUsd(t.daily_avg)}</td>
                  <td className="mono" style={{ padding: "4px 8px", textAlign: "right", color: "var(--text-faint)" }}>{_costUsd(t.per_call)}</td>
                  <td className="mono" style={{ padding: "4px 8px", textAlign: "right", color: "var(--text-faint)" }}>{t.calls_per_day}</td>
                  <td className="mono" style={{ padding: "4px 8px", textAlign: "right", color: "var(--text-faint)" }}>{t.syms}</td>
                </tr>
              );
            })}
          </tbody>
        </table>
      </div>

      {/* What-if */}
      <div style={{ background: "var(--surface2)", borderRadius: 8, padding: 14 }}>
        <div style={{ fontSize: 12, fontWeight: 600, marginBottom: 12 }}>Simulatore "e se…"</div>
        <div style={{ display: "flex", flexWrap: "wrap", gap: 20 }}>
          <div style={{ flex: "1 1 240px" }}>
            <div style={{ display: "flex", justifyContent: "space-between", fontSize: 12, marginBottom: 4 }}>
              <span style={{ color: "var(--text-muted)" }}>Ticker in watchlist</span>
              <span className="mono" style={{ fontWeight: 700 }}>{nTick}{nTick !== wl ? <span style={{ color: "var(--text-faint)", fontWeight: 400 }}> (ora {wl})</span> : ""}</span>
            </div>
            <input type="range" min={1} max={Math.max(wl + 30, wl * 4)} step={1} value={nTick} onChange={e => setNTick(parseInt(e.target.value))} style={sliderStyle} />
          </div>
          <div style={{ flex: "1 1 240px" }}>
            <div style={{ display: "flex", justifyContent: "space-between", fontSize: 12, marginBottom: 4 }}>
              <span style={{ color: "var(--text-muted)" }}>Run Tool3/4 ogni</span>
              <span className="mono" style={{ fontWeight: 700 }}>{interval}′ <span style={{ color: "var(--text-faint)", fontWeight: 400 }}>· ~{cycles(interval)} cicli/g{interval !== curInt ? ` (ora ${curInt}′)` : ""}</span></span>
            </div>
            <input type="range" min={5} max={60} step={5} value={interval} onChange={e => setIv(parseInt(e.target.value))} style={sliderStyle} />
          </div>
        </div>
        <div style={{ display: "flex", flexWrap: "wrap", gap: 10, marginTop: 14, alignItems: "stretch" }}>
          {statBox("Stima / giorno", _costUsd(projDaily), _costEur(projDaily, rate))}
          {statBox("Stima / mese", _costUsd(projMonthly), `${_costEur(projMonthly, rate)} · ≈${tdpm}g`)}
          <div className="card" style={{ flex: "1 1 170px", minWidth: 150 }}>
            <div style={{ fontSize: 10.5, textTransform: "uppercase", color: "var(--text-muted)", marginBottom: 3 }}>Δ vs adesso</div>
            <div className="mono" style={{ fontSize: 19, fontWeight: 700, color: deltaCol }}>{fmtD(deltaDaily)}<span style={{ fontSize: 12, fontWeight: 400 }}>/g</span></div>
            <div style={{ fontSize: 11, color: deltaCol, marginTop: 2 }}>{fmtD(deltaDaily * tdpm)}/mese</div>
          </div>
        </div>
        <div style={{ display: "flex", flexWrap: "wrap", gap: 14, marginTop: 12, fontSize: 11.5, color: "var(--text-muted)" }}>
          <span>+1 ticker ≈ <b className="mono" style={{ color: "var(--text)" }}>{fmtD(estDaily(wl + 1, curInt) - baseDaily)}/g</b> ({fmtD((estDaily(wl + 1, curInt) - baseDaily) * tdpm)}/mese)</span>
          <span>· da {curInt}′ → 25′ ≈ <b className="mono" style={{ color: "var(--text)" }}>{fmtD(estDaily(wl, 25) - baseDaily)}/g</b></span>
        </div>
      </div>
    </div>
  );
}

// Campo numerico stabile (definito a livello di modulo per non perdere il focus a ogni keystroke)
function _NumField({ label, value, onChange, step }) {
  return (
    <label style={{ display: "flex", flexDirection: "column", gap: 3, fontSize: 11.5, color: "var(--text-muted)" }}>
      {label}
      <input type="number" step={step || "0.01"} className="mono" value={value ?? ""}
        onChange={e => onChange(e.target.value)}
        style={{ width: 94, padding: "5px 7px", background: "var(--surface2)", border: "1px solid var(--border)", borderRadius: 6, color: "var(--text)" }} />
    </label>
  );
}

function CreditCard({ c, rate }) {
  const has = c && c.amount != null;
  const rem = has ? (c.remaining || 0) : null;
  const frac = has && c.amount > 0 ? Math.max(0, rem / c.amount) : 0;
  const col = !has ? "var(--text-faint)" : frac > 0.25 ? "var(--green)" : frac > 0.1 ? "var(--amber)" : "var(--red)";
  return (
    <div className="card" style={{ flex: "1 1 240px", minWidth: 210 }}>
      <div style={{ fontSize: 11, textTransform: "uppercase", color: "var(--text-muted)", marginBottom: 4 }}>
        Credito {_PROVIDER_LABEL[c.provider] || c.provider}
      </div>
      {!has ? (
        <div style={{ fontSize: 12.5, color: "var(--text-faint)" }}>Non impostato — vedi Impostazioni ⚙</div>
      ) : (
        <>
          <div className="mono" style={{ fontSize: 22, fontWeight: 700, color: col }}>{_costUsd(rem)}</div>
          <div style={{ fontSize: 11.5, color: "var(--text-muted)" }}>
            su {_costUsd(c.amount)} · speso {_costUsd(c.spent_since)}{c.set_at ? ` dal ${_costTs(c.set_at)}` : ""}
          </div>
          {c.n_recharges > 0 && (
            <div style={{ fontSize: 10.5, color: "var(--text-faint)", marginTop: 2 }}>
              incl. {c.n_recharges} {c.n_recharges === 1 ? "ricarica" : "ricariche"} (+{_costUsd(c.topups)})
            </div>
          )}
          <div style={{ height: 6, background: "var(--surface2)", borderRadius: 3, marginTop: 6, overflow: "hidden" }}>
            <div style={{ width: Math.round(frac * 100) + "%", height: "100%", background: col, transition: "width 200ms" }} />
          </div>
        </>
      )}
    </div>
  );
}

// Ledger ricariche credito: aggiungi top-up storicizzati + elenco con eliminazione.
function RechargePanel({ data, onChanged }) {
  const [provider, setProvider] = useState("anthropic");
  const [amount, setAmount] = useState("");
  const [date, setDate] = useState("");
  const [note, setNote] = useState("");
  const [busy, setBusy] = useState(false);
  const [msg, setMsg] = useState(null);

  const recharges = [];
  (data?.credits || []).forEach(c => (c.recharges || []).forEach(r => recharges.push(r)));
  recharges.sort((a, b) => String(b.timestamp).localeCompare(String(a.timestamp)));

  const inputStyle = { padding: "5px 7px", background: "var(--surface2)", border: "1px solid var(--border)", borderRadius: 6, color: "var(--text)", fontSize: 12.5 };

  const add = async () => {
    const amt = parseFloat(amount);
    if (!(amt > 0)) { setMsg("Importo non valido"); setTimeout(() => setMsg(null), 3000); return; }
    setBusy(true); setMsg(null);
    try {
      const r = await fetch("/api/costs/recharge", {
        method: "POST", headers: { "Content-Type": "application/json" },
        body: JSON.stringify({ provider, amount: amt, date: date || undefined, note: note || undefined }),
      }).then(r => r.json());
      if (r.ok) { setAmount(""); setNote(""); setDate(""); setMsg("ok"); onChanged && onChanged(); }
      else setMsg(r.error || "errore");
    } catch (e) { setMsg(String(e)); }
    finally { setBusy(false); setTimeout(() => setMsg(null), 3000); }
  };

  const del = async (id) => {
    try {
      const r = await fetch("/api/costs/recharge/delete", {
        method: "POST", headers: { "Content-Type": "application/json" },
        body: JSON.stringify({ id }),
      }).then(r => r.json());
      if (r.ok) onChanged && onChanged();
    } catch (e) { /* ignore */ }
  };

  return (
    <div className="card" style={{ marginBottom: 12 }}>
      <div style={{ fontSize: 11, textTransform: "uppercase", letterSpacing: 0.5, color: "var(--text-muted)", marginBottom: 3 }}>Ricariche credito</div>
      <div style={{ fontSize: 10.5, color: "var(--text-faint)", marginBottom: 10, maxWidth: 480 }}>
        Registra ogni acquisto di credito: si somma al saldo di riferimento e aumenta il credito disponibile mostrato sopra.
      </div>
      <div style={{ display: "flex", gap: 8, flexWrap: "wrap", alignItems: "flex-end", marginBottom: 10 }}>
        <label style={{ display: "flex", flexDirection: "column", gap: 3, fontSize: 11.5, color: "var(--text-muted)" }}>
          Provider
          <select value={provider} onChange={e => setProvider(e.target.value)} style={{ ...inputStyle, width: 150 }}>
            <option value="anthropic">Anthropic (Claude)</option>
            <option value="perplexity">Perplexity</option>
          </select>
        </label>
        <label style={{ display: "flex", flexDirection: "column", gap: 3, fontSize: 11.5, color: "var(--text-muted)" }}>
          Importo $
          <input type="number" step="0.5" className="mono" value={amount} onChange={e => setAmount(e.target.value)} style={{ ...inputStyle, width: 100 }} />
        </label>
        <label style={{ display: "flex", flexDirection: "column", gap: 3, fontSize: 11.5, color: "var(--text-muted)" }}>
          Data (opz.)
          <input type="date" value={date} onChange={e => setDate(e.target.value)} style={{ ...inputStyle, width: 150 }} />
        </label>
        <label style={{ display: "flex", flexDirection: "column", gap: 3, fontSize: 11.5, color: "var(--text-muted)", flex: "1 1 150px" }}>
          Nota (opz.)
          <input type="text" value={note} onChange={e => setNote(e.target.value)} placeholder="es. ricarica mensile" style={{ ...inputStyle, width: "100%" }} />
        </label>
        <button className="btn btn-sm btn-primary" disabled={busy} onClick={add}>{busy ? "…" : "Aggiungi"}</button>
        {msg === "ok" && <span style={{ fontSize: 12, color: "var(--green)" }}>✓</span>}
        {msg && msg !== "ok" && <span style={{ fontSize: 12, color: "var(--red)" }}>{msg}</span>}
      </div>
      {recharges.length === 0 ? (
        <div style={{ fontSize: 11.5, color: "var(--text-faint)", fontStyle: "italic" }}>Nessuna ricarica registrata.</div>
      ) : (
        <div style={{ display: "flex", flexDirection: "column" }}>
          {recharges.map(r => (
            <div key={r.id} style={{ display: "flex", alignItems: "center", gap: 10, fontSize: 12.5, padding: "5px 0", borderTop: "1px solid var(--border)" }}>
              <span className="mono" style={{ width: 92, color: "var(--text-muted)" }}>{_costTs(r.timestamp)}</span>
              <span style={{ width: 96, color: _PROVIDER_COLOR[r.provider] || "var(--text)" }}>{r.provider}</span>
              <span className="mono" style={{ width: 84, fontWeight: 600, color: "var(--green)" }}>+{_costUsd(r.amount_usd)}</span>
              <span style={{ flex: 1, color: "var(--text-faint)", overflow: "hidden", textOverflow: "ellipsis", whiteSpace: "nowrap" }}>{r.note || ""}</span>
              <button className="btn btn-sm" onClick={() => del(r.id)} title="Elimina ricarica" style={{ padding: "2px 9px", color: "var(--red)" }}>×</button>
            </div>
          ))}
        </div>
      )}
    </div>
  );
}

function CostSettings({ data, onSaved }) {
  const [form, setForm] = useState(null);
  const [saving, setSaving] = useState(false);
  const [msg, setMsg] = useState(null);
  const [recomp, setRecomp] = useState(null);
  const [recomping, setRecomping] = useState(false);
  // Inizializza il form SOLO al mount (il pannello è montato all'apertura): così i
  // refresh dati ogni 60s non sovrascrivono le modifiche in corso dell'utente.
  useEffect(() => {
    if (!data) return;
    // c.anchor = saldo manuale grezzo (NON c.amount, che è il pool ancora+ricariche)
    const cr = {}; (data.credits || []).forEach(c => { cr[c.provider] = c.anchor; });
    setForm({
      eur_per_usd: data.eur_per_usd ?? 0.92,
      haiku: { ...(data.pricing?.haiku || {}) },
      sonnet: { ...(data.pricing?.sonnet || {}) },
      sonar: { ...(data.pricing?.sonar || {}) },
      credit_anthropic: cr.anthropic ?? "",
      credit_perplexity: cr.perplexity ?? "",
    });
  }, []);
  if (!form) return null;
  const setP = (grp, key, v) => setForm(f => ({ ...f, [grp]: { ...f[grp], [key]: v } }));
  const save = async () => {
    setSaving(true); setMsg(null);
    const body = {
      eur_per_usd: parseFloat(form.eur_per_usd) || 0,
      pricing: {
        haiku: ["in", "out", "cache_write", "cache_read"].reduce((o, k) => { o[k] = parseFloat(form.haiku[k]) || 0; return o; }, {}),
        sonnet: ["in", "out", "cache_write", "cache_read"].reduce((o, k) => { o[k] = parseFloat(form.sonnet[k]) || 0; return o; }, {}),
        sonar: ["in", "out", "request_fee"].reduce((o, k) => { o[k] = parseFloat(form.sonar[k]) || 0; return o; }, {}),
      },
      credits: {},
    };
    if (form.credit_anthropic !== "" && form.credit_anthropic != null) body.credits.anthropic = parseFloat(form.credit_anthropic);
    if (form.credit_perplexity !== "" && form.credit_perplexity != null) body.credits.perplexity = parseFloat(form.credit_perplexity);
    try {
      const r = await fetch("/api/costs/settings", { method: "POST", headers: { "Content-Type": "application/json" }, body: JSON.stringify(body) }).then(r => r.json());
      if (r.ok) { setMsg("ok"); onSaved && onSaved(); } else setMsg(r.error || "errore");
    } catch (e) { setMsg(String(e)); }
    finally { setSaving(false); setTimeout(() => setMsg(null), 3000); }
  };
  const recompute = async () => {
    setRecomping(true); setRecomp(null);
    try {
      const r = await fetch("/api/costs/recompute", { method: "POST" }).then(r => r.json());
      if (r.ok) { setRecomp(`✓ ${r.rows} righe · $${(r.before || 0).toFixed(2)} → $${(r.after || 0).toFixed(2)}`); onSaved && onSaved(); }
      else setRecomp(r.error || "errore");
    } catch (e) { setRecomp(String(e)); }
    finally { setRecomping(false); setTimeout(() => setRecomp(null), 7000); }
  };
  return (
    <div className="card" style={{ marginBottom: 12 }}>
      <div style={{ fontSize: 11, textTransform: "uppercase", letterSpacing: 0.5, color: "var(--text-muted)", marginBottom: 12 }}>Impostazioni costi</div>
      <div style={{ display: "flex", flexWrap: "wrap", gap: 22 }}>
        <div>
          <div style={{ fontSize: 12, fontWeight: 600, marginBottom: 6 }}>Credito disponibile (USD)</div>
          <div style={{ display: "flex", gap: 10 }}>
            <_NumField label="Anthropic" step="0.5" value={form.credit_anthropic} onChange={v => setForm(f => ({ ...f, credit_anthropic: v }))} />
            <_NumField label="Perplexity" step="0.5" value={form.credit_perplexity} onChange={v => setForm(f => ({ ...f, credit_perplexity: v }))} />
          </div>
          <div style={{ fontSize: 10.5, color: "var(--text-faint)", marginTop: 5, maxWidth: 210 }}>
            Saldo di riferimento: da quel momento viene scalato a ogni chiamata. Le <b>ricariche</b> (sezione in fondo alla pagina) si sommano sopra a questo.
          </div>
        </div>
        <div>
          <div style={{ fontSize: 12, fontWeight: 600, marginBottom: 6 }}>Claude Haiku ($/1M token)</div>
          <div style={{ display: "flex", gap: 10, flexWrap: "wrap" }}>
            <_NumField label="input" value={form.haiku.in} onChange={v => setP("haiku", "in", v)} />
            <_NumField label="output" value={form.haiku.out} onChange={v => setP("haiku", "out", v)} />
            <_NumField label="cache write" value={form.haiku.cache_write} onChange={v => setP("haiku", "cache_write", v)} />
            <_NumField label="cache read" value={form.haiku.cache_read} onChange={v => setP("haiku", "cache_read", v)} />
          </div>
        </div>
        <div>
          <div style={{ fontSize: 12, fontWeight: 600, marginBottom: 6 }}>Claude Sonnet ($/1M token) <span style={{ fontWeight: 400, color: "var(--text-faint)" }}>· Portfolio Manager</span></div>
          <div style={{ display: "flex", gap: 10, flexWrap: "wrap" }}>
            <_NumField label="input" value={form.sonnet.in} onChange={v => setP("sonnet", "in", v)} />
            <_NumField label="output" value={form.sonnet.out} onChange={v => setP("sonnet", "out", v)} />
            <_NumField label="cache write" value={form.sonnet.cache_write} onChange={v => setP("sonnet", "cache_write", v)} />
            <_NumField label="cache read" value={form.sonnet.cache_read} onChange={v => setP("sonnet", "cache_read", v)} />
          </div>
        </div>
        <div>
          <div style={{ fontSize: 12, fontWeight: 600, marginBottom: 6 }}>Perplexity Sonar</div>
          <div style={{ display: "flex", gap: 10, flexWrap: "wrap" }}>
            <_NumField label="input /1M" value={form.sonar.in} onChange={v => setP("sonar", "in", v)} />
            <_NumField label="output /1M" value={form.sonar.out} onChange={v => setP("sonar", "out", v)} />
            <_NumField label="fee/richiesta" step="0.001" value={form.sonar.request_fee} onChange={v => setP("sonar", "request_fee", v)} />
          </div>
        </div>
        <div>
          <div style={{ fontSize: 12, fontWeight: 600, marginBottom: 6 }}>Cambio</div>
          <_NumField label="€ per 1 $" value={form.eur_per_usd} onChange={v => setForm(f => ({ ...f, eur_per_usd: v }))} />
        </div>
      </div>
      <div style={{ display: "flex", alignItems: "center", gap: 10, marginTop: 14, flexWrap: "wrap" }}>
        <button className="btn btn-sm btn-primary" disabled={saving} onClick={save}>{saving ? "Salvo…" : "Salva impostazioni"}</button>
        {msg === "ok" && <span style={{ fontSize: 12, color: "var(--green)" }}>✓ salvato</span>}
        {msg && msg !== "ok" && <span style={{ fontSize: 12, color: "var(--red)" }}>{msg}</span>}
        <button className="btn btn-sm" disabled={recomping} onClick={recompute} style={{ marginLeft: "auto" }}
                title="Ricalcola cost_usd di tutte le righe coi prezzi correnti (es. dopo aver aggiunto il prezzo di Sonnet).">
          {recomping ? "Ricalcolo…" : "↻ Ricalcola costi storici"}
        </button>
        {recomp && <span style={{ fontSize: 12, color: recomp.startsWith("✓") ? "var(--green)" : "var(--red)" }}>{recomp}</span>}
      </div>
    </div>
  );
}

function CostsView() {
  const [data, setData] = useState(null);
  const [loading, setLoading] = useState(true);
  const [error, setError] = useState(null);
  const [showSettings, setShowSettings] = useState(false);

  const load = async () => {
    try {
      const d = await fetch("/api/costs").then(r => r.json());
      setData(d); setError(d?.error || null);
    } catch (e) { setError(String(e)); }
    finally { setLoading(false); }
  };
  useEffect(() => {
    load();
    const t = setInterval(load, 60 * 1000);
    return () => clearInterval(t);
  }, []);

  const rate = data?.eur_per_usd || 0.92;
  const totals = data?.totals || {};
  const nPayers = data?.n_payers || 0;
  const credits = data?.credits || [];
  const provRows = (data?.by_provider || []).map(r => ({ label: _PROVIDER_LABEL[r.provider] || r.provider, usd: r.usd, calls: r.calls, provider: r.provider }));
  const toolRows = (data?.by_tool || []).map(r => ({ label: (r.tool || "?").toUpperCase(), usd: r.usd, calls: r.calls }));
  const recent = data?.recent || [];
  const hasData = (totals?.all?.calls || 0) > 0;

  return (
    <div style={{ padding: 16, overflowY: "auto", height: "100%" }}>
      <div style={{ display: "flex", alignItems: "center", gap: 10, marginBottom: 4, flexWrap: "wrap" }}>
        <h3 style={{ margin: 0, fontSize: 15 }}>Costi API</h3>
        <span style={{ fontSize: 11, color: "var(--text-muted)" }}>tasso €/$ {rate}</span>
        <div style={{ marginLeft: "auto", display: "flex", gap: 8 }}>
          <button className="btn btn-sm" onClick={() => setShowSettings(s => !s)}
                  style={showSettings ? { color: "var(--accent)" } : {}}>
            <Icon name="settings" size={13} /> Impostazioni
          </button>
          <button className="btn btn-sm" disabled={loading} onClick={load}>
            <Icon name="refresh" size={13} style={loading ? { animation: "spin 1s linear infinite" } : {}} /> Aggiorna
          </button>
        </div>
      </div>
      <div style={{ color: "var(--text-muted)", fontSize: 12.5, marginBottom: 14 }}>
        Costo delle chiamate a pagamento del daemon (Claude di Tool4/Tool9 + Perplexity). Calcolato dai token di ogni risposta × prezzo del modello. Il conteggio parte da quando è stato attivato il tracking.
      </div>

      {loading && !data && <div style={{ color: "var(--text-muted)" }}>Caricamento…</div>}
      {error && <div style={{ color: "var(--red)", marginBottom: 12 }}>Errore: {error}</div>}

      {data && showSettings && <CostSettings data={data} onSaved={load} />}

      {data && !hasData && (
        <div className="card" style={{ color: "var(--text-muted)" }}>
          Nessuna chiamata registrata ancora. La tabella si popola appena Tool4 o Tool9 fanno una chiamata
          ad Anthropic o Perplexity (in orario di mercato, se abilitati). Intanto puoi impostare crediti e prezzi da <b>Impostazioni ⚙</b>.
        </div>
      )}

      {data && hasData && <>
        {/* Card riepilogo */}
        <div style={{ display: "flex", flexWrap: "wrap", gap: 12, marginBottom: 12 }}>
          <_CostCard title="Questo mese" totals={totals.month} rate={rate} nPayers={nPayers} />
          <_CostCard title="Ultimi 30 giorni" totals={totals.last30} rate={rate} nPayers={nPayers} />
          <_CostCard title="Totale" totals={totals.all} rate={rate} nPayers={nPayers} />
        </div>

        {/* Credito residuo per provider */}
        {credits.length > 0 && (
          <div style={{ display: "flex", flexWrap: "wrap", gap: 12, marginBottom: 16 }}>
            {credits.map(c => <CreditCard key={c.provider} c={c} rate={rate} />)}
          </div>
        )}

        {/* Analisi & proiezioni (capacity planning) */}
        <CostProjection p={data.projection} rate={rate} />

        {/* Costo per API */}
        <div className="card" style={{ marginBottom: 12 }}>
          <div style={{ fontSize: 11, textTransform: "uppercase", letterSpacing: 0.5, color: "var(--text-muted)", marginBottom: 10 }}>Costo per API</div>
          <CostHBars rows={provRows} rate={rate} colorFor={r => _PROVIDER_COLOR[r.provider] || "#6ea8fe"} />
        </div>

        {/* Costo per mese */}
        <div className="card" style={{ marginBottom: 12 }}>
          <div style={{ display: "flex", alignItems: "center", gap: 12, marginBottom: 10 }}>
            <div style={{ fontSize: 11, textTransform: "uppercase", letterSpacing: 0.5, color: "var(--text-muted)" }}>Costo per mese</div>
            <span style={{ fontSize: 11, color: _PROVIDER_COLOR.anthropic }}>■ Anthropic</span>
            <span style={{ fontSize: 11, color: _PROVIDER_COLOR.perplexity }}>■ Perplexity</span>
          </div>
          <CostMonthChart months={data.by_month || []} rate={rate} />
        </div>

        {/* Costo per tool */}
        <div className="card" style={{ marginBottom: 12 }}>
          <div style={{ fontSize: 11, textTransform: "uppercase", letterSpacing: 0.5, color: "var(--text-muted)", marginBottom: 10 }}>Costo per tool</div>
          <CostHBars rows={toolRows} rate={rate} colorFor={() => "#5fd0ac"} />
        </div>

        {/* Ultime chiamate */}
        <div className="card">
          <div style={{ fontSize: 11, textTransform: "uppercase", letterSpacing: 0.5, color: "var(--text-muted)", marginBottom: 10 }}>Ultime chiamate</div>
          <div style={{ overflowX: "auto" }}>
            <table style={{ width: "100%", borderCollapse: "collapse", fontSize: 12 }}>
              <thead>
                <tr style={{ color: "var(--text-muted)", textAlign: "left" }}>
                  <th style={{ padding: "4px 8px" }}>Ora</th>
                  <th style={{ padding: "4px 8px" }}>API</th>
                  <th style={{ padding: "4px 8px" }}>Modello</th>
                  <th style={{ padding: "4px 8px" }}>Tool</th>
                  <th style={{ padding: "4px 8px" }}>Op.</th>
                  <th style={{ padding: "4px 8px" }}>Ticker</th>
                  <th style={{ padding: "4px 8px", textAlign: "right" }}>Token in/out</th>
                  <th style={{ padding: "4px 8px", textAlign: "right" }}>Costo</th>
                </tr>
              </thead>
              <tbody>
                {recent.map((r, i) => (
                  <tr key={i} style={{ borderTop: "1px solid var(--border)", opacity: r.status === "error" ? 0.55 : 1 }}>
                    <td className="mono" style={{ padding: "4px 8px", color: "var(--text-muted)" }}>{_costTs(r.timestamp)}</td>
                    <td style={{ padding: "4px 8px", color: _PROVIDER_COLOR[r.provider] || "var(--text)" }}>{r.provider}</td>
                    <td className="mono" style={{ padding: "4px 8px", color: "var(--text-faint)", fontSize: 11 }}>{(r.model || "—").replace("claude-", "")}</td>
                    <td style={{ padding: "4px 8px" }}>{(r.tool || "—").toUpperCase()}</td>
                    <td style={{ padding: "4px 8px", color: "var(--text-muted)" }}>{r.operation || "—"}</td>
                    <td className="mono" style={{ padding: "4px 8px" }}>{r.symbol || "—"}</td>
                    <td className="mono" style={{ padding: "4px 8px", textAlign: "right", color: "var(--text-faint)" }}>{(r.input_tokens || 0)}/{(r.output_tokens || 0)}</td>
                    <td className="mono" style={{ padding: "4px 8px", textAlign: "right", fontWeight: 600 }}>{r.status === "error" ? "—" : _costUsd(r.cost_usd)}</td>
                  </tr>
                ))}
              </tbody>
            </table>
          </div>
        </div>
      </>}

      {/* Ricariche credito — sempre visibile, sotto le ultime chiamate */}
      {data && <RechargePanel data={data} onChanged={load} />}
    </div>
  );
}

window.CostsView = CostsView;
