// ============================================================
// Reports.jsx
// ============================================================
function Reports() {
  const { seed, pushToast, user } = useStore();
  const { KPI, PROJECTS = [] } = seed;

  // Sessione 80 / C1 — Pivot reports server-side.
  const [reportsList, setReportsList] = React.useState([]);
  const [selectedReport, setSelectedReport] = React.useState(null);
  const [pivotResult, setPivotResult] = React.useState(null);
  const [pivotLoading, setPivotLoading] = React.useState(false);
  const [shareModal, setShareModal] = React.useState(null); // {reportId} | null
  const [shareTokens, setShareTokens] = React.useState([]);
  const [newTokenLabel, setNewTokenLabel] = React.useState('');
  const [newTokenPlaintext, setNewTokenPlaintext] = React.useState(null);

  // Bootstrap: fetch reports list.
  React.useEffect(() => {
    let cancelled = false;
    (async () => {
      try {
        const r = await fetch('/api/reports', { headers: { 'X-Actor-Persona-Id': user?.id || '' } });
        if (!r.ok) return;
        const j = await r.json();
        if (cancelled) return;
        const list = j.data || j || [];
        setReportsList(Array.isArray(list) ? list : []);
        // Auto-select primo report con config pivot
        const auto = (Array.isArray(list) ? list : []).find(x => x.config);
        if (auto && !selectedReport) setSelectedReport(auto.id);
      } catch {}
    })();
    return () => { cancelled = true; };
  }, [user?.id]);

  // Fetch pivot quando cambia selectedReport.
  React.useEffect(() => {
    if (!selectedReport) { setPivotResult(null); return; }
    let cancelled = false;
    setPivotLoading(true);
    (async () => {
      try {
        const r = await fetch(`/api/reports/${encodeURIComponent(selectedReport)}/pivot`, {
          method: 'POST',
          headers: { 'Content-Type': 'application/json', 'X-Actor-Persona-Id': user?.id || '' },
          body: JSON.stringify({}),
        });
        if (!r.ok) { if (!cancelled) setPivotResult(null); return; }
        const j = await r.json();
        if (cancelled) return;
        setPivotResult(j.data || null);
      } finally { if (!cancelled) setPivotLoading(false); }
    })();
    return () => { cancelled = true; };
  }, [selectedReport, user?.id]);

  // Download XLSX/PPTX.
  const downloadExport = async (format) => {
    if (!selectedReport) return;
    try {
      const url = `/api/reports/${encodeURIComponent(selectedReport)}/export?format=${format}`;
      const a = document.createElement('a');
      a.href = url + `&actor=${encodeURIComponent(user?.id || '')}`; // hint per dev tools
      // Per inviare header X-Actor-Persona-Id su un link <a> serve fetch+blob.
      const resp = await fetch(url, { headers: { 'X-Actor-Persona-Id': user?.id || '' } });
      if (!resp.ok) {
        pushToast({ title: `Export ${format.toUpperCase()} fallito`, desc: `HTTP ${resp.status}`, tone: 'err' });
        return;
      }
      const blob = await resp.blob();
      const dlUrl = URL.createObjectURL(blob);
      const link = document.createElement('a');
      link.href = dlUrl;
      const sel = reportsList.find(r => r.id === selectedReport);
      link.download = `${(sel?.name || 'report').replace(/[^a-zA-Z0-9._-]+/g, '_')}_${new Date().toISOString().slice(0,10)}.${format}`;
      document.body.appendChild(link);
      link.click();
      document.body.removeChild(link);
      URL.revokeObjectURL(dlUrl);
      pushToast({ title: `Export ${format.toUpperCase()} pronto`, desc: link.download, tone: 'ok' });
    } catch (err) {
      pushToast({ title: 'Errore di rete', desc: err?.message || 'Export fallito', tone: 'err' });
    }
  };

  // Apri share modal + fetch tokens list.
  const openShareModal = async () => {
    if (!selectedReport) return;
    setShareModal({ reportId: selectedReport });
    setNewTokenPlaintext(null);
    try {
      const r = await fetch(`/api/reports/${encodeURIComponent(selectedReport)}/share-tokens`, {
        headers: { 'X-Actor-Persona-Id': user?.id || '' },
      });
      const j = await r.json();
      setShareTokens(j.data || []);
    } catch { setShareTokens([]); }
  };

  const createShareToken = async () => {
    if (!shareModal?.reportId) return;
    try {
      const r = await fetch(`/api/reports/${encodeURIComponent(shareModal.reportId)}/share-tokens`, {
        method: 'POST',
        headers: { 'Content-Type': 'application/json', 'X-Actor-Persona-Id': user?.id || '' },
        body: JSON.stringify({
          label: newTokenLabel || 'Share senza etichetta',
          allowedFormats: ['view', 'xlsx', 'pptx'],
          expiresInDays: 7,
        }),
      });
      const j = await r.json();
      if (!r.ok) {
        pushToast({ title: 'Token non creato', desc: j?.error || `HTTP ${r.status}`, tone: 'err' });
        return;
      }
      setNewTokenPlaintext(j.data.plaintext);
      setNewTokenLabel('');
      // Refresh list
      const list = await fetch(`/api/reports/${encodeURIComponent(shareModal.reportId)}/share-tokens`, {
        headers: { 'X-Actor-Persona-Id': user?.id || '' },
      });
      const listJ = await list.json();
      setShareTokens(listJ.data || []);
      pushToast({ title: 'Token creato', desc: 'Copialo ora — visibile UNA volta.', tone: 'ok' });
    } catch (err) {
      pushToast({ title: 'Errore di rete', desc: err?.message || 'Create token fallito', tone: 'err' });
    }
  };

  const revokeToken = async (tokenId) => {
    if (!shareModal?.reportId) return;
    try {
      const r = await fetch(`/api/reports/${encodeURIComponent(shareModal.reportId)}/share-tokens/${encodeURIComponent(tokenId)}`, {
        method: 'DELETE',
        headers: { 'X-Actor-Persona-Id': user?.id || '' },
      });
      if (!r.ok) {
        pushToast({ title: 'Revoca fallita', desc: `HTTP ${r.status}`, tone: 'err' });
        return;
      }
      // Refresh list
      const list = await fetch(`/api/reports/${encodeURIComponent(shareModal.reportId)}/share-tokens`, {
        headers: { 'X-Actor-Persona-Id': user?.id || '' },
      });
      const listJ = await list.json();
      setShareTokens(listJ.data || []);
      pushToast({ title: 'Token revocato', desc: tokenId, tone: 'ok' });
    } catch (err) {
      pushToast({ title: 'Errore di rete', desc: err?.message || 'Revoke fallito', tone: 'err' });
    }
  };
  const portfolio = KPI?.portfolio || {};

  // MVP gap #3: KPI live calcolati da KPI.portfolio + aggregazione PROJECTS.
  const capexTotal = portfolio.capexTotal || 0;
  const committed = portfolio.committed || 0;
  const spent = portfolio.spent || 0;
  const aiTimeSaved = portfolio.aiTimeSaved || 0;
  const savingsYTD = portfolio.savingsYTD || 0;
  const commitmentRate = capexTotal > 0 ? (committed / capexTotal) * 100 : 0;
  // Cost variance = scostamento spent vs commitment proporzionale al progresso medio
  const avgProgress = PROJECTS.length > 0
    ? PROJECTS.reduce((a, p) => a + (p.progress || 0), 0) / PROJECTS.length / 100
    : 0;
  const expectedSpentAtProgress = committed * avgProgress;
  const costVariance = expectedSpentAtProgress > 0
    ? ((spent - expectedSpentAtProgress) / expectedSpentAtProgress) * 100
    : 0;
  // Sessione 69 — rimosso 'pilot' (cleanup pilot/simulated):
  // ROI AI ora calcolato su `aiPlatformCost` annuale invece di pilotCost.
  const aiHourlyRate = 85; // €/h, configurabile in futuro
  const aiValueEquivalent = aiTimeSaved * aiHourlyRate;
  const totalAiBenefit = aiValueEquivalent + savingsYTD;
  const aiPlatformCost = portfolio.aiPlatformCost || portfolio.pilotCost || 180000;
  const roi = aiPlatformCost > 0 ? totalAiBenefit / aiPlatformCost : 0;

  // Aggregazione CAPEX per categoria, dai PROJECTS
  const byCategory = React.useMemo(() => {
    const acc = new Map();
    for (const p of PROJECTS) {
      const cat = p.category || p.categoryRef || 'Non categorizzato';
      const cur = acc.get(cat) || { capex: 0, count: 0 };
      cur.capex += p.budget || 0;
      cur.count += 1;
      acc.set(cat, cur);
    }
    const total = [...acc.values()].reduce((a, c) => a + c.capex, 0);
    return [...acc.entries()]
      .map(([cat, v]) => ({ cat, capex: v.capex, count: v.count, pct: total > 0 ? (v.capex / total) * 100 : 0 }))
      .sort((a, b) => b.capex - a.capex);
  }, [PROJECTS]);

  return (
    <div className="page fade-in">
      <div className="page-header">
        <div>
          <div className="eyebrow">Finance & governance</div>
          <h1 className="page-title">Report & analytics</h1>
          <div className="page-sub">Cruscotto di sintesi per CFO, Controlling e Direzione. Tutti i numeri derivano dalle stesse fonti operative dei progetti.</div>
        </div>
        <div className="actions">
          <Btn variant="ghost" size="sm" onClick={() => downloadExport('xlsx')} disabled={!selectedReport} data-testid="reports-export-xlsx">
            <Icon name="download" size={12}/> Export XLSX
          </Btn>
          <Btn variant="ghost" size="sm" onClick={() => downloadExport('pptx')} disabled={!selectedReport} data-testid="reports-export-pptx">
            <Icon name="download" size={12}/> Export PPTX
          </Btn>
          <Btn variant="primary" size="sm" onClick={openShareModal} disabled={!selectedReport} data-testid="reports-share-btn">
            <Icon name="link" size={12}/> Condividi link
          </Btn>
        </div>
      </div>

      {/* Selector report pivot server-side */}
      <div className="card" style={{ marginBottom: 14 }}>
        <div className="card-body" style={{ display: 'flex', gap: 12, alignItems: 'center' }}>
          <div className="eyebrow" style={{ marginBottom: 0 }}>Report pivot server-side</div>
          <select
            value={selectedReport || ''}
            onChange={(e) => setSelectedReport(e.target.value || null)}
            style={{ padding: '6px 8px', fontSize: 12, background: 'var(--bg-2)', border: '1px solid var(--line)', borderRadius: 6, color: 'var(--text)' }}
            data-testid="reports-selector"
          >
            <option value="">— Seleziona un report —</option>
            {reportsList.filter(r => r.config).map((r) => (
              <option key={r.id} value={r.id}>{r.name}</option>
            ))}
          </select>
          {pivotLoading && <span style={{ fontSize: 11, color: 'var(--text-3)' }}>caricamento pivot…</span>}
          {pivotResult && (
            <span style={{ fontSize: 11, color: 'var(--text-3)' }} data-testid="reports-pivot-stats">
              dataset <b>{pivotResult.config.dataset}</b> · {pivotResult.pivot.recordsTotal} record · {pivotResult.pivot.rowsOut} righe · {pivotResult.pivot.stats.measuresComputed} misure
            </span>
          )}
        </div>
      </div>

      {/* Tabella pivot live */}
      {pivotResult && (
        <div className="card" style={{ marginBottom: 14 }}>
          <div className="card-header">
            <div className="title">
              {pivotResult.report?.name || 'Report'} — pivot live
            </div>
          </div>
          <div className="card-body" style={{ overflowX: 'auto' }}>
            <table className="tbl" data-testid="reports-pivot-table">
              <thead>
                <tr>
                  {pivotResult.config.dimensions.map((d) => <th key={d}>{d}</th>)}
                  {pivotResult.config.measures.map((m) => <th key={m.id} className="num">{m.label || m.id}</th>)}
                </tr>
              </thead>
              <tbody>
                {pivotResult.pivot.rows.length === 0 ? (
                  <tr><td colSpan={pivotResult.config.dimensions.length + pivotResult.config.measures.length} style={{ textAlign: 'center', color: 'var(--text-3)', fontSize: 11 }}>Nessun dato</td></tr>
                ) : pivotResult.pivot.rows.map((row, i) => (
                  <tr key={i}>
                    {pivotResult.config.dimensions.map((d) => (
                      <td key={d}>{row.dims[d] == null ? <span style={{color:'var(--text-3)'}}>∅</span> : String(row.dims[d])}</td>
                    ))}
                    {pivotResult.config.measures.map((m) => (
                      <td key={m.id} className="num mono">{Number.isFinite(row.measures[m.id]) ? row.measures[m.id].toLocaleString('it-IT', { maximumFractionDigits: 2 }) : '—'}</td>
                    ))}
                  </tr>
                ))}
                {pivotResult.pivot.rowsOut > 0 && (
                  <tr style={{ fontWeight: 600, borderTop: '2px solid var(--line)' }}>
                    {pivotResult.config.dimensions.map((d, i) => <td key={d}>{i === 0 ? 'TOTALE' : ''}</td>)}
                    {pivotResult.config.measures.map((m) => (
                      <td key={m.id} className="num mono">{Number.isFinite(pivotResult.pivot.totals[m.id]) ? pivotResult.pivot.totals[m.id].toLocaleString('it-IT', { maximumFractionDigits: 2 }) : '—'}</td>
                    ))}
                  </tr>
                )}
              </tbody>
            </table>
          </div>
        </div>
      )}

      {/* Share modal */}
      {shareModal && (
        <Modal open={!!shareModal} onClose={() => setShareModal(null)} title="Condividi report via link" size="md" footer={
          <>
            <Btn variant="ghost" size="sm" onClick={() => setShareModal(null)}>Chiudi</Btn>
          </>
        }>
          <div className="col" style={{ gap: 12 }}>
            <div style={{ fontSize: 11.5, color: 'var(--text-2)' }}>
              Crea un link condivisibile (anonimo) per il report <b>{shareModal.reportId}</b>. Il token plaintext è visibile UNA volta.
              Default: scadenza 7 giorni · formati view+xlsx+pptx.
            </div>
            <div className="row" style={{ gap: 8 }}>
              <input
                value={newTokenLabel}
                onChange={(e) => setNewTokenLabel(e.target.value)}
                placeholder="Etichetta (es. CFO board, Newsletter Q2)"
                style={{ flex: 1, padding: '6px 8px', fontSize: 12, background: 'var(--bg-2)', border: '1px solid var(--line)', borderRadius: 6, color: 'var(--text)' }}
              />
              <Btn variant="primary" size="sm" onClick={createShareToken} data-testid="reports-share-create">
                <Icon name="plus" size={11}/> Crea token
              </Btn>
            </div>
            {newTokenPlaintext && (
              <div style={{ padding: 12, background: 'var(--ok-bg, #1f3a2a)', border: '1px solid var(--ok)', borderRadius: 8, fontFamily: 'var(--font-mono)', fontSize: 11.5, wordBreak: 'break-all' }} data-testid="reports-token-plaintext">
                <div style={{ marginBottom: 6, fontWeight: 600, color: 'var(--ok)' }}>📋 Copia ORA — non sarà più mostrato:</div>
                <div style={{ background: 'var(--bg)', padding: 8, borderRadius: 4 }}>{`${window.location.origin}/api/share/${newTokenPlaintext}/report`}</div>
              </div>
            )}
            <div>
              <div className="eyebrow" style={{ marginBottom: 6 }}>Token attivi ({shareTokens.length})</div>
              {shareTokens.length === 0 ? (
                <div style={{ fontSize: 11.5, color: 'var(--text-3)' }}>Nessun token. Creane uno sopra.</div>
              ) : shareTokens.map(t => (
                <div key={t.id} className="row" style={{ gap: 8, padding: '8px 0', borderBottom: '1px dashed var(--line)' }}>
                  <div style={{ flex: 1 }}>
                    <div style={{ fontSize: 12, fontWeight: 500 }}>{t.label || '(nessuna etichetta)'}</div>
                    <div style={{ fontSize: 10.5, color: 'var(--text-3)', fontFamily: 'var(--font-mono)' }}>
                      {t.tokenHint} · {t.allowedFormats.join('+')} · {t.accessCount} access · {t.revokedAt ? 'REVOCATO' : t.expiresAt ? `scade ${new Date(t.expiresAt).toLocaleDateString('it-IT')}` : 'no expiry'}
                    </div>
                  </div>
                  {!t.revokedAt && (
                    <Btn variant="ghost" size="xs" onClick={() => revokeToken(t.id)} data-testid={`reports-token-revoke-${t.id}`}>
                      Revoca
                    </Btn>
                  )}
                </div>
              ))}
            </div>
          </div>
        </Modal>
      )}

      <div className="grid grid-4" style={{marginBottom:14}}>
        <div className="card"><Stat label="CAPEX totale" value={fmtEUR(capexTotal, true)} delta="budget 2026" /></div>
        <div className="card"><Stat label="Commitment rate" value={commitmentRate.toFixed(1) + '%'} delta={`${fmtEUR(committed, true)} su ${fmtEUR(capexTotal, true)}`} tone={commitmentRate >= 70 ? 'up' : ''} /></div>
        <div className="card"><Stat label="Cost variance" value={fmtPct(costVariance, 1)} delta={Math.abs(costVariance) <= 5 ? 'entro target ±5%' : Math.abs(costVariance) <= 10 ? 'fuori target' : '⚠️ critico'} tone={Math.abs(costVariance) <= 5 ? 'up' : 'down'} /></div>
        <div className="card"><Stat label="ROI AI" value={roi.toFixed(1) + '×'} delta={`benefit ${fmtEUR(totalAiBenefit, true)} / cost ${fmtEUR(aiPlatformCost, true)}`} tone={roi >= 2 ? 'up' : roi >= 1 ? '' : 'down'} /></div>
      </div>

      <div className="grid" style={{gridTemplateColumns:'2fr 1fr', gap:14, marginBottom:14}}>
        <div className="card">
          <div className="card-header"><div className="title">Distribuzione CAPEX per categoria ({byCategory.length})</div></div>
          <div className="card-body">
            {byCategory.length === 0 ? (
              <div style={{fontSize:11, color:'var(--text-3)', padding:14, textAlign:'center'}}>Nessun progetto: distribuzione non calcolabile.</div>
            ) : (
              <div style={{display:'grid', gap:10}}>
                {byCategory.map(({ cat, capex, count, pct }) => (
                  <div key={cat}>
                    <div className="row" style={{justifyContent:'space-between', fontSize:11.5, marginBottom:3}}>
                      <span>{cat} <span style={{fontSize:10, color:'var(--text-3)'}}>· {count} progett{count === 1 ? 'o' : 'i'}</span></span>
                      <span className="mono" style={{color:'var(--text-2)'}}>{pct.toFixed(1)}% · {fmtEUR(capex, true)}</span>
                    </div>
                    <div style={{height:6, background:'var(--bg-2)', border:'1px solid var(--line)', borderRadius:3, overflow:'hidden'}}>
                      <div style={{width:pct+'%', height:'100%', background:'var(--accent)'}}/>
                    </div>
                  </div>
                ))}
              </div>
            )}
          </div>
        </div>

        <div className="card">
          <div className="card-header"><div className="title">ROI piattaforma AI</div></div>
          <div className="card-body">
            <div style={{fontSize:36, fontFamily:'var(--font-display)', fontWeight:600, letterSpacing:'-0.02em'}}>{roi.toFixed(1)}×</div>
            <div style={{fontSize:11.5, color:'var(--text-2)'}}>ritorno stimato sulla spesa AI ({fmtEUR(aiPlatformCost, true)})</div>
            <div className="sep"/>
            <div className="row" style={{justifyContent:'space-between', fontSize:11.5, padding:'6px 0', borderBottom:'1px dashed var(--line)'}}><span>Ore uomo risparmiate</span><span className="mono">{aiTimeSaved.toLocaleString('it-IT')} h</span></div>
            <div className="row" style={{justifyContent:'space-between', fontSize:11.5, padding:'6px 0', borderBottom:'1px dashed var(--line)'}}><span>Valore equivalente ({aiHourlyRate}€/h)</span><span className="mono">{fmtEUR(aiValueEquivalent, true)}</span></div>
            <div className="row" style={{justifyContent:'space-between', fontSize:11.5, padding:'6px 0', borderBottom:'1px dashed var(--line)'}}><span>Risparmio diretto YTD</span><span className="mono">{fmtEUR(savingsYTD, true)}</span></div>
            <div className="row" style={{justifyContent:'space-between', fontSize:11.5, padding:'6px 0'}}><span>Beneficio totale</span><span className="mono" style={{fontWeight:600}}>{fmtEUR(totalAiBenefit, true)}</span></div>
          </div>
        </div>
      </div>

      <div className="card">
        <div className="card-header"><div className="title">Cashflow CAPEX — 12 mesi rolling</div></div>
        <div className="card-body">
          <MiniBars data={seed.KPI.cashflow} width={1100} height={140}/>
        </div>
      </div>
    </div>
  );
}
Object.assign(window, { Reports });
