/* =========================================================
   ANTARES — Schermate 1-4
   Cruscotto · Fatture · Collaboratori · Cespiti
   ========================================================= */

const { useState, useMemo } = React;
const { fmt, fmtNum, fmtPct, MESI, MESI_FULL,
  PROGETTI, FATTURE, COLLABORATORI, CESPITI,
  POSIZIONE_IVA, SCADENZE_FISCALI, SCADENZE_INCASSI } = window.AntaresData;

/* ---------- Small icons ---------- */
const Icon = ({ name, size = 16 }) => {
  const map = {
    plus: "M12 5v14M5 12h14",
    arrow: "M5 12h14M13 5l7 7-7 7",
    check: "M5 12l5 5L20 7",
    alert: "M12 9v4M12 17h.01M10.29 3.86L1.82 18a2 2 0 001.71 3h16.94a2 2 0 001.71-3L13.71 3.86a2 2 0 00-3.42 0z",
    download: "M21 15v4a2 2 0 01-2 2H5a2 2 0 01-2-2v-4M7 10l5 5 5-5M12 15V3",
    filter: "M22 3H2l8 9.46V19l4 2v-8.54L22 3z",
    search: "M21 21l-4.35-4.35M11 19a8 8 0 100-16 8 8 0 000 16z",
    cal: "M19 4H5a2 2 0 00-2 2v14a2 2 0 002 2h14a2 2 0 002-2V6a2 2 0 00-2-2zM16 2v4M8 2v4M3 10h18",
    chev: "M9 18l6-6-6-6",
    menu: "M3 12h18M3 6h18M3 18h18",
    x: "M18 6L6 18M6 6l12 12",
    home: "M3 12L12 3l9 9M5 10v10a1 1 0 001 1h3v-6h6v6h3a1 1 0 001-1V10",
    doc: "M14 2H6a2 2 0 00-2 2v16a2 2 0 002 2h12a2 2 0 002-2V8zM14 2v6h6M16 13H8M16 17H8M10 9H8",
    users: "M17 21v-2a4 4 0 00-4-4H5a4 4 0 00-4 4v2M9 11a4 4 0 100-8 4 4 0 000 8zM23 21v-2a4 4 0 00-3-3.87M16 3.13a4 4 0 010 7.75",
    box: "M21 16V8a2 2 0 00-1-1.73l-7-4a2 2 0 00-2 0l-7 4A2 2 0 003 8v8a2 2 0 001 1.73l7 4a2 2 0 002 0l7-4A2 2 0 0021 16zM3.27 6.96L12 12.01l8.73-5.05M12 22.08V12",
    chart: "M18 20V10M12 20V4M6 20v-6",
    cash: "M12 1v22M17 5H9.5a3.5 3.5 0 000 7h5a3.5 3.5 0 010 7H6",
    clock: "M12 22c5.523 0 10-4.477 10-10S17.523 2 12 2 2 6.477 2 12s4.477 10 10 10zM12 6v6l4 2",
    file: "M14 2H6a2 2 0 00-2 2v16a2 2 0 002 2h12a2 2 0 002-2V8zM14 2v6h6",
    edit: "M11 4H4a2 2 0 00-2 2v14a2 2 0 002 2h14a2 2 0 002-2v-7M18.5 2.5a2.121 2.121 0 013 3L12 15l-4 1 1-4 9.5-9.5z",
    pdf: "M14 2H6a2 2 0 00-2 2v16a2 2 0 002 2h12a2 2 0 002-2V8zM14 2v6h6M9 13h6M9 17h6M9 9h1",
    copy: "M9 9h11a2 2 0 012 2v9a2 2 0 01-2 2h-9a2 2 0 01-2-2v-9a2 2 0 012-2zM5 15H4a2 2 0 01-2-2V4a2 2 0 012-2h9a2 2 0 012 2v1",
  };
  return (
    <svg width={size} height={size} viewBox="0 0 24 24" fill="none"
         stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round">
      <path d={map[name]} />
    </svg>
  );
};

// Opzioni <select> dei progetti raggruppate per anno (più facili da trovare).
function progettoOptionsByYear(progetti) {
  const byYear = new Map();
  (progetti || []).forEach(p => {
    const y = p.anno || "—";
    if (!byYear.has(y)) byYear.set(y, []);
    byYear.get(y).push(p);
  });
  const years = [...byYear.keys()].sort((a, b) => (a === "—" ? 1 : b === "—" ? -1 : b - a));
  return years.map(y => (
    <optgroup key={y} label={y === "—" ? "Senza anno" : String(y)}>
      {byYear.get(y).sort((a, b) => String(a.nome).localeCompare(String(b.nome))).map(p => (
        <option key={p.id} value={p.id}>{p.nome}{p.cliente ? " · " + p.cliente : ""}</option>
      ))}
    </optgroup>
  ));
}

/* ============================================================
   1. CRUSCOTTO
   ============================================================ */
function Cruscotto({ onNavigate }) {
  // KPI calcolati live dalle fatture
  const year = new Date().getFullYear();
  const inYear = (f) => {
    const parts = (f.data || "").split("/");
    return parts.length === 3 && parseInt(parts[2], 10) === year;
  };
  const monthOf = (f) => parseInt((f.data || "").split("/")[1], 10);
  const trimOf = (m) => Math.ceil(m / 3);
  const ivaOf  = (f) => f.iva > 0 ? f.imponibile * f.iva / 100 : 0;

  const fattAttYear  = FATTURE.filter(f => f.tipo === "attiva"  && inYear(f));
  const fattPasYear  = FATTURE.filter(f => f.tipo === "passiva" && inYear(f));

  const ricavi      = fattAttYear.reduce((s,f) => s + f.imponibile, 0);
  const costiFatt   = fattPasYear.reduce((s,f) => s + f.imponibile, 0);
  const costiCollab = (COLLABORATORI || [])
    .filter(c => c.anno == null || Number(c.anno) === year)
    .reduce((s,c) => s + (c.costoReale || 0), 0);
  const costi       = costiFatt + costiCollab;
  const risultato   = ricavi - costi;
  const ivaStimata  = Math.max(0, fattAttYear.reduce((s,f)=>s+ivaOf(f),0) - fattPasYear.reduce((s,f)=>s+ivaOf(f),0));
  const daIncassare = fattAttYear.filter(f => f.stato !== "incassata")
    .reduce((s,f) => s + f.imponibile * (1 + (f.iva > 0 ? f.iva/100 : 0)), 0);

  // YoY ricavi vs anno precedente (live)
  const yearOf = (f) => parseInt((f.data || "").split("/")[2], 10);
  const ricaviPrev = FATTURE.filter(f => f.tipo === "attiva" && yearOf(f) === year - 1)
    .reduce((s,f) => s + f.imponibile, 0);
  const yoyRicavi = ricaviPrev > 0 ? ((ricavi - ricaviPrev) / ricaviPrev) * 100 : null;

  // Fatture aperte / sollecitate (live)
  const fattAperte = fattAttYear.filter(f => f.stato !== "incassata");
  const nAperte = fattAperte.length;
  const nSollecit = fattAperte.filter(f => f.stato === "sollecitata").length;

  // Posizione IVA per trimestre (live)
  const ivaTrim = [1,2,3,4].map(t => {
    const vendite  = fattAttYear.filter(f => trimOf(monthOf(f)) === t).reduce((s,f)=>s+ivaOf(f),0);
    const acquisti = fattPasYear.filter(f => trimOf(monthOf(f)) === t).reduce((s,f)=>s+ivaOf(f),0);
    return { periodo: `${t}° trimestre ${year}`, ivaVendite: vendite, ivaAcquisti: acquisti, saldo: vendite - acquisti };
  });
  const ivaTotV = ivaTrim.reduce((s,p)=>s+p.ivaVendite,0);
  const ivaTotA = ivaTrim.reduce((s,p)=>s+p.ivaAcquisti,0);
  const ivaTotS = ivaTotV - ivaTotA;

  // Ricavi per linea (live)
  const lineeMap = new Map();
  fattAttYear.forEach(f => {
    const l = f.linea || "Altro";
    lineeMap.set(l, (lineeMap.get(l) || 0) + f.imponibile);
  });
  const lineeArr = [...lineeMap.entries()].map(([linea, ricaviL]) => ({
    linea, ricavi: ricaviL,
    pct: ricavi > 0 ? (ricaviL / ricavi) * 100 : 0,
  })).sort((a,b) => b.ricavi - a.ricavi);

  return (
    <div className="stack">
      <div className="page-head">
        <div className="page-title-block">
          <span className="eyebrow">Esercizio 2026 · aggiornato oggi</span>
          <h1 className="h1">Cruscotto</h1>
        </div>
        <div className="page-actions">
          <button className="btn ghost"><Icon name="download" /> Esporta</button>
          <button className="btn primary" onClick={() => onNavigate("fatture")}>
            <Icon name="plus" /> Nuova fattura
          </button>
        </div>
      </div>

      {(() => {
        const urgFis = SCADENZE_FISCALI.filter(s => s.urgent);
        const urgInc = SCADENZE_INCASSI.filter(s => s.urgent);
        const tot = urgFis.length + urgInc.length;
        if (tot === 0) return null;
        const labels = [...urgFis, ...urgInc]
          .slice(0, 3)
          .map(s => `${s.tipo || s.cliente} (${s.data} · ${fmt(s.importo)})`)
          .join(" · ");
        return (
          <div className="alert coral">
            <div className="alert-icon">!</div>
            <div>
              <strong>{tot} scaden{tot === 1 ? "za" : "ze"} nei prossimi 15 giorni.</strong>
              <div className="muted" style={{ fontSize: 12, marginTop: 2 }}>{labels}</div>
            </div>
            <div className="alert-action">
              <button className="btn" onClick={() => onNavigate("scadenze")}>
                Vai a Scadenze <Icon name="arrow" />
              </button>
            </div>
          </div>
        );
      })()}

      <div className="kpi-grid">
        <div className="kpi">
          <div className="kpi-label">Ricavi anno</div>
          <div className="kpi-value">{fmt(ricavi)}</div>
          <div className="kpi-sub">
            {yoyRicavi == null
              ? <span className="muted">nessun dato {year - 1}</span>
              : <><span className={(yoyRicavi >= 0 ? "pos" : "neg") + " delta"}>{yoyRicavi >= 0 ? "▲" : "▼"} {fmtPct(Math.abs(yoyRicavi), 1)}</span> vs. {year - 1}</>}
          </div>
        </div>
        <div className="kpi blue">
          <div className="kpi-label">Risultato gestionale</div>
          <div className="kpi-value">{fmt(risultato)}</div>
          <div className="kpi-sub">
            Margine <span className="pos delta">{ricavi > 0 ? fmtPct((risultato/ricavi)*100, 1) : "—"}</span> · EBITDA stimato
          </div>
        </div>
        <div className="kpi yellow">
          <div className="kpi-label">Saldo IVA stimato</div>
          <div className="kpi-value">{fmt(ivaStimata)}</div>
          <div className="kpi-sub">
            <span className="warn delta">a debito</span> · da versare entro 16/08
          </div>
        </div>
        <div className="kpi coral">
          <div className="kpi-label">Da incassare</div>
          <div className="kpi-value">{fmt(daIncassare)}</div>
          <div className="kpi-sub">{nAperte} fattur{nAperte === 1 ? "a aperta" : "e aperte"} · {nSollecit} sollecitat{nSollecit === 1 ? "a" : "e"}</div>
        </div>
      </div>

      <div className="two-col-asym">
        <div className="card">
          <div className="card-bar" />
          <div className="card-head">
            <div>
              <h3 className="h3">Posizione IVA</h3>
              <div className="muted" style={{ fontSize: 12 }}>Liquidazioni trimestrali 2026</div>
            </div>
            <span className="pill teal"><span className="dot" /> aggiornato</span>
          </div>
          <div className="table-wrap">
            <table className="table">
              <thead>
                <tr>
                  <th>Periodo</th>
                  <th className="num">IVA vendite</th>
                  <th className="num">IVA acquisti</th>
                  <th className="num">Saldo</th>
                  <th>Stato</th>
                </tr>
              </thead>
              <tbody>
                {ivaTrim.map((p, i) => (
                  <tr key={i}>
                    <td>{p.periodo}</td>
                    <td className="num">{p.ivaVendite ? fmt(p.ivaVendite) : "—"}</td>
                    <td className="num">{p.ivaAcquisti ? fmt(p.ivaAcquisti) : "—"}</td>
                    <td className="num"><strong>{p.saldo ? fmt(p.saldo) : "—"}</strong></td>
                    <td>
                      {p.saldo > 0 ? <span className="pill yellow">a debito</span>
                        : p.saldo < 0 ? <span className="pill teal">a credito</span>
                        : <span className="dim">—</span>}
                    </td>
                  </tr>
                ))}
                <tr className="row-total">
                  <td>Totale anno</td>
                  <td className="num">{fmt(ivaTotV)}</td>
                  <td className="num">{fmt(ivaTotA)}</td>
                  <td className="num">{fmt(ivaTotS)}</td>
                  <td></td>
                </tr>
              </tbody>
            </table>
          </div>
        </div>

        <div className="card">
          <div className="card-bar blue" />
          <div className="card-head">
            <h3 className="h3">Ricavi per linea</h3>
            <span className="muted" style={{ fontSize: 12 }}>YTD 2026</span>
          </div>
          <div className="card-body" style={{ display: "flex", flexDirection: "column", gap: 16 }}>
            {lineeArr.length === 0 && (
              <div className="muted" style={{ fontSize: 13 }}>Nessun ricavo registrato per quest'anno.</div>
            )}
            {lineeArr.map((l, i) => (
              <div key={l.linea}>
                <div style={{ display: "flex", justifyContent: "space-between", marginBottom: 6 }}>
                  <strong style={{ fontFamily: "var(--serif)", fontSize: 15 }}>{l.linea}</strong>
                  <span className="mono">{fmt(l.ricavi)}</span>
                </div>
                <div className="minibar"><div className={"minibar-fill" + (i % 2 ? " blue" : "")} style={{ width: l.pct.toFixed(0) + "%" }} /></div>
                <div className="muted" style={{ fontSize: 11, marginTop: 4 }}>{l.pct.toFixed(0)}%</div>
              </div>
            ))}
          </div>
        </div>
      </div>

      <div className="two-col">
        <div className="card">
          <div className="card-bar yellow" />
          <div className="card-head">
            <h3 className="h3">Cassa attuale</h3>
            <button className="btn ghost" onClick={() => onNavigate("tesoreria")}>
              Apri tesoreria <Icon name="arrow" />
            </button>
          </div>
          <div className="card-body">
            {(() => {
              const TES = window.AntaresData.TESORERIA;
              const meseCorr = new Date().getMonth(); // 0..11
              // ricalcolo saldi progressivi per Cruscotto
              let s = TES.saldoIniziale || 0;
              const saldiFine = (TES.mesi || []).map(m => {
                const tE = m.entrate.incassiClienti + m.entrate.apportiSoci + m.entrate.finanziamenti + m.entrate.altre;
                const tU = m.uscite.stipendi + m.uscite.fornitori + m.uscite.f24 + m.uscite.rateFin + (m.uscite.rateFiscali||0) + m.uscite.altreSpese;
                s += (tE - tU);
                return s;
              });
              const saldoOggi  = saldiFine[Math.min(meseCorr, 11)] ?? (TES.saldoIniziale || 0);
              const saldo30gg  = saldiFine[Math.min(meseCorr + 1, 11)] ?? saldoOggi;
              const minSaldo   = saldiFine.length ? Math.min(...saldiFine) : 0;
              const minIdx     = saldiFine.indexOf(minSaldo);
              const minNome    = window.AntaresData.MESI_FULL?.[minIdx] || "—";
              return (
                <>
                  <div style={{ display: "grid", gridTemplateColumns: "1fr 1fr", gap: 14 }}>
                    <div>
                      <div className="kpi-label">Saldo a fine mese corrente</div>
                      <div style={{ fontFamily: "var(--serif)", fontSize: 26, fontWeight: 600, marginTop: 4 }}>{fmt(saldoOggi)}</div>
                      <div className="muted" style={{ fontSize: 12 }}>fine {(window.AntaresData.MESI_FULL?.[meseCorr] || "").toLowerCase()}</div>
                    </div>
                    <div>
                      <div className="kpi-label">Previsione mese successivo</div>
                      <div style={{ fontFamily: "var(--serif)", fontSize: 26, fontWeight: 600, marginTop: 4 }} className={saldo30gg >= 0 ? "pos" : "neg"}>{fmt(saldo30gg)}</div>
                      <div className="muted" style={{ fontSize: 12 }}>dopo entrate/uscite previste</div>
                    </div>
                  </div>
                  <div className="divider" />
                  <div className="row" style={{ justifyContent: "space-between" }}>
                    <div className="muted" style={{ fontSize: 12 }}>
                      Mese più critico: <strong className={minSaldo < 10000 ? "warn" : ""}>{minNome}</strong> · saldo previsto {fmt(minSaldo)}
                    </div>
                  </div>
                </>
              );
            })()}
          </div>
        </div>

        <div className="card">
          <div className="card-bar coral" />
          <div className="card-head">
            <h3 className="h3">Prossime uscite F24</h3>
            <button className="btn ghost" onClick={() => onNavigate("scadenze")}>Tutte <Icon name="arrow" /></button>
          </div>
          <div>
            {(() => {
              const prossime = SCADENZE_FISCALI
                .filter(s => s.stato !== "pagata" && (s.giorniAllaScadenza ?? 0) >= 0)
                .sort((a, b) => (a.giorniAllaScadenza ?? 0) - (b.giorniAllaScadenza ?? 0))
                .slice(0, 4);
              if (prossime.length === 0) {
                return <div style={{ padding: 24, textAlign: "center", color: "var(--muted)", fontSize: 13 }}>
                  Nessuna scadenza fiscale in vista. Aggiungile dalla pagina Scadenze.
                </div>;
              }
              return prossime.map(s => (
                <div className="sched-item" key={s.id}>
                  <div className={`sched-date ${s.urgent ? "urgent" : ""}`}>
                    <div className="d">{s.giorno}</div>
                    <div className="m">{s.mese}</div>
                  </div>
                  <div>
                    <div className="sched-title">{s.tipo}</div>
                    <div className="sched-meta">{s.data} · {s.stato}</div>
                  </div>
                  <div className="sched-amount">{fmt(s.importo)}</div>
                </div>
              ));
            })()}
          </div>
        </div>
      </div>
    </div>
  );
}

/* ============================================================
   2. FATTURE
   ============================================================ */
function Fatture() {
  // form
  const [tipo, setTipo]             = useState("attiva");
  const [data, setData]             = useState(todayIt());
  const [controparte, setControparte] = useState("");
  const [imponibile, setImponibile] = useState("");
  const [iva, setIva]               = useState(22);
  const [linea, setLinea]           = useState("Service");
  const [categoria, setCategoria]   = useState("");
  const [fissoVar, setFissoVar]     = useState("variabile");
  const [progettoId, setProgettoId] = useState("");
  const [stato, setStato]           = useState("emessa");
  const [numDoc, setNumDoc]         = useState(nextFatturaId("attiva"));
  const [editingId, setEditingId]   = useState(null);
  const [busy, setBusy]             = useState(false);
  const [showImport, setShowImport] = useState(false);

  // lista
  const [filter, setFilter] = useState("tutte");
  const [search, setSearch] = useState("");
  const [toast, setToast]   = useState(null);
  const [filtroAnno, setFiltroAnno] = useState(String(new Date().getFullYear()));
  const [filtroMese, setFiltroMese] = useState("tutti");
  const [selected, setSelected] = useState({}); // mappa id -> true, solo righe selezionate
  const [bulkBusy, setBulkBusy] = useState(false);

  // cambiando filtro/ricerca la selezione si riferisce a righe non più visibili: azzerala
  React.useEffect(() => { setSelected({}); }, [filter, search]);

  const totale = useMemo(() => {
    const v = parseFloat(imponibile) || 0;
    return iva > 0 ? v + v * (iva / 100) : v;
  }, [imponibile, iva]);

  // tipo cambia (solo su fattura NUOVA, i bottoni Attiva/Passiva sono disabilitati
  // in modifica) → resetta default stato e suggerisci id. In modifica NON deve mai
  // toccare lo stato: altrimenti aprire una fattura già "pagata" la faceva tornare
  // "da pagare" solo perché editingId passa da null a valorizzato.
  React.useEffect(() => {
    if (!editingId) {
      setStato(tipo === "attiva" ? "emessa" : "da pagare");
      setNumDoc(nextFatturaId(tipo));
    }
  }, [tipo, editingId]);

  const resetForm = () => {
    setEditingId(null);
    setData(todayIt()); setControparte(""); setImponibile(""); setIva(22);
    setLinea("Service"); setCategoria(""); setFissoVar("variabile");
    setProgettoId(""); setStato(tipo === "attiva" ? "emessa" : "da pagare");
    setNumDoc(nextFatturaId(tipo));
  };

  const startEdit = (f) => {
    const r = f._raw || {};
    setEditingId(r.id);
    setTipo(r.tipo);
    setData(f.data || todayIt());
    setControparte(r.controparte || "");
    setImponibile(String(r.imponibile || ""));
    setIva(r.iva_aliquota === "rc" ? -1 : parseInt(r.iva_aliquota, 10));
    setLinea(r.linea || "Service");
    setCategoria(r.categoria_ce || "");
    setFissoVar(r.fv === "F" ? "fisso" : "variabile");
    setProgettoId(r.progetto_id || "");
    setStato(r.stato || (r.tipo === "attiva" ? "emessa" : "da pagare"));
    setNumDoc(r.id);
    window.scrollTo({ top: 0, behavior: "smooth" });
  };

  const submit = async (e) => {
    e.preventDefault();
    if (!controparte.trim() || !imponibile) {
      setToast({ kind: "err", msg: "Controparte e imponibile obbligatori" });
      setTimeout(() => setToast(null), 2400);
      return;
    }
    setBusy(true);
    try {
      const payload = window.AntaresStore.fatturaToDB({
        id: numDoc.trim() || nextFatturaId(tipo),
        tipo, data, controparte: controparte.trim(),
        imponibile: parseFloat(String(imponibile).replace(",", ".")),
        iva,
        linea, categoria, fv: fissoVar === "fisso" ? "F" : "V",
        progetto_id: progettoId || null, stato,
      });
      const res = editingId
        ? await window.AntaresAPI.fatture.update(editingId, payload)
        : await window.AntaresAPI.fatture.insert(payload);
      if (res.error) {
        setToast({ kind: "err", msg: "Errore: " + res.error.message });
        setTimeout(() => setToast(null), 4000);
        return;
      }
      await window.AntaresStore.refresh("fatture");
      setToast({ kind: "ok", msg: editingId ? "Fattura aggiornata" : "Fattura registrata" });
      setTimeout(() => setToast(null), 2400);
      resetForm();
    } catch (ex) {
      setToast({ kind: "err", msg: "Errore: " + (ex.message || ex) });
      setTimeout(() => setToast(null), 4000);
    } finally {
      setBusy(false);
    }
  };

  const remove = async (id) => {
    if (!confirm(`Eliminare la fattura ${id}?`)) return;
    try {
      const res = await window.AntaresAPI.fatture.remove(id);
      if (res.error) { setToast({ kind: "err", msg: res.error.message }); setTimeout(() => setToast(null), 3000); return; }
      await window.AntaresStore.refresh("fatture");
      setToast({ kind: "ok", msg: "Fattura eliminata" });
      setTimeout(() => setToast(null), 2000);
      if (editingId === id) resetForm();
    } catch (ex) {
      setToast({ kind: "err", msg: "Errore: " + (ex.message || ex) });
      setTimeout(() => setToast(null), 3000);
    }
  };

  // Azione massiva: segna pagate/non pagate tutte le fatture selezionate in un colpo solo.
  // Attive e passive hanno vocabolari di stato diversi -> al massimo 2 chiamate batch, mai una per riga.
  const markSelected = async (pagato) => {
    const rowsSel = filtered.filter(f => selected[f.id]);
    if (!rowsSel.length) return;
    const attiveIds  = rowsSel.filter(f => f.tipo === "attiva").map(f => f.id);
    const passiveIds = rowsSel.filter(f => f.tipo === "passiva").map(f => f.id);
    setBulkBusy(true);
    try {
      const oggiIso = pagato ? new Date().toISOString().slice(0, 10) : null;
      const jobs = [];
      if (attiveIds.length)  jobs.push(window.AntaresAPI.fatture.updateMany(attiveIds,  { stato: pagato ? "incassata" : "emessa",    data_pagamento: oggiIso }));
      if (passiveIds.length) jobs.push(window.AntaresAPI.fatture.updateMany(passiveIds, { stato: pagato ? "pagata"    : "da pagare", data_pagamento: oggiIso }));
      const results = await Promise.all(jobs);
      const errRes = results.find(r => r && r.error);
      if (errRes) {
        setToast({ kind: "err", msg: "Errore: " + errRes.error.message });
        setTimeout(() => setToast(null), 4000);
        return;
      }
      await window.AntaresStore.refresh("fatture");
      setToast({ kind: "ok", msg: `${rowsSel.length} fatture aggiornate` });
      setTimeout(() => setToast(null), 2400);
      setSelected({});
    } catch (ex) {
      setToast({ kind: "err", msg: "Errore: " + (ex.message || ex) });
      setTimeout(() => setToast(null), 4000);
    } finally {
      setBulkBusy(false);
    }
  };

  // anni presenti in archivio (sempre almeno l'anno corrente), per il filtro sotto —
  // altrimenti il Registro cresce all'infinito e diventa impossibile da scorrere (feedback Marco).
  const anniDisponibili = [...new Set([
    String(new Date().getFullYear()),
    ...FATTURE.map(f => (f.data || "").split("/")[2]).filter(Boolean),
  ])].sort((a, b) => b.localeCompare(a));

  const filtered = FATTURE.filter(f => {
    if (filter !== "tutte" && f.tipo !== filter) return false;
    if (search && !(f.controparte.toLowerCase().includes(search.toLowerCase()) || f.id.toLowerCase().includes(search.toLowerCase()))) return false;
    const [, mm, aaaa] = (f.data || "").split("/");
    if (filtroAnno !== "tutti" && aaaa !== filtroAnno) return false;
    if (filtroMese !== "tutti" && mm !== filtroMese) return false;
    return true;
  });
  const totAttive  = FATTURE.filter(f => f.tipo === "attiva").reduce((s, f) => s + f.imponibile, 0);
  const totPassive = FATTURE.filter(f => f.tipo === "passiva").reduce((s, f) => s + f.imponibile, 0);

  return (
    <div className="stack">
      <div className="page-head">
        <div className="page-title-block">
          <span className="eyebrow">Registro · esercizio 2026</span>
          <h1 className="h1">Fatture</h1>
        </div>
        <div className="page-actions">
          <span className="pill teal" style={{ padding: "8px 14px" }}>attive {fmt(totAttive, { decimals: 2 })}</span>
          <span className="pill coral" style={{ padding: "8px 14px" }}>passive {fmt(totPassive, { decimals: 2 })}</span>
          <button className="btn ghost" onClick={() => setShowImport(true)} title="Importa un export Excel da Fatture in Cloud (solo lettura del file)">
            <Icon name="download" /> Importa da Fatture in Cloud
          </button>
        </div>
      </div>

      {showImport && <ImportFattureModal onClose={() => setShowImport(false)} />}

      {/* FORM */}
      <div className="card">
        <div className={`card-bar ${tipo === "passiva" ? "coral" : ""}`} />
        <div className="card-head">
          <h3 className="h3">{editingId ? `Modifica ${editingId}` : "Nuova fattura"}</h3>
          <div className={`segmented ${tipo === "passiva" ? "coral" : "teal"}`}>
            <button type="button" className={tipo === "attiva" ? "active" : ""} onClick={() => !editingId && setTipo("attiva")} disabled={!!editingId}>Attiva</button>
            <button type="button" className={tipo === "passiva" ? "active" : ""} onClick={() => !editingId && setTipo("passiva")} disabled={!!editingId}>Passiva</button>
          </div>
        </div>
        <form onSubmit={submit} className="card-body">
          <div className="form-grid cols-3">
            <div className="field">
              <label className="label">Data</label>
              <input className="input" type="text" value={data} onChange={e => setData(e.target.value)} placeholder="gg/mm/aaaa" />
            </div>
            <div className="field span-2">
              <label className="label">{tipo === "attiva" ? "Cliente" : "Fornitore"}</label>
              <input className="input" type="text" value={controparte} onChange={e => setControparte(e.target.value)}
                placeholder={tipo === "attiva" ? "Rai Pubblicità, Mediaset…" : "Cinevideo Noleggi, Hotel Bernini…"} />
            </div>

            <div className="field">
              <label className="label">Imponibile</label>
              <input className="input num" type="text" placeholder="0,00 €" value={imponibile} onChange={e => setImponibile(e.target.value.replace(",", "."))} />
            </div>
            <div className="field">
              <label className="label">Regime IVA</label>
              <select className="select" value={iva} onChange={e => setIva(+e.target.value)}>
                <option value={22}>Standard 22%</option>
                <option value={10}>Ridotta 10%</option>
                <option value={4}>Super-ridotta 4%</option>
                <option value={0}>Esente / non imponibile</option>
                <option value={-1}>Reverse charge</option>
              </select>
            </div>
            <div className="field">
              <label className="label">Totale fattura</label>
              <input className="input num" type="text" readOnly value={totale ? fmt(totale, { decimals: 2 }) : "—"} />
            </div>

            {tipo === "attiva" ? (
              <div className="field span-2">
                <label className="label">Linea di business</label>
                <div className="segmented teal" style={{ display: "flex" }}>
                  {(window.AntaresData.LINEE_BUSINESS || []).map(L => (
                    <button key={L} type="button" className={linea === L ? "active" : ""} onClick={() => setLinea(L)} style={{flex:1}}>{L}</button>
                  ))}
                </div>
              </div>
            ) : (
              <>
                <div className="field">
                  <label className="label">Categoria</label>
                  <select className="select" value={categoria} onChange={e => setCategoria(e.target.value)}>
                    <option value="">— nessuna —</option>
                    {CATEGORIE_PASSIVE.map(c => <option key={c}>{c}</option>)}
                  </select>
                </div>
                <div className="field">
                  <label className="label">Tipologia</label>
                  <div className="segmented">
                    <button type="button" className={fissoVar === "fisso" ? "active" : ""} onClick={() => setFissoVar("fisso")} style={{flex:1}}>Fisso</button>
                    <button type="button" className={fissoVar === "variabile" ? "active" : ""} onClick={() => setFissoVar("variabile")} style={{flex:1}}>Variabile</button>
                  </div>
                </div>
              </>
            )}

            <div className="field">
              <label className="label">Progetto</label>
              <select className="select" value={progettoId} onChange={e => setProgettoId(e.target.value)}>
                <option value="">— nessuno —</option>
                {progettoOptionsByYear(PROGETTI)}
              </select>
            </div>
            <div className="field">
              <label className="label">Stato</label>
              <select className="select" value={stato} onChange={e => setStato(e.target.value)}>
                {tipo === "attiva" ? (
                  <>
                    <option value="emessa">emessa</option>
                    <option value="incassata">incassata</option>
                    <option value="parzialmente incassata">parzialmente incassata</option>
                    <option value="sollecitata">sollecitata</option>
                  </>
                ) : (
                  <>
                    <option value="da pagare">da pagare</option>
                    <option value="pagata">pagata</option>
                    <option value="parzialmente pagata">parzialmente pagata</option>
                  </>
                )}
              </select>
            </div>
            <div className="field">
              <label className="label">N. documento</label>
              <input className="input" type="text" value={numDoc} onChange={e => setNumDoc(e.target.value)} disabled={!!editingId} />
            </div>
          </div>

          <div className="divider" />
          <div className="row" style={{ justifyContent: "space-between" }}>
            <span className="help">
              {editingId ? `Stai modificando ${editingId}` : "Tutti i campi sono modificabili in seguito · le righe attive vengono marcate teal, le passive corallo."}
            </span>
            <div className="row">
              <button type="button" className="btn ghost" onClick={resetForm}>{editingId ? "Annulla modifica" : "Pulisci"}</button>
              <button type="submit" className="btn primary" disabled={busy}>
                <Icon name="check" /> {busy ? "Salvo…" : (editingId ? "Aggiorna" : "Registra")}
              </button>
            </div>
          </div>
        </form>
      </div>

      {/* REGISTRO */}
      <div className="card">
        <div className="card-bar muted" />
        <div className="card-head" style={{ flexWrap: "wrap", gap: 12 }}>
          <div className="row">
            <h3 className="h3">Registro</h3>
            <span className="pill">{filtered.length} fatture</span>
          </div>
          <div className="row">
            <div className="segmented compact">
              <button className={filter === "tutte" ? "active" : ""} onClick={() => setFilter("tutte")}>Tutte</button>
              <button className={filter === "attiva" ? "active" : ""} onClick={() => setFilter("attiva")}>Attive</button>
              <button className={filter === "passiva" ? "active" : ""} onClick={() => setFilter("passiva")}>Passive</button>
            </div>
            <select className="select" style={{ width: "auto" }} value={filtroAnno} onChange={e => setFiltroAnno(e.target.value)}>
              <option value="tutti">Tutti gli anni</option>
              {anniDisponibili.map(a => <option key={a} value={a}>{a}</option>)}
            </select>
            <select className="select" style={{ width: "auto" }} value={filtroMese} onChange={e => setFiltroMese(e.target.value)}>
              <option value="tutti">Tutti i mesi</option>
              {["01","02","03","04","05","06","07","08","09","10","11","12"].map((m, i) => (
                <option key={m} value={m}>{["Gennaio","Febbraio","Marzo","Aprile","Maggio","Giugno","Luglio","Agosto","Settembre","Ottobre","Novembre","Dicembre"][i]}</option>
              ))}
            </select>
            <div style={{ position: "relative" }}>
              <input className="input" style={{ paddingLeft: 34, minWidth: 200 }} placeholder="Cerca controparte o n°…" value={search} onChange={e => setSearch(e.target.value)} />
              <div style={{ position: "absolute", left: 10, top: "50%", transform: "translateY(-50%)", color: "var(--muted)" }}>
                <Icon name="search" size={14} />
              </div>
            </div>
          </div>
        </div>
        {Object.values(selected).some(Boolean) && (
          <div className="row" style={{ gap: 8, padding: "0 20px 12px", flexWrap: "wrap" }}>
            <span className="pill">{Object.values(selected).filter(Boolean).length} selezionate</span>
            <button type="button" className="btn ghost" disabled={bulkBusy} onClick={() => markSelected(true)}>
              {bulkBusy ? "Aggiorno…" : "Segna pagate/incassate"}
            </button>
            <button type="button" className="btn ghost" disabled={bulkBusy} onClick={() => markSelected(false)}>
              Segna da pagare/emesse
            </button>
            <button type="button" className="btn ghost" disabled={bulkBusy} onClick={() => setSelected({})}>
              Annulla selezione
            </button>
          </div>
        )}
        <div className="table-wrap">
          <table className="table">
            <thead>
              <tr>
                <th style={{ width: 32 }}>
                  <input type="checkbox"
                    checked={filtered.length > 0 && filtered.every(f => selected[f.id])}
                    onChange={e => setSelected(e.target.checked ? Object.fromEntries(filtered.map(f => [f.id, true])) : {})} />
                </th>
                <th>N°</th><th>Data</th><th>Controparte</th>
                <th>Progetto / categoria</th>
                <th className="num">Imponibile</th>
                <th className="num">IVA</th>
                <th>Stato</th>
                <th></th>
              </tr>
            </thead>
            <tbody>
              {filtered.length === 0 && (
                <tr><td colSpan="9" style={{ padding: 24, textAlign: "center", color: "var(--muted)" }}>
                  Nessuna fattura. Compila il form qui sopra e clicca Registra.
                </td></tr>
              )}
              {filtered.map(f => (
                <tr key={f.id} className={f.tipo === "attiva" ? "row-active" : "row-passive"}>
                  <td>
                    <input type="checkbox" checked={!!selected[f.id]}
                      onChange={e => setSelected(s => ({ ...s, [f.id]: e.target.checked }))} />
                  </td>
                  <td className="mono">{f.id}</td>
                  <td className="mono">{f.data}</td>
                  <td><strong>{f.controparte}</strong></td>
                  <td className="muted" style={{ fontSize: 12 }}>
                    {f.progetto !== "—" ? f.progetto : (f.categoria || "—")}
                    {f.categoria && f.progetto !== "—" && <> · {f.categoria}</>}
                  </td>
                  <td className="num">{fmt(f.imponibile, { decimals: 2 })}</td>
                  <td className="num muted">{f.iva === -1 ? "RC" : f.iva + "%"}</td>
                  <td>
                    {f.stato === "incassata" && <span className="pill teal"><span className="dot" /> incassata</span>}
                    {f.stato === "emessa" && <span className="pill blue"><span className="dot" /> emessa</span>}
                    {f.stato === "pagata" && <span className="pill"><span className="dot" /> pagata</span>}
                    {f.stato === "da pagare" && <span className="pill coral"><span className="dot" /> da pagare</span>}
                    {!["incassata","emessa","pagata","da pagare"].includes(f.stato) && f.stato && <span className="pill">{f.stato}</span>}
                  </td>
                  <td style={{ textAlign: "right", whiteSpace: "nowrap" }}>
                    <button onClick={() => startEdit(f)} style={{ marginRight: 4, background: "none", border: "1px solid var(--border)", borderRadius: 6, padding: "3px 8px", cursor: "pointer", fontSize: 12 }}>Modifica</button>
                    <button onClick={() => remove(f.id)} style={{ background: "none", border: "1px solid var(--border)", borderRadius: 6, padding: "3px 8px", cursor: "pointer", fontSize: 12, color: "var(--danger, #c0392b)" }}>Elimina</button>
                  </td>
                </tr>
              ))}
            </tbody>
          </table>
        </div>
      </div>

      {toast && (
        <div className="toast" style={toast.kind === "err" ? { background: "var(--danger, #c0392b)", color: "#fff" } : {}}>
          <div className="toast-icon">{toast.kind === "err" ? "!" : "✓"}</div>
          {toast.msg}
        </div>
      )}
    </div>
  );
}

/* ---- helpers Fatture ---- */
function todayIt() {
  const d = new Date();
  return `${String(d.getDate()).padStart(2,"0")}/${String(d.getMonth()+1).padStart(2,"0")}/${d.getFullYear()}`;
}
function nextFatturaId(tipo) {
  const year = new Date().getFullYear();
  const prefix = tipo === "attiva" ? "F" : "P";
  const ids = (window.AntaresData.FATTURE || [])
    .filter(f => f.id && f.id.startsWith(`${prefix}${year}-`))
    .map(f => parseInt(f.id.split("-")[1], 10) || 0);
  const n = (ids.length ? Math.max(...ids) : 0) + 1;
  return `${prefix}${year}-${String(n).padStart(3,"0")}`;
}

// categorie di conto economico per le fatture passive (condivisa dal form manuale
// e dall'import, così restano sempre le stesse diciture)
const CATEGORIE_PASSIVE = [
  "Noleggio attrezzature", "Trasferte / hotel", "Trasporti", "Catering",
  "Consulenze", "Utenze", "Compensi collaboratori", "Materiali di consumo",
];

// regole parola-chiave -> categoria, ORDINATE dalla più specifica alla più generica
// (la prima che matcha vince: es. "noleggio auto" va controllata prima del generico
// "noleggio", altrimenti finirebbe sempre in Noleggio attrezzature).
const REGOLE_CATEGORIA = [
  ["noleggio auto", "Trasporti"], ["rent a car", "Trasporti"], ["autostrad", "Trasporti"],
  ["telepass", "Trasporti"], ["trenitalia", "Trasporti"], ["italo", "Trasporti"],
  ["taxi", "Trasporti"], [" ncc", "Trasporti"], ["uber", "Trasporti"],
  ["benzina", "Trasporti"], ["carburante", "Trasporti"], ["parcheggio", "Trasporti"],
  ["volo", "Trasporti"], ["aereo", "Trasporti"], ["aerea", "Trasporti"],
  ["hotel", "Trasferte / hotel"], ["albergo", "Trasferte / hotel"], ["booking", "Trasferte / hotel"],
  ["airbnb", "Trasferte / hotel"], ["b&b", "Trasferte / hotel"], ["trasferta", "Trasferte / hotel"],
  ["pernottamento", "Trasferte / hotel"], ["soggiorno", "Trasferte / hotel"],
  ["catering", "Catering"], ["ristorante", "Catering"], ["trattoria", "Catering"],
  ["pranzo", "Catering"], ["buffet", "Catering"], ["pizzeria", "Catering"],
  ["commercialista", "Consulenze"], ["avvocato", "Consulenze"], ["notaio", "Consulenze"],
  ["consulenza", "Consulenze"], ["studio legale", "Consulenze"],
  ["enel", "Utenze"], ["vodafone", "Utenze"], ["tim ", "Utenze"], ["wind ", "Utenze"],
  ["fastweb", "Utenze"], ["telefonia", "Utenze"], ["internet", "Utenze"],
  ["fibra", "Utenze"], [" luce", "Utenze"], [" gas", "Utenze"], ["acqua", "Utenze"],
  ["compenso", "Compensi collaboratori"], ["collaborazione", "Compensi collaboratori"],
  ["prestazione occasionale", "Compensi collaboratori"],
  ["cancelleria", "Materiali di consumo"], ["materiale di consumo", "Materiali di consumo"],
  ["materiali di consumo", "Materiali di consumo"], ["forniture", "Materiali di consumo"],
  ["noleggio", "Noleggio attrezzature"], ["rental", "Noleggio attrezzature"], ["affitto attrezz", "Noleggio attrezzature"],
];

// indovina la categoria da controparte + un testo grezzo (es. colonna "categoria"
// del file importato, quando non è già uno dei valori canonici) — usata solo in
// import: se non trova nulla torna null e la riga va segnalata, mai un default forzato.
function indoviniCategoria(controparte, testoGrezzo) {
  const testo = ((controparte || "") + " " + (testoGrezzo || "")).toLowerCase();
  for (const [kw, cat] of REGOLE_CATEGORIA) {
    if (testo.includes(kw)) return cat;
  }
  return null;
}

/* ============================================================
   3. COLLABORATORI
   ============================================================ */
function Collaboratori() {
  // form
  const [canale, setCanale]   = useState("P.IVA");        // UI: "P.IVA"|"Ritenuta"|"Dipendente"
  const [regime, setRegime]   = useState("forfettario");
  const [nome, setNome]       = useState("");
  const [ruolo, setRuolo]     = useState("");
  const [lordo, setLordo]     = useState("");
  const [progettoId, setProgettoId] = useState("");
  const [dataInizio, setDataInizio] = useState(todayIt());
  const [dataFine, setDataFine]     = useState("");
  const [editingId, setEditingId]   = useState(null);
  const [busy, setBusy]             = useState(false);
  const [toast, setToast]           = useState(null);
  const [filtroAnno, setFiltroAnno] = useState("2026");
  // cedolino (solo Dipendente)
  const [cedFile, setCedFile]       = useState(null);
  const [cedAnalyzing, setCedAnaly] = useState(false);
  const [cedCandidates, setCedCand] = useState([]);     // pattern "totale costo azienda" (fallback)
  const [cedSezioni, setCedSezioni] = useState([]);     // sezioni Teamsystem dedotte
  const [cedSel, setCedSel]         = useState(-1);     // indice sezione selezionata
  const [cedAliquota, setCedAliq]   = useState(23.81);  // % a carico azienda
  const [cedCostOverride, setCedCO] = useState("");
  const [cedExistingPath, setCedXP] = useState(null);

  const canaleDB = canale === "P.IVA" ? "piva" : canale === "Ritenuta" ? "ritenuta" : "dipendente";
  const coeff = canale === "Dipendente" ? 1.49 : canale === "P.IVA" && regime === "ordinario" ? 1.04 : 1.00;
  const costoReale = useMemo(() => {
    const v = parseFloat(lordo) || 0;
    return v ? v * coeff : null;
  }, [lordo, coeff]);
  const nettoRitenuta = useMemo(() => (parseFloat(lordo)||0) * 0.8, [lordo]);

  const reset = () => {
    setEditingId(null);
    setCanale("P.IVA"); setRegime("forfettario");
    setNome(""); setRuolo(""); setLordo("");
    setProgettoId(""); setDataInizio(todayIt()); setDataFine("");
    setCedFile(null); setCedCand([]); setCedSezioni([]); setCedSel(-1);
    setCedAliq(23.81); setCedCO(""); setCedXP(null);
  };

  const onPickCedolino = async (file) => {
    if (!file) return;
    setCedFile(file); setCedCand([]); setCedSezioni([]); setCedSel(-1); setCedCO("");
    setCedAnaly(true);
    const res = await window.AntaresCedolino.analyze(file);
    setCedAnaly(false);
    if (res.error) {
      setToast({ kind: "err", msg: res.error });
      setTimeout(() => setToast(null), 4000);
      setCedFile(null);
      return;
    }
    if (res.kind === "image") {
      setToast({ kind: "err", msg: "Immagine caricata: nessun dato estratto in automatico (serve un PDF testuale). Inserisci il costo azienda a mano qui sotto." });
      setTimeout(() => setToast(null), 6000);
      return;
    }
    // sezioni Teamsystem (priorità: layout multi-cedolino del consulente)
    if (res.sezioni && res.sezioni.length > 0) {
      setCedSezioni(res.sezioni);
      // pre-selezione: cerca quella che matcha il nome del collaboratore corrente
      const idx = res.sezioni.findIndex(s => nameMatches(s.nome, nome));
      if (idx >= 0) {
        setCedSel(idx);
        applySezione(res.sezioni[idx]);
      }
      return;
    }
    // fallback pattern "totale costo azienda" diretto
    setCedCand(res.candidates);
    if (res.candidates.length === 1) setCedCO(String(res.candidates[0].value));
    else if (res.candidates.length === 0) {
      setToast({ kind: "err", msg: "Costo azienda non riconosciuto automaticamente. Inseriscilo a mano." });
      setTimeout(() => setToast(null), 4000);
    }
  };

  const applySezione = (s) => {
    if (!s) return;
    setCedAliq(s.aliquota || 23.81);
    setCedCO(s.costoAzienda ? s.costoAzienda.toFixed(2) : "");
    if (s.nome && !nome) setNome(toTitleCase(s.nome));
    if (s.qualifica && !ruolo) setRuolo(toTitleCase(s.qualifica));
  };

  const recomputeFromSezione = (newAliquota) => {
    const s = cedSezioni[cedSel];
    if (!s) return;
    const contributi = (s.imponibileContr || 0) * (newAliquota / 100);
    const cost = (s.competenze || 0) + contributi + (s.tfr || 0) + (s.inail || 0);
    setCedCO(cost.toFixed(2));
  };

  const viewExistingCedolino = async () => {
    if (!cedExistingPath) return;
    const { url, error } = await window.AntaresCedolino.getSignedUrl(cedExistingPath);
    if (error) { alert("Errore link: " + error.message); return; }
    window.open(url, "_blank");
  };

  const startEdit = (c) => {
    const r = c._raw || {};
    setEditingId(r.id);
    setCanale(r.canale === "piva" ? "P.IVA" : r.canale === "ritenuta" ? "Ritenuta" : "Dipendente");
    setNome(r.nome || ""); setRuolo(r.ruolo || "");
    setLordo(String(r.lordo || ""));
    setProgettoId(r.progetto_id || "");
    setDataInizio(r.data_inizio ? isoToIt(r.data_inizio) : todayIt());
    setDataFine(r.data_fine ? isoToIt(r.data_fine) : "");
    setCedFile(null); setCedCand([]);
    setCedCO(r.costo_reale != null ? String(r.costo_reale) : "");
    setCedXP(r.cedolino_url || null);
    window.scrollTo({ top: 0, behavior: "smooth" });
  };

  const submit = async (e) => {
    e.preventDefault();
    if (!nome.trim() || !lordo) {
      setToast({ kind: "err", msg: "Nome e compenso obbligatori" });
      setTimeout(() => setToast(null), 2500);
      return;
    }
    setBusy(true);
    const anno = parseInt((dataInizio.split("/")[2] || new Date().getFullYear()), 10);
    // costo_reale: per dipendenti, se l'utente ha confermato un valore dal cedolino, usalo;
    // altrimenti lasciamo NULL e l'adapter calcolerà lordo*coeff
    const costoConfermato = cedCostOverride ? parseFloat(String(cedCostOverride).replace(",", ".")) : null;
    const payload = {
      nome: nome.trim(),
      ruolo: ruolo.trim() || null,
      canale: canaleDB,
      lordo: parseFloat(String(lordo).replace(",", ".")),
      coeff: canale === "Dipendente" ? 1.49 : 1.00,
      progetto_id: progettoId || null,
      anno,
      data_inizio: itToIso(dataInizio) || null,
      data_fine: dataFine ? itToIso(dataFine) : null,
      costo_reale: costoConfermato,
    };
    // se è stato scelto un nuovo PDF, upload PRIMA del save
    if (cedFile && canale === "Dipendente") {
      const tmpId = editingId || "new-" + Date.now();
      const up = await window.AntaresCedolino.uploadCedolino(cedFile, tmpId);
      if (up.error) {
        setBusy(false);
        setToast({ kind: "err", msg: "Upload cedolino fallito: " + up.error.message });
        setTimeout(() => setToast(null), 4500);
        return;
      }
      payload.cedolino_url = up.path;
    } else if (cedExistingPath) {
      payload.cedolino_url = cedExistingPath;
    }
    let res;
    if (editingId) res = await window.AntaresAPI.collaboratori.update(editingId, payload);
    else           res = await window.AntaresAPI.collaboratori.insert(payload);
    setBusy(false);
    if (res.error) {
      setToast({ kind: "err", msg: res.error.message });
      setTimeout(() => setToast(null), 3500);
      return;
    }
    await window.AntaresStore.refresh("collaboratori");
    setToast({ kind: "ok", msg: editingId ? "Collaboratore aggiornato" : "Collaboratore aggiunto" });
    setTimeout(() => setToast(null), 2400);
    reset();
  };

  const remove = async (id) => {
    if (!confirm("Eliminare il collaboratore?")) return;
    const res = await window.AntaresAPI.collaboratori.remove(id);
    if (res.error) { setToast({ kind: "err", msg: res.error.message }); setTimeout(() => setToast(null), 3000); return; }
    await window.AntaresStore.refresh("collaboratori");
    setToast({ kind: "ok", msg: "Eliminato" });
    setTimeout(() => setToast(null), 2000);
    if (editingId === id) reset();
  };

  const rowsAll = COLLABORATORI;
  const rows = filtroAnno === "tutti" ? rowsAll : rowsAll.filter(c => String(c.anno) === String(filtroAnno));

  return (
    <div className="stack">
      <div className="page-head">
        <div className="page-title-block">
          <span className="eyebrow">Risorse umane · {filtroAnno}</span>
          <h1 className="h1">Collaboratori</h1>
        </div>
        <div className="page-actions">
          <span className="pill">{rows.length} persone</span>
          <span className="pill teal">costo annuo {fmt(rows.reduce((s,c)=>s+(c.costoReale||0),0))}</span>
        </div>
      </div>

      <div className="card">
        <div className="card-bar blue" />
        <div className="card-head">
          <h3 className="h3">{editingId ? "Modifica collaboratore" : "Nuovo collaboratore"}</h3>
        </div>
        <form className="card-body" onSubmit={submit}>
          <div className="field" style={{ marginBottom: 18 }}>
            <label className="label">Canale di ingaggio</label>
            <div className="segmented" style={{ width: "100%", display: "flex" }}>
              <button type="button" className={canale === "P.IVA" ? "active" : ""} onClick={() => setCanale("P.IVA")} style={{flex:1}}>P. IVA</button>
              <button type="button" className={canale === "Ritenuta" ? "active" : ""} onClick={() => setCanale("Ritenuta")} style={{flex:1}}>Ritenuta d'acconto</button>
              <button type="button" className={canale === "Dipendente" ? "active" : ""} onClick={() => setCanale("Dipendente")} style={{flex:1}}>Dipendente</button>
            </div>
          </div>

          <div className="form-grid cols-3">
            <div className="field span-2">
              <label className="label">Nome e cognome</label>
              <input className="input" type="text" placeholder="Es. Luca Pellegrini" value={nome} onChange={e => setNome(e.target.value)} />
            </div>
            <div className="field">
              <label className="label">Ruolo</label>
              <input className="input" type="text" placeholder="DOP, Editor, Producer…" value={ruolo} onChange={e => setRuolo(e.target.value)} />
            </div>

            {canale === "P.IVA" && (
              <div className="field">
                <label className="label">Regime fiscale</label>
                <div className="segmented" style={{ display: "flex" }}>
                  <button type="button" className={regime === "forfettario" ? "active" : ""} onClick={() => setRegime("forfettario")} style={{flex:1}}>Forfettario</button>
                  <button type="button" className={regime === "ordinario" ? "active" : ""} onClick={() => setRegime("ordinario")} style={{flex:1}}>Ordinario</button>
                </div>
              </div>
            )}

            <div className="field">
              <label className="label">{canale === "Dipendente" ? "RAL (annua lorda)" : "Compenso lordo"}</label>
              <input className="input num" placeholder="0,00 €" value={lordo} onChange={e => setLordo(e.target.value.replace(",","."))} />
            </div>

            {canale === "Ritenuta" && (
              <>
                <div className="field">
                  <label className="label">Ritenuta (20%)</label>
                  <input className="input num" readOnly value={lordo ? fmt((parseFloat(lordo)||0)*0.2, {decimals:2}) : "—"} />
                </div>
                <div className="field">
                  <label className="label">Netto a collaboratore</label>
                  <input className="input num" readOnly value={lordo ? fmt(nettoRitenuta, {decimals:2}) : "—"} />
                </div>
              </>
            )}

            <div className="field">
              <label className="label">Progetto</label>
              <select className="select" value={progettoId} onChange={e => setProgettoId(e.target.value)}>
                <option value="">— nessuno —</option>
                {progettoOptionsByYear(PROGETTI)}
              </select>
            </div>
            <div className="field">
              <label className="label">Inizio</label>
              <input className="input" value={dataInizio} onChange={e => setDataInizio(e.target.value)} placeholder="gg/mm/aaaa" />
            </div>
            <div className="field">
              <label className="label">Fine (se a tempo)</label>
              <input className="input" placeholder="gg/mm/aaaa" value={dataFine} onChange={e => setDataFine(e.target.value)} />
            </div>
          </div>

          {canale === "Dipendente" && (
            <>
              <div className="divider" />
              <div style={{ background: "var(--surface-2)", border: "1px dashed var(--border)", borderRadius: 10, padding: 16 }}>
                <div style={{ display: "flex", alignItems: "center", justifyContent: "space-between", flexWrap: "wrap", gap: 12, marginBottom: 12 }}>
                  <div>
                    <strong style={{ fontFamily: "var(--serif)", fontSize: 16 }}>Cedolino (PDF o immagine)</strong>
                    <div className="help">Carica PDF, JPG o PNG. Sui PDF provo a estrarre il costo azienda. Sulle immagini lo inserisci a mano.</div>
                  </div>
                  <div style={{ display: "flex", gap: 8, alignItems: "center" }}>
                    {cedExistingPath && !cedFile && (
                      <button type="button" className="btn ghost" onClick={viewExistingCedolino}>
                        <Icon name="file" /> Vedi cedolino salvato
                      </button>
                    )}
                    <label className="btn ghost" style={{ cursor: "pointer", margin: 0 }}>
                      <Icon name="file" /> {cedFile ? "Cambia file" : "Scegli file"}
                      <input
                        type="file"
                        accept="application/pdf,image/jpeg,image/png,image/webp,.jpg,.jpeg,.png,.webp"
                        style={{ display: "none" }}
                        onChange={e => onPickCedolino(e.target.files?.[0])}
                      />
                    </label>
                  </div>
                </div>

                {cedFile && (
                  <div style={{ fontSize: 13, color: "var(--muted)", marginBottom: 8 }}>
                    📄 <strong style={{ color: "var(--text)" }}>{cedFile.name}</strong> · {Math.round(cedFile.size/1024)} KB
                  </div>
                )}

                {cedAnalyzing && <div className="help">⏳ Analisi del PDF in corso…</div>}

                {!cedAnalyzing && cedSezioni.length > 0 && (
                  <div style={{ marginBottom: 12 }}>
                    <div className="help" style={{ marginBottom: 6 }}>
                      Trovati <strong>{cedSezioni.length} cedolini</strong> nel PDF. Seleziona quello del collaboratore corrente:
                    </div>
                    <div style={{ display: "flex", flexDirection: "column", gap: 6 }}>
                      {cedSezioni.map((s, i) => (
                        <button
                          key={i} type="button"
                          onClick={() => { setCedSel(i); applySezione(s); }}
                          style={{
                            display: "grid", gridTemplateColumns: "1fr auto auto", gap: 12,
                            alignItems: "center", padding: "10px 12px", borderRadius: 8,
                            border: "1px solid " + (cedSel === i ? "var(--teal)" : "var(--border)"),
                            background: cedSel === i ? "rgba(0,180,180,.08)" : "transparent",
                            cursor: "pointer", textAlign: "left",
                          }}
                        >
                          <div>
                            <strong style={{ fontFamily: "var(--serif)", fontSize: 14 }}>{toTitleCase(s.nome || "—")}</strong>
                            {s.qualifica && <span className="muted" style={{ marginLeft: 8, fontSize: 12 }}>{s.qualifica}</span>}
                            {s.foglio && <span className="muted" style={{ marginLeft: 8, fontSize: 11 }}>foglio {s.foglio}</span>}
                          </div>
                          <div className="muted" style={{ fontSize: 11 }}>
                            {s.tipoContratto === "spettacolo" ? "Spettacolo (ENPALS)"
                              : s.tipoContratto === "collab" ? "Collaboratore"
                              : "CCNL"}
                          </div>
                          <div className="mono" style={{ fontSize: 16, fontWeight: 600, color: "var(--teal)" }}>
                            {s.parziale && <span title={"Estrazione incompleta: manca " + s.mancanti.join(", ")}>⚠️ </span>}
                            {s.costoAzienda ? fmt(s.costoAzienda, { decimals: 2 }) : "—"}
                          </div>
                        </button>
                      ))}
                    </div>
                    {cedSel >= 0 && cedSezioni[cedSel] && (
                      <div style={{ marginTop: 12, padding: 12, background: "var(--surface, transparent)", border: "1px dashed var(--border)", borderRadius: 8 }}>
                        <div className="help" style={{ marginBottom: 8 }}>Scomposizione del costo dedotto:</div>
                        {cedSezioni[cedSel].parziale && (
                          <div className="login-error" style={{ marginBottom: 10, fontSize: 12 }}>
                            ⚠️ Estrazione incompleta (mancano: {cedSezioni[cedSel].mancanti.join(", ")}). Verifica i valori prima di confermare.
                          </div>
                        )}
                        {(() => {
                          const s = cedSezioni[cedSel];
                          return (
                            <div style={{ display: "grid", gridTemplateColumns: "1fr auto", gap: "4px 16px", fontSize: 13 }}>
                              <span>Competenze (lordo lavoratore)</span>            <span className="mono num">{fmt(s.competenze||0, {decimals:2})}</span>
                              <span>Imponibile contributivo × aliquota azienda</span><span className="mono num">{fmt((s.imponibileContr||0)*(cedAliquota/100), {decimals:2})}</span>
                              <span>TFR maturato mese</span>                         <span className="mono num">{fmt(s.tfr||0, {decimals:2})}</span>
                              <span>Contributi INAIL azienda</span>                  <span className="mono num">{fmt(s.inail||0, {decimals:2})}</span>
                              <span style={{ borderTop: "1px solid var(--border)", paddingTop: 4 }}><strong>Costo reale azienda (stimato)</strong></span>
                              <span style={{ borderTop: "1px solid var(--border)", paddingTop: 4 }} className="mono num"><strong>{fmt(parseFloat(cedCostOverride)||0, {decimals:2})}</strong></span>
                            </div>
                          );
                        })()}
                        <div style={{ marginTop: 10, display: "grid", gridTemplateColumns: "auto 1fr", gap: 8, alignItems: "center" }}>
                          <label className="label" style={{ margin: 0 }}>Aliquota azienda %</label>
                          <input
                            className="input num" type="number" step="0.01"
                            value={cedAliquota}
                            onChange={e => { const v = parseFloat(e.target.value)||0; setCedAliq(v); recomputeFromSezione(v); }}
                            style={{ maxWidth: 120 }}
                          />
                        </div>
                      </div>
                    )}
                  </div>
                )}

                {!cedAnalyzing && cedSezioni.length === 0 && cedCandidates.length > 0 && (
                  <div>
                    <div className="help" style={{ marginBottom: 6 }}>Costi azienda trovati nel PDF — seleziona quello giusto:</div>
                    <div style={{ display: "flex", flexWrap: "wrap", gap: 8 }}>
                      {cedCandidates.map((c, i) => (
                        <button
                          key={i} type="button"
                          onClick={() => setCedCO(String(c.value))}
                          className="btn"
                          style={{
                            border: "1px solid " + (cedCostOverride === String(c.value) ? "var(--teal)" : "var(--border)"),
                            background: cedCostOverride === String(c.value) ? "rgba(0,180,180,.08)" : "transparent",
                            fontFamily: "var(--mono, monospace)",
                          }}
                        >
                          <span style={{ fontWeight: 600 }}>{fmt(c.value, { decimals: 2 })}</span>
                          <span className="muted" style={{ fontSize: 11, marginLeft: 8 }}>{c.label}</span>
                        </button>
                      ))}
                    </div>
                  </div>
                )}

                <div style={{ display: "grid", gridTemplateColumns: "1fr 2fr", gap: 12, alignItems: "end", marginTop: 12 }}>
                  <div className="field" style={{ margin: 0 }}>
                    <label className="label">Costo reale azienda confermato</label>
                    <input
                      className="input num" placeholder="0,00 €"
                      value={cedCostOverride}
                      onChange={e => setCedCO(e.target.value.replace(",", "."))}
                    />
                  </div>
                  <div className="help">
                    Sovrascrive la stima <em>lordo × coefficiente</em> con il valore reale dal cedolino. Lascialo vuoto per usare la stima.
                  </div>
                </div>
              </div>
            </>
          )}

          <div className="divider" />
          <div style={{
            background: "var(--surface-2)", border: "1px solid var(--teal)", borderRadius: 10,
            padding: 16, display: "grid", gridTemplateColumns: "1fr 1fr 1fr", gap: 16
          }}>
            <div>
              <div className="kpi-label">Compenso lordo</div>
              <div style={{ fontFamily: "var(--serif)", fontSize: 22, fontWeight: 600, marginTop: 4 }}>
                {lordo ? fmt(parseFloat(lordo)||0, {decimals:2}) : "—"}
              </div>
            </div>
            <div>
              <div className="kpi-label">Oneri stimati</div>
              <div style={{ fontFamily: "var(--serif)", fontSize: 22, fontWeight: 600, marginTop: 4 }} className="muted">
                {costoReale && lordo ? fmt(costoReale - (parseFloat(lordo)||0), {decimals:2}) : "—"}
              </div>
              <div className="help" style={{ marginTop: 2 }}>
                {canale === "Dipendente" && "INPS + INAIL + TFR ≈ 49%"}
                {canale === "P.IVA" && regime === "ordinario" && "Rivalsa 4% (cassa o gestione separata)"}
                {canale === "P.IVA" && regime === "forfettario" && "Nessun onere a carico azienda"}
                {canale === "Ritenuta" && "Ritenuta versata dall'azienda, non aggiuntiva"}
              </div>
            </div>
            <div>
              <div className="kpi-label">Costo reale azienda</div>
              <div style={{ fontFamily: "var(--serif)", fontSize: 26, fontWeight: 700, marginTop: 4, color: "var(--teal)" }}>
                {cedCostOverride ? fmt(parseFloat(cedCostOverride)||0, {decimals:2})
                  : (costoReale ? fmt(costoReale, {decimals:2}) : "—")}
              </div>
              {cedCostOverride && <div className="help" style={{ marginTop: 2 }}>da cedolino (override)</div>}
            </div>
          </div>

          <div className="row" style={{ justifyContent: "flex-end", marginTop: 18 }}>
            <button type="button" className="btn ghost" onClick={reset}>{editingId ? "Annulla modifica" : "Pulisci"}</button>
            <button type="submit" className="btn primary" disabled={busy}>
              <Icon name="check" /> {busy ? "Salvo…" : (editingId ? "Aggiorna" : "Aggiungi collaboratore")}
            </button>
          </div>
        </form>
      </div>

      <div className="card">
        <div className="card-bar muted" />
        <div className="card-head" style={{ flexWrap: "wrap" }}>
          <h3 className="h3">Collaboratori per progetto</h3>
          <div className="segmented compact">
            <button className={filtroAnno === "2026" ? "active" : ""} onClick={() => setFiltroAnno("2026")}>2026</button>
            <button className={filtroAnno === "2025" ? "active" : ""} onClick={() => setFiltroAnno("2025")}>2025</button>
            <button className={filtroAnno === "tutti" ? "active" : ""} onClick={() => setFiltroAnno("tutti")}>Tutti</button>
          </div>
        </div>
        <div className="table-wrap">
          <table className="table">
            <thead>
              <tr>
                <th>Persona</th><th>Ruolo</th><th>Canale</th><th>Progetto</th>
                <th className="num">Compenso lordo</th>
                <th className="num">Costo reale</th>
                <th></th>
              </tr>
            </thead>
            <tbody>
              {rows.length === 0 && (
                <tr><td colSpan="7" style={{ padding: 24, textAlign: "center", color: "var(--muted)" }}>
                  Nessun collaboratore. Aggiungine uno dal form qui sopra.
                </td></tr>
              )}
              {rows.map(c => (
                <tr key={c.id}>
                  <td><strong>{c.nome}</strong></td>
                  <td className="muted">{c.ruolo}</td>
                  <td>
                    {c.canale === "Dipendente" && <span className="pill blue">{c.canale}</span>}
                    {c.canale.startsWith("P.IVA") && <span className="pill teal">{c.canale}</span>}
                    {c.canale === "Ritenuta d'acconto" && <span className="pill yellow">ritenuta</span>}
                  </td>
                  <td className="muted">{c.progetto}</td>
                  <td className="num">{fmt(c.lordo || c.compenso || 0)}</td>
                  <td className="num"><strong>{fmt(c.costoReale)}</strong></td>
                  <td style={{ textAlign: "right", whiteSpace: "nowrap" }}>
                    <button onClick={() => startEdit(c)} style={{ marginRight: 4, background: "none", border: "1px solid var(--border)", borderRadius: 6, padding: "3px 8px", cursor: "pointer", fontSize: 12 }}>Modifica</button>
                    <button onClick={() => remove(c.id)} style={{ background: "none", border: "1px solid var(--border)", borderRadius: 6, padding: "3px 8px", cursor: "pointer", fontSize: 12, color: "var(--danger, #c0392b)" }}>Elimina</button>
                  </td>
                </tr>
              ))}
              <tr className="row-total">
                <td colSpan="4">Totale</td>
                <td className="num">{fmt(rows.reduce((s,c)=>s+(c.lordo||c.compenso||0),0))}</td>
                <td className="num">{fmt(rows.reduce((s,c)=>s+(c.costoReale||0),0))}</td>
                <td></td>
              </tr>
            </tbody>
          </table>
        </div>
      </div>

      {toast && (
        <div className="toast" style={toast.kind === "err" ? { background: "var(--danger, #c0392b)", color: "#fff" } : {}}>
          <div className="toast-icon">{toast.kind === "err" ? "!" : "✓"}</div>
          {toast.msg}
        </div>
      )}
    </div>
  );
}

/* ---- helpers date ---- */
function isoToIt(iso) {
  if (!iso) return "";
  const [y,m,d] = iso.split("-");
  return `${d}/${m}/${y}`;
}
function itToIso(it) {
  if (!it || !it.includes("/")) return null;
  const [d,m,y] = it.split("/");
  return `${y}-${m.padStart(2,"0")}-${d.padStart(2,"0")}`;
}
function toTitleCase(s) {
  return (s || "").toLowerCase().replace(/\b[a-zà-ú]/g, c => c.toUpperCase()).replace(/\s+/g, " ").trim();
}
function nameMatches(a, b) {
  if (!a || !b) return false;
  const norm = (x) => x.toLowerCase().replace(/[^a-zà-ú]+/g, " ").trim().split(/\s+/).sort().join(" ");
  const A = norm(a), B = norm(b);
  if (!A || !B) return false;
  // match se almeno 2 parole in comune (cognome + nome)
  const aw = new Set(A.split(" "));
  const bw = B.split(" ").filter(w => aw.has(w));
  return bw.length >= 2;
}

/* ============================================================
   4. CESPITI
   ============================================================ */
function Cespiti() {
  const [bene, setBene]         = useState("");
  const [costo, setCosto]       = useState("");
  const [anno, setAnno]         = useState(new Date().getFullYear());
  const [aliquota, setAliquota] = useState(20);
  const [editingId, setEditingId] = useState(null);
  const [busy, setBusy]         = useState(false);
  const [toast, setToast]       = useState(null);

  const quotaAnnua = useMemo(() => (parseFloat(costo)||0) * (aliquota / 100), [costo, aliquota]);

  const reset = () => {
    setEditingId(null);
    setBene(""); setCosto(""); setAnno(new Date().getFullYear()); setAliquota(20);
  };

  const startEdit = (c) => {
    const r = c._raw || {};
    setEditingId(r.id);
    setBene(r.bene || ""); setCosto(String(r.costo || ""));
    setAnno(r.anno_acquisto || new Date().getFullYear());
    setAliquota(parseFloat(r.aliquota) || 20);
    window.scrollTo({ top: 0, behavior: "smooth" });
  };

  const submit = async (e) => {
    e.preventDefault();
    if (!bene.trim() || !costo) {
      setToast({ kind: "err", msg: "Descrizione e costo obbligatori" });
      setTimeout(() => setToast(null), 2500);
      return;
    }
    setBusy(true);
    const payload = {
      bene: bene.trim(),
      anno_acquisto: parseInt(anno, 10),
      costo: parseFloat(String(costo).replace(",", ".")),
      aliquota: parseFloat(aliquota),
    };
    let res;
    if (editingId) res = await window.AntaresAPI.cespiti.update(editingId, payload);
    else           res = await window.AntaresAPI.cespiti.insert(payload);
    setBusy(false);
    if (res.error) {
      setToast({ kind: "err", msg: res.error.message });
      setTimeout(() => setToast(null), 3500);
      return;
    }
    await window.AntaresStore.refresh("cespiti");
    setToast({ kind: "ok", msg: editingId ? "Cespite aggiornato" : "Cespite iscritto" });
    setTimeout(() => setToast(null), 2400);
    reset();
  };

  const remove = async (id) => {
    if (!confirm("Eliminare il cespite?")) return;
    const res = await window.AntaresAPI.cespiti.remove(id);
    if (res.error) { setToast({ kind: "err", msg: res.error.message }); setTimeout(() => setToast(null), 3000); return; }
    await window.AntaresStore.refresh("cespiti");
    setToast({ kind: "ok", msg: "Eliminato" });
    setTimeout(() => setToast(null), 2000);
    if (editingId === id) reset();
  };

  const totCosto   = CESPITI.reduce((s, c) => s + c.costo, 0);
  const totResiduo = CESPITI.reduce((s, c) => s + c.residuo, 0);
  const totQuota   = CESPITI.reduce((s, c) => s + c.quotaAnnua, 0);

  return (
    <div className="stack">
      <div className="page-head">
        <div className="page-title-block">
          <span className="eyebrow">Beni strumentali · esercizio 2026</span>
          <h1 className="h1">Cespiti</h1>
        </div>
      </div>

      <div className="kpi-grid">
        <div className="kpi">
          <div className="kpi-label">Valore storico</div>
          <div className="kpi-value">{fmt(totCosto)}</div>
          <div className="kpi-sub">{CESPITI.length} beni in libro</div>
        </div>
        <div className="kpi blue">
          <div className="kpi-label">Valore residuo</div>
          <div className="kpi-value">{fmt(totResiduo)}</div>
          <div className="kpi-sub">al 31/12/{new Date().getFullYear()}</div>
        </div>
        <div className="kpi yellow">
          <div className="kpi-label">Ammortamento annuo</div>
          <div className="kpi-value">{fmt(totQuota)}</div>
          <div className="kpi-sub">competenza esercizio</div>
        </div>
        <div className="kpi coral">
          <div className="kpi-label">Quota mensile</div>
          <div className="kpi-value">{fmt(totQuota / 12)}</div>
          <div className="kpi-sub">peso costi fissi</div>
        </div>
      </div>

      <div className="card">
        <div className="card-bar blue" />
        <div className="card-head">
          <h3 className="h3">{editingId ? "Modifica cespite" : "Nuovo cespite"}</h3>
        </div>
        <form className="card-body" onSubmit={submit}>
          <div className="form-grid cols-3">
            <div className="field span-2">
              <label className="label">Descrizione bene</label>
              <input className="input" placeholder="Es. Camera Sony FX9, Furgone Iveco…" value={bene} onChange={e => setBene(e.target.value)} />
            </div>
            <div className="field">
              <label className="label">Categoria</label>
              <select className="select" defaultValue="Attrezzature audiovisive">
                <option>Attrezzature audiovisive</option>
                <option>Automezzi</option>
                <option>Hardware / IT</option>
                <option>Mobili e arredi</option>
                <option>Software</option>
              </select>
            </div>

            <div className="field">
              <label className="label">Costo storico</label>
              <input className="input num" placeholder="0,00 €" value={costo} onChange={e => setCosto(e.target.value.replace(",","."))} />
            </div>
            <div className="field">
              <label className="label">Anno acquisto</label>
              <select className="select" value={anno} onChange={e => setAnno(+e.target.value)}>
                {[0,1,2,3,4,5].map(off => {
                  const y = new Date().getFullYear() - off;
                  return <option key={y} value={y}>{y}</option>;
                })}
              </select>
            </div>
            <div className="field">
              <label className="label">Aliquota ammortamento</label>
              <select className="select" value={aliquota} onChange={e => setAliquota(+e.target.value)}>
                <option value={10}>10% (10 anni)</option>
                <option value={15}>15% (~7 anni)</option>
                <option value={20}>20% (5 anni)</option>
                <option value={25}>25% (4 anni)</option>
                <option value={33}>33% (3 anni)</option>
              </select>
            </div>

            <div className="field span-full">
              <div style={{
                background: "var(--surface-2)", border: "1px solid var(--border)", borderRadius: 10,
                padding: 14, display: "grid", gridTemplateColumns: "1fr 1fr 1fr", gap: 16
              }}>
                <div>
                  <div className="kpi-label">Quota annua</div>
                  <div className="mono" style={{ fontSize: 18, marginTop: 4 }}>{costo ? fmt(quotaAnnua, {decimals:2}) : "—"}</div>
                </div>
                <div>
                  <div className="kpi-label">Quota mensile</div>
                  <div className="mono muted" style={{ fontSize: 18, marginTop: 4 }}>{costo ? fmt(quotaAnnua/12, {decimals:2}) : "—"}</div>
                </div>
                <div>
                  <div className="kpi-label">Anni di ammortamento</div>
                  <div className="mono muted" style={{ fontSize: 18, marginTop: 4 }}>{aliquota ? Math.round(100/aliquota) + " anni" : "—"}</div>
                </div>
              </div>
            </div>
          </div>
          <div className="row" style={{ justifyContent: "flex-end", marginTop: 16 }}>
            <button type="button" className="btn ghost" onClick={reset}>{editingId ? "Annulla modifica" : "Pulisci"}</button>
            <button type="submit" className="btn primary" disabled={busy}>
              <Icon name="check" /> {busy ? "Salvo…" : (editingId ? "Aggiorna cespite" : "Iscrivi a libro cespiti")}
            </button>
          </div>
        </form>
      </div>

      <div className="card">
        <div className="card-bar muted" />
        <div className="card-head">
          <h3 className="h3">Libro cespiti</h3>
          <button className="btn ghost"><Icon name="pdf" /> Stampa libro</button>
        </div>
        <div className="table-wrap">
          <table className="table">
            <thead>
              <tr>
                <th>Bene</th>
                <th className="num">Anno</th>
                <th className="num">Costo storico</th>
                <th className="num">Aliquota</th>
                <th className="num">Quota annua</th>
                <th className="num">Residuo</th>
                <th></th>
              </tr>
            </thead>
            <tbody>
              {CESPITI.length === 0 && (
                <tr><td colSpan="7" style={{ padding: 24, textAlign: "center", color: "var(--muted)" }}>
                  Nessun cespite. Iscrivi il primo dal form qui sopra.
                </td></tr>
              )}
              {CESPITI.map(c => (
                <tr key={c.id}>
                  <td><strong>{c.bene}</strong></td>
                  <td className="num mono">{c.anno}</td>
                  <td className="num">{fmt(c.costo)}</td>
                  <td className="num muted">{c.aliquota}%</td>
                  <td className="num">{fmt(c.quotaAnnua)}</td>
                  <td className="num"><strong>{fmt(c.residuo)}</strong></td>
                  <td style={{ textAlign: "right", whiteSpace: "nowrap" }}>
                    <button onClick={() => startEdit(c)} style={{ marginRight: 4, background: "none", border: "1px solid var(--border)", borderRadius: 6, padding: "3px 8px", cursor: "pointer", fontSize: 12 }}>Modifica</button>
                    <button onClick={() => remove(c.id)} style={{ background: "none", border: "1px solid var(--border)", borderRadius: 6, padding: "3px 8px", cursor: "pointer", fontSize: 12, color: "var(--danger, #c0392b)" }}>Elimina</button>
                  </td>
                </tr>
              ))}
              <tr className="row-total">
                <td>Totale</td><td></td>
                <td className="num">{fmt(totCosto)}</td>
                <td></td>
                <td className="num">{fmt(totQuota)}</td>
                <td className="num">{fmt(totResiduo)}</td>
                <td></td>
              </tr>
            </tbody>
          </table>
        </div>
      </div>

      {toast && (
        <div className="toast" style={toast.kind === "err" ? { background: "var(--danger, #c0392b)", color: "#fff" } : {}}>
          <div className="toast-icon">{toast.kind === "err" ? "!" : "✓"}</div>
          {toast.msg}
        </div>
      )}
    </div>
  );
}

/* ============================================================
   IMPORT FATTURE da Fatture in Cloud (export Excel/CSV)
   Legge il file in locale (nessuna scrittura su FiC), mappa e fa upsert.
   ============================================================ */
function ImportFattureModal({ onClose }) {
  const [rows, setRows]   = useState([]);     // righe mappate {id,tipo,data,controparte,imponibile,iva,categoria,stato}
  const [tipoRil, setTipoRil] = useState(""); // attiva/passiva rilevato
  const [fileName, setFileName] = useState("");
  const [err, setErr]     = useState("");
  const [busy, setBusy]   = useState(false);
  const [done, setDone]   = useState(null);

  const parseEuro = (v) => {
    if (typeof v === "number") return v;
    let s = String(v || "").replace(/eur/i, "").replace(/\s/g, "");
    if (!s) return 0;
    s = s.replace(/,/g, ""); // FiC: virgola = separatore migliaia
    const n = parseFloat(s);
    return isNaN(n) ? 0 : n;
  };
  const fixDate = (s) => {
    const p = String(s || "").trim().split("/");
    if (p.length !== 3) return "";
    let [g, m, a] = p;
    if (a.length === 2) a = "20" + a;
    return g.padStart(2, "0") + "/" + m.padStart(2, "0") + "/" + a;
  };
  const slug = (s) => String(s || "").toLowerCase().replace(/[^a-z0-9]+/g, "-").replace(/^-+|-+$/g, "").slice(0, 18);
  const snapRate = (imp, ivaAmt) => {
    if (imp <= 0) return 0;
    const r = Math.round((ivaAmt / imp) * 100);
    if (Math.abs(r - 22) <= 1) return 22;
    if (Math.abs(r - 10) <= 1) return 10;
    if (Math.abs(r - 4) <= 1) return 4;
    return 0;
  };

  const handleFile = (file) => {
    setErr(""); setDone(null); setRows([]); setTipoRil("");
    if (!file) return;
    if (!window.XLSX) { setErr("Libreria Excel non caricata. Ricarica la pagina."); return; }
    setFileName(file.name);
    const reader = new FileReader();
    reader.onload = (e) => {
      try {
        const wb = window.XLSX.read(new Uint8Array(e.target.result), { type: "array" });
        const ws = wb.Sheets[wb.SheetNames[0]];
        const grid = window.XLSX.utils.sheet_to_json(ws, { header: 1, defval: "", raw: false });
        // trova riga intestazione (contiene "Data" e "Imponibile")
        const hi = grid.findIndex(r => r.some(c => String(c).toLowerCase().trim() === "data") && r.some(c => String(c).toLowerCase().includes("imponibile")));
        if (hi < 0) { setErr("Non riconosco il formato: manca la riga con le colonne (Data … Imponibile)."); return; }
        const H = grid[hi].map(c => String(c).toLowerCase().trim());
        const idxExact = (n) => H.indexOf(n);
        const idxInc = (...names) => H.findIndex(h => names.some(n => h.includes(n)));
        const ci = {
          data: idxExact("data") >= 0 ? idxExact("data") : idxInc("data"),
          nr: H.findIndex(h => h.startsWith("nr") || h.includes("numero") || h.includes("n.ro")),
          fornitore: idxExact("fornitore"),
          cliente: idxExact("cliente"),
          imp: idxInc("imponibile"),
          iva: idxExact("iva") >= 0 ? idxExact("iva") : H.findIndex(h => h === "iva" || (h.includes("iva") && !h.includes("partita"))),
          cat: idxExact("categoria"),
          serie: idxExact("serie"),
          saldato: idxExact("saldato"),
        };
        const tipo = ci.fornitore >= 0 ? "passiva" : (ci.cliente >= 0 ? "attiva" : "passiva");
        const cpIdx = tipo === "passiva" ? ci.fornitore : ci.cliente;
        const out = [];
        for (let i = hi + 1; i < grid.length; i++) {
          const r = grid[i];
          const cp = String(r[cpIdx] || "").trim();
          const dataIt = fixDate(r[ci.data]);
          const imp = parseEuro(r[ci.imp]);
          if (!cp || !dataIt || (imp === 0 && !cp)) continue;
          if (!cp && imp === 0) continue;
          const ivaAmt = parseEuro(r[ci.iva]);
          const rate = snapRate(imp, ivaAmt);
          const nr = String(r[ci.nr] || "").trim();
          const aaaa = dataIt.split("/")[2] || "";
          const serie = ci.serie >= 0 ? String(r[ci.serie] || "").trim() : "";
          const saldato = ci.saldato >= 0 ? /^s/i.test(String(r[ci.saldato] || "").trim()) : null; // SI -> true
          const id = tipo === "attiva"
            ? "F-" + aaaa + "-" + slug((serie ? serie + "-" : "") + (nr || cp))
            : "P-" + dataIt.split("/").reverse().join("") + "-" + slug(cp) + (nr ? "-" + slug(nr) : "");
          const stato = tipo === "attiva"
            ? (saldato === true ? "incassata" : "emessa")
            : (saldato === true ? "pagata" : "da pagare");
          // categoria: se il file ne ha già una che coincide con una delle nostre
          // (es. FiC esporta già "Trasporti"), usiamo quella; altrimenti proviamo a
          // indovinarla da controparte + testo grezzo del file; se non riconosciuta
          // resta vuota e la riga va segnalata — mai un default forzato (vedi nota Marco).
          let categoria = null, categoriaIncerta = false;
          if (tipo === "passiva") {
            const grezza = String(r[ci.cat] || "").trim();
            const esatta = CATEGORIE_PASSIVE.find(c => c.toLowerCase() === grezza.toLowerCase());
            categoria = esatta || indoviniCategoria(cp, grezza);
            if (!categoria) categoriaIncerta = true;
          }
          out.push({
            id, tipo, data: dataIt, controparte: cp, imponibile: imp, iva: rate,
            categoria, categoriaIncerta, stato,
          });
        }
        if (out.length === 0) { setErr("Nessuna fattura trovata nel file."); return; }
        setTipoRil(tipo);
        setRows(out);
      } catch (ex) {
        console.error("[import fatture]", ex);
        setErr("Errore lettura file: " + (ex.message || ex));
      }
    };
    reader.readAsArrayBuffer(file);
  };

  const totImp = rows.reduce((s, r) => s + r.imponibile, 0);
  const nIncerte = rows.filter(r => r.categoriaIncerta).length;

  const updateRigaCategoria = (idx, val) => {
    setRows(rs => rs.map((r, i) => i === idx ? { ...r, categoria: val || null, categoriaIncerta: false } : r));
  };

  const doImport = async () => {
    setBusy(true); setErr("");
    try {
      const dbRows = rows.map(r => window.AntaresStore.fatturaToDB({
        id: r.id, tipo: r.tipo, data: r.data, controparte: r.controparte,
        imponibile: r.imponibile, iva: r.iva, categoria: r.categoria,
        fv: r.tipo === "passiva" ? "V" : null, progetto_id: null, stato: r.stato,
        linea: null,
      }));
      const { error } = await window.AntaresAPI.withTimeout(window.AntaresDB.from("fatture").upsert(dbRows, { onConflict: "id" }));
      if (error) { setErr(error.message); setBusy(false); return; }
      await window.AntaresStore.refresh("fatture");
      setBusy(false);
      setDone(dbRows.length);
    } catch (ex) {
      setBusy(false); setErr(ex.message || String(ex));
    }
  };

  return (
    <div onClick={onClose} style={{ position: "fixed", inset: 0, background: "rgba(0,0,0,.4)", zIndex: 200, display: "flex", alignItems: "center", justifyContent: "center", padding: 16 }}>
      <div onClick={e => e.stopPropagation()} style={{ background: "var(--surface, #fff)", borderRadius: 14, padding: 24, width: "100%", maxWidth: 640, maxHeight: "90vh", overflow: "auto", boxShadow: "0 20px 60px rgba(0,0,0,.25)" }}>
        <h3 style={{ margin: 0, marginBottom: 6, fontFamily: "Playfair Display, serif", fontSize: 22 }}>Importa da Fatture in Cloud</h3>
        <p style={{ margin: 0, marginBottom: 14, fontSize: 13, color: "var(--muted)" }}>
          Seleziona l'export Excel (.xls/.xlsx) scaricato da FiC — attive o passive. Il file viene letto solo in locale:
          <strong> nessuna modifica su Fatture in Cloud</strong>. Re-importi senza creare doppioni.
        </p>
        {err && <div className="login-error" style={{ marginBottom: 10 }}>{err}</div>}

        {done != null ? (
          <div style={{ padding: "12px 0" }}>
            <div className="pill teal" style={{ padding: "8px 14px" }}>✓ Importate/aggiornate {done} fatture</div>
            <p className="muted" style={{ fontSize: 13, marginTop: 10 }}>
              Le fatture sono nel registro <strong>senza progetto</strong>: assegnalo dove serve aprendole in modifica.
            </p>
          </div>
        ) : (
          <>
            <input type="file" accept=".xls,.xlsx,.csv" onChange={e => handleFile(e.target.files[0])} style={{ marginBottom: 12 }} />
            {fileName && <div className="muted" style={{ fontSize: 12, marginBottom: 8 }}>File: {fileName}</div>}

            {rows.length > 0 && (
              <>
                <div className="row" style={{ gap: 10, marginBottom: 8, flexWrap: "wrap" }}>
                  <span className={"pill " + (tipoRil === "passiva" ? "coral" : "teal")}>{rows.length} fatture {tipoRil}</span>
                  <span className="muted" style={{ fontSize: 13 }}>Totale imponibile: <strong className="mono">{fmt(totImp, { decimals: 2 })}</strong></span>
                  {nIncerte > 0 && (
                    <span className="pill coral">⚠️ {nIncerte} categoria non riconosciuta, verifica sotto</span>
                  )}
                </div>
                <div className="table-wrap" style={{ maxHeight: "40vh", overflow: "auto", marginBottom: 14 }}>
                  <table className="table">
                    <thead>
                      <tr>
                        <th>Data</th><th>Controparte</th><th className="num">Imponibile</th><th className="num">IVA</th>
                        {tipoRil === "passiva" && <th>Categoria</th>}
                      </tr>
                    </thead>
                    <tbody>
                      {rows.slice(0, 50).map((r, i) => (
                        <tr key={i}>
                          <td className="mono" style={{ fontSize: 12 }}>{r.data}</td>
                          <td style={{ fontSize: 13 }}>{r.controparte}</td>
                          <td className="num">{fmt(r.imponibile, { decimals: 2 })}</td>
                          <td className="num muted">{r.iva === 0 ? "—" : r.iva + "%"}</td>
                          {tipoRil === "passiva" && (
                            <td>
                              <div className="row" style={{ gap: 4, flexWrap: "nowrap" }}>
                                <select
                                  className="select"
                                  style={{ fontSize: 12, padding: "3px 6px", width: "auto", border: r.categoriaIncerta ? "1px solid var(--coral)" : undefined }}
                                  value={r.categoria || ""}
                                  onChange={e => updateRigaCategoria(i, e.target.value)}
                                >
                                  <option value="">— nessuna —</option>
                                  {CATEGORIE_PASSIVE.map(c => <option key={c}>{c}</option>)}
                                </select>
                                {r.categoriaIncerta && <span title="Categoria non riconosciuta automaticamente: verificala">⚠️</span>}
                              </div>
                            </td>
                          )}
                        </tr>
                      ))}
                      {rows.length > 50 && <tr><td colSpan={tipoRil === "passiva" ? 5 : 4} className="muted" style={{ textAlign: "center", fontSize: 12 }}>… e altre {rows.length - 50}</td></tr>}
                    </tbody>
                  </table>
                </div>
              </>
            )}

            <div className="row" style={{ justifyContent: "flex-end", gap: 8 }}>
              <button type="button" onClick={onClose} style={{ padding: "9px 14px", borderRadius: 8, border: "1px solid var(--border)", background: "none", cursor: "pointer" }}>Annulla</button>
              <button type="button" className="login-btn" style={{ flex: "0 0 auto", width: "auto", padding: "9px 16px" }} onClick={doImport} disabled={busy || rows.length === 0}>
                {busy ? "Importo…" : `Importa ${rows.length || ""}`}
              </button>
            </div>
          </>
        )}
      </div>
    </div>
  );
}

window.AntaresScreens1 = { Cruscotto, Fatture, Collaboratori, Cespiti, Icon };
