// ============================================================
// pdf.jsx — generatore PDF sintetici + viewer
// Crea PDF reali (application/pdf) a partire dai metadati dei doc del seed.
// Usa pdf-lib via CDN (caricata dinamicamente al primo uso).
// ============================================================

const PDF_LIB_URL = 'https://unpkg.com/pdf-lib@1.17.1/dist/pdf-lib.min.js';
let pdfLibPromise = null;
function loadPdfLib() {
  if (pdfLibPromise) return pdfLibPromise;
  pdfLibPromise = new Promise((resolve, reject) => {
    if (window.PDFLib) return resolve(window.PDFLib);
    const s = document.createElement('script');
    s.src = PDF_LIB_URL;
    s.onload = () => resolve(window.PDFLib);
    s.onerror = () => reject(new Error('pdf-lib load failed'));
    document.head.appendChild(s);
  });
  return pdfLibPromise;
}

// Testi canned per tipologia — strutturati e realistici, non lorem
const PDF_TEMPLATES = {
  offerta: {
    header: 'OFFERTA COMMERCIALE',
    sections: [
      { t: '1. OGGETTO', p: 'La presente offerta ha per oggetto la fornitura, installazione, collaudo e messa in servizio di {TITLE} presso lo stabilimento {SITE}. La fornitura è riferita al progetto CAPEX {PROJECT} di cui alla Vs. RdA.' },
      { t: '2. PERIMETRO TECNICO', p: 'Il perimetro comprende: progettazione esecutiva, fornitura materiali e componentistica, integrazione con i sistemi esistenti (MES/SCADA/PLC), test di accettazione in fabbrica (FAT), trasporto e installazione on-site, test di accettazione (SAT), formazione operatori (16 ore) e documentazione tecnica completa as-built.' },
      { t: '3. QUOTAZIONE ECONOMICA', p: 'Importo totale della fornitura: {AMOUNT}. IVA esclusa. Prezzo fisso ed invariabile, non soggetto a revisione. Validità offerta: 60 giorni dalla data di emissione.' },
      { t: '4. TERMINI DI PAGAMENTO', p: '30% all\'ordine contro fattura anticipata · 40% a conclusione del FAT · 20% a consegna on-site · 10% a completamento SAT e sottoscrizione verbale di collaudo definitivo. Pagamenti a 60 gg data fattura.' },
      { t: '5. TEMPI DI CONSEGNA', p: 'Consegna on-site prevista entro 18 settimane dalla data di ricevimento ordine. SAT entro ulteriori 4 settimane. Penali per ritardo: 0,3% dell\'importo contrattuale per settimana, fino a un massimo del 5%.' },
      { t: '6. GARANZIE', p: 'Garanzia meccanica ed elettrica 24 mesi dalla firma del verbale SAT. Garanzia estesa opzionale 36 mesi: +3,2% sull\'importo di fornitura. Ricambi strategici garantiti per 10 anni.' },
      { t: '7. RIFERIMENTI NORMATIVI', p: 'La fornitura è conforme a: Direttiva Macchine 2006/42/CE · UNI EN ISO 12100 · UNI EN ISO 13849-1 · IEC 62061 · EMC 2014/30/UE · marcatura CE. Per la parte di cybersecurity OT: IEC 62443-3-3 livello SL-2.' },
      { t: '8. ESCLUSIONI', p: 'Sono escluse dalla presente offerta: opere civili, predisposizioni elettriche a monte del quadro di fornitura, allacciamenti aria compressa e acqua, consumabili di produzione, licenze software di terze parti non espressamente indicate.' },
    ],
    footer: 'Documento riservato. Ogni diffusione è vietata senza autorizzazione scritta del mittente.',
  },
  capitolato: {
    header: 'CAPITOLATO TECNICO',
    sections: [
      { t: '1. SCOPO DEL DOCUMENTO', p: 'Il presente capitolato definisce i requisiti tecnici, prestazionali, costruttivi e documentali per {TITLE}, nell\'ambito del progetto CAPEX {PROJECT} presso {SITE}.' },
      { t: '2. REQUISITI PRESTAZIONALI', p: 'Throughput minimo: 250 pezzi/ora. Disponibilità OEE ≥ 87%. MTBF ≥ 2.500 ore. MTTR ≤ 30 minuti. Precisione di posizionamento: ±0,05 mm sull\'intera corsa utile. Rumorosità massima a 1 m: 72 dB(A).' },
      { t: '3. REQUISITI DI INTEGRAZIONE', p: 'Integrazione obbligatoria con: MES aziendale (interfaccia OPC UA), SCADA di stabilimento (protocollo MQTT su TLS), sistema di qualità (export CSV e REST API). Sistema di tracciabilità: salvataggio per ogni pezzo di serial number, timestamp, esito qualità, operatore, parametri di processo.' },
      { t: '4. REQUISITI DI SICUREZZA', p: 'Valutazione PL d secondo UNI EN ISO 13849-1. Barriere ottiche perimetrali, portelli interbloccati con chiave, fungo di emergenza accessibile entro 500 mm da ogni postazione. Documento DVR e Analisi Rischi da fornire in fase di FAT.' },
      { t: '5. DOCUMENTAZIONE RICHIESTA', p: 'Manuale uso e manutenzione (italiano) · schemi elettrici in formato EPLAN · schemi pneumatici · programma PLC commentato con backup · lista ricambi con codici · verbale FAT · dichiarazione CE · fascicolo tecnico.' },
      { t: '6. COLLAUDO E ACCETTAZIONE', p: 'FAT presso lo stabilimento del fornitore con presenza di 2 tecnici Industrial per un massimo di 5 giorni lavorativi. SAT on-site entro 30 giorni dalla consegna, con prove di produzione continua per 72 ore. Accettazione definitiva subordinata al raggiungimento delle KPI prestazionali dichiarate.' },
      { t: '7. FORMAZIONE', p: '24 ore di formazione operatori (produzione e manutenzione) + 8 ore training tecnici di stabilimento sulla manutenzione predittiva. Materiale didattico in lingua italiana.' },
      { t: '8. SERVICE E RICAMBI', p: 'Contratto di manutenzione annuale opzionale (4 visite): 3,8% dell\'importo di fornitura. Tempo di risposta per fermo macchina critico: 4 ore telefoniche, 24 ore on-site. Fondo ricambi strategici: 2% dell\'importo.' },
    ],
    footer: 'Capitolato tecnico — revisione 1.0 — approvato Engineering Industrial',
  },
  specifica: {
    header: 'SPECIFICA TECNICA',
    sections: [
      { t: '1. IDENTIFICAZIONE', p: 'Documento: Specifica tecnica relativa a {TITLE}. Progetto: {PROJECT}. Sito di installazione: {SITE}. Revisione: 1.2.' },
      { t: '2. FUNZIONE', p: 'Il sistema ha la funzione di eseguire ispezione visiva automatica di pezzi in linea, classificarli secondo criteri di qualità definiti, tracciare ogni pezzo nel MES e segnalare in tempo reale anomalie di processo ai sistemi a monte.' },
      { t: '3. DATI DI TARGA', p: 'Alimentazione: 400 V AC trifase + N + PE · 50 Hz · potenza installata 22 kW · aria compressa 6 bar · consumo aria 120 Nl/min · temperatura ambiente 10–40°C · umidità relativa 30–80% non condensante.' },
      { t: '4. ARCHITETTURA', p: 'Il sistema è composto da: 4 telecamere industriali 12 MP con ottiche telecentriche, illuminatori LED a spettro selezionabile, unità di elaborazione GPU edge, PLC Siemens S7-1500, HMI 21" touch, quadro elettrico IP54, gruppo di continuità da 3 kVA.' },
      { t: '5. INTERFACCE', p: 'Rete di stabilimento: Ethernet 1 Gbps su switch industriale gestito. MES: OPC UA (modello informativo PackML esteso). Qualità: REST API con autenticazione OAuth2. Remote service: VPN site-to-site su firewall di stabilimento.' },
      { t: '6. PRESTAZIONI', p: 'Ciclo di ispezione: ≤ 1,8 s/pezzo · accuratezza classificazione ≥ 99,2% su dataset di 10.000 campioni certificati · falsi positivi ≤ 0,5% · falsi negativi ≤ 0,2% · disponibilità operativa ≥ 99,0% su turno a regime.' },
      { t: '7. CONDIZIONI DI RIFIUTO', p: 'Il sistema è rifiutato qualora: accuratezza < 98% al SAT · MTBF < 1.800 ore nel primo anno · mancato rispetto requisiti cybersecurity OT IEC 62443 SL-2 · assenza di documentazione tecnica completa in italiano.' },
      { t: '8. RIFERIMENTI', p: 'UNI EN ISO 12100 · IEC 61508 · IEC 62443-3-3 · Direttiva Macchine 2006/42/CE · Regolamento UE Machinery 2023/1230. Cyber: allineamento a framework NIST CSF 2.0.' },
    ],
    footer: 'Specifica tecnica — rev. 1.2 — Engineering Industrial · Stefano Marchetti',
  },
  SAL: {
    header: 'STATO AVANZAMENTO LAVORI',
    sections: [
      { t: '1. RIFERIMENTI', p: 'SAL n. {SAL_N} relativo al contratto {PROJECT} sottoscritto tra Industrial e il fornitore, avente ad oggetto {TITLE}. Sito di installazione: {SITE}.' },
      { t: '2. PERCENTUALE DI AVANZAMENTO', p: 'Avanzamento complessivo dichiarato dal fornitore: {PROGRESS}%. Avanzamento verificato da Direzione Lavori Industrial: {PROGRESS_V}%. Delta da motivare in sede di riunione di coordinamento.' },
      { t: '3. LAVORAZIONI COMPLETATE NEL PERIODO', p: 'Progettazione esecutiva completata al 100% con approvazione Engineering Industrial. Completata la fornitura di 2 quadri elettrici primari e del 60% del materiale meccanico. Installata la struttura principale del basamento. Eseguiti 3 dei 5 test parziali previsti.' },
      { t: '4. LAVORAZIONI PREVISTE NEL PROSSIMO PERIODO', p: 'Completamento installazione componentistica automazione · cablaggio e messa in tensione quadri · test funzionali sui singoli sottosistemi · preparazione FAT (check-list finale, materiali di consumo, strumentazione di misura).' },
      { t: '5. SCOSTAMENTI E CRITICITÀ', p: 'Ritardo di 2 settimane sulla fornitura di 1 componente (gruppo motore) imputabile a fornitura di terzo livello. Il fornitore ha attivato un canale alternativo con consegna confermata per il prossimo SAL. Non si registrano scostamenti economici al momento.' },
      { t: '6. CONTABILIZZAZIONE ECONOMICA', p: 'Importo contabilizzato a SAL: {AMOUNT}. Trattenuta di garanzia 5% = {GUARANTEE}. Importo netto proposto in liquidazione: {NET}. Documentazione di supporto: rapporti di ispezione, DDT, verbali di prova, foto di cantiere (archiviate sistema documentale).' },
      { t: '7. NOTE DI CANTIERE', p: 'Registrate 2 non-conformità minori (NCR-014, NCR-015) entrambe chiuse nel periodo. Nessun near-miss o incidente sulla sicurezza. HSE compliance confermata da audit interno del 12/03.' },
    ],
    footer: 'Direzione Lavori: Ing. Stefano Marchetti — Industrial Engineering',
  },
  verbale: {
    header: 'VERBALE DI RIUNIONE',
    sections: [
      { t: 'DATI GENERALI', p: 'Riunione: {TITLE}. Progetto di riferimento: {PROJECT}. Luogo: {SITE} · Durata: 90 min · Redattore: Marco Ferretti (PM CAPEX).' },
      { t: 'PARTECIPANTI', p: 'Marco Ferretti (PM CAPEX) · Elena Conti (Procurement) · Stefano Marchetti (Engineering Lead) · Chiara Battaglia (Plant Manager) · Alessandro De Luca (Vendor) · Davide Russo (Controlling).' },
      { t: 'ORDINE DEL GIORNO', p: '1) Verifica avanzamento lavori rispetto a cronoprogramma · 2) Analisi scostamenti e piano di rientro · 3) Aggiornamento forecast economico · 4) Valutazione rischi aperti · 5) Varie ed eventuali.' },
      { t: 'DISCUSSIONE E DECISIONI', p: 'Il PM ha presentato un avanzamento fisico leggermente inferiore alle previsioni (−4%) dovuto a un ritardo di fornitura di 1 componente critico. È stato concordato un piano di rientro a costo zero attraverso riorganizzazione delle lavorazioni parallele. Il Controlling ha confermato che non sono necessari interventi sul budget. Engineering ha approvato la modifica di layout proposta dal vendor per ottimizzare tempi di montaggio.' },
      { t: 'ACTION ITEM', p: '• AI-01 — Vendor: confermare per iscritto data recupero componente (entro 26/04 · owner: De Luca) · AI-02 — PM: aggiornare Gantt e distribuire nuovo baseline (entro 28/04 · owner: Ferretti) · AI-03 — Procurement: avviare attivazione piano B vendor alternativo (entro 30/04 · owner: Conti) · AI-04 — Engineering: validare disegni modifica layout (entro 25/04 · owner: Marchetti).' },
      { t: 'RISCHI APERTI', p: 'R-01 — Ritardo fornitura componente: probabilità media, impatto alto, mitigazione in corso. R-03 — Disponibilità area di cantiere: bassa, impatto medio, monitoraggio bisettimanale. R-07 — Rischio cambio cambio USD: monitorato da Treasury, coperto al 60%.' },
      { t: 'PROSSIMO INCONTRO', p: 'Prossima riunione di coordinamento: tra 14 giorni, stesso luogo. Agenda preliminare: verifica chiusura action item, update forecast economico, preparazione FAT.' },
    ],
    footer: 'Verbale approvato dai partecipanti · Industrial Program Management',
  },
  contratto: {
    header: 'CONTRATTO DI FORNITURA',
    sections: [
      { t: 'TRA', p: 'INDUSTRIAL DEMO S.p.A. (in seguito "Committente"), con sede in Via dell\'Industria 14, Cameri (NO), C.F. e P.IVA 01234567890, in persona del legale rappresentante pro-tempore' },
      { t: 'E', p: 'Il Fornitore in persona del legale rappresentante pro-tempore, come identificato nell\'atto di conferimento d\'ordine e accettato dalle parti.' },
      { t: 'PREMESSO', p: 'Che il Committente intende realizzare presso lo stabilimento di {SITE} l\'intervento CAPEX denominato {TITLE} ({PROJECT}); che il Fornitore, in esito a procedura di selezione tra più concorrenti, è risultato aggiudicatario con l\'offerta citata in premessa; le Parti sottoscrivono il presente contratto alle condizioni che seguono.' },
      { t: 'ART. 1 — OGGETTO', p: 'Il Fornitore si obbliga a consegnare, installare, collaudare e mettere in servizio la fornitura descritta in offerta, nel pieno rispetto delle specifiche tecniche e del capitolato parte integrante del presente contratto.' },
      { t: 'ART. 2 — CORRISPETTIVO', p: 'Il corrispettivo pattuito è pari a {AMOUNT} al netto di IVA. Il prezzo è fisso ed invariabile e non sarà soggetto a revisione di sorta, salvo diverso accordo scritto tra le Parti.' },
      { t: 'ART. 3 — TEMPI', p: 'La consegna deve avvenire entro la data indicata in offerta. Per ogni settimana di ritardo il Fornitore riconoscerà al Committente una penale pari allo 0,3% del corrispettivo, fino al tetto massimo del 5%. Superato tale tetto, il Committente si riserva il diritto di risoluzione del contratto.' },
      { t: 'ART. 4 — GARANZIE', p: 'Garanzia meccanica ed elettrica 24 mesi decorrenti dalla sottoscrizione del verbale di accettazione finale (SAT). Ricambi strategici garantiti per 10 anni. Fideiussione bancaria a prima richiesta pari al 10% del valore contrattuale.' },
      { t: 'ART. 5 — LEGGE APPLICABILE E FORO COMPETENTE', p: 'Il presente contratto è regolato dalla legge italiana. Ogni controversia è devoluta alla competenza esclusiva del Foro di Milano.' },
    ],
    footer: 'Sottoscritto digitalmente ai sensi del D.Lgs. 82/2005',
  },
  rda: {
    header: 'RICHIESTA DI ACQUISTO',
    sections: [
      { t: 'DATI GENERALI', p: 'RdA: {RDA_ID} · Progetto CAPEX: {PROJECT} · Centro di costo: {CDC} · Richiedente: {REQ} · Data: {DATE} · Priorità: {PRIORITY}.' },
      { t: 'OGGETTO', p: '{TITLE}. Sito di destinazione: {SITE}. Tipologia investimento: sostituzione / potenziamento / nuovo impianto. Budget CAPEX già stanziato e autorizzato al livello di portfolio.' },
      { t: 'GIUSTIFICAZIONE DEL BISOGNO', p: 'La presente richiesta è motivata dalla necessità di raggiungere gli obiettivi del programma industriale 2026-2028, in coerenza con il piano di sviluppo approvato dal CdA. La soluzione proposta è stata selezionata tra le alternative disponibili sulla base di costo totale di possesso, time-to-value, riduzione dei fermi produttivi attesi e compatibilità con gli standard tecnici Industrial.' },
      { t: 'IMPORTO ATTESO', p: 'Importo stimato: {AMOUNT} (al netto di IVA). La stima è basata su benchmark interno di progetti comparabili degli ultimi 5 anni e su quotazione di massima raccolta informalmente presso 2 vendor qualificati.' },
      { t: 'VENDOR PROPOSTI', p: 'Vendor suggeriti per l\'invio della RfQ: {VENDORS}. Tutti i vendor proposti sono presenti in Albo Fornitori qualificati Industrial con rating minimo 4.0/5 e assenza di criticità HSE negli ultimi 24 mesi.' },
      { t: 'TEMPISTICHE', p: 'Data obiettivo di ordine: entro 45 giorni dall\'approvazione della presente RdA. Data obiettivo di consegna: in linea con la milestone "pronto-opera" del progetto {PROJECT}.' },
      { t: 'CHECKLIST DOCUMENTALE', p: 'Allegati richiesti: specifica tecnica · capitolato (se applicabile) · scheda di valutazione rischi HSE · valutazione di impatto cybersecurity OT · CdA / delibera di investimento · evidenza di budget · eventuali autorizzazioni ambientali.' },
      { t: 'APPROVAZIONI', p: 'Flow di approvazione: Engineering Lead · Procurement · Controlling · Plant Manager · CFO (se importo ≥ 500k€). Ogni livello ha 3 giorni lavorativi per fornire un parere esplicito motivato.' },
    ],
    footer: 'Documento generato dal Workflow CAPEX Industrial · Traccia audit disponibile',
  },
  layout: {
    header: 'LAYOUT DI INSTALLAZIONE',
    sections: [
      { t: '1. RIFERIMENTI', p: 'Layout relativo a {TITLE} · progetto {PROJECT} · stabilimento {SITE}. Revisione corrente: rev. 4.' },
      { t: '2. AREA INTERESSATA', p: 'Superficie totale area di installazione: 820 m². Altezza utile sotto trave: 8,5 m. Portata pavimento: 2.500 kg/m². Zona classificata: nessuna. Accessibilità mezzi: porta sezionale 4×4 m lato nord.' },
      { t: '3. POSIZIONAMENTO MACCHINARI', p: 'Macchina principale posizionata al centro dell\'area, asse lungo parallelo al flusso di produzione. Quadri elettrici su parete ovest a distanza ≥ 1,2 m dalla macchina. Area di manutenzione tecnica su lato est, 2 m × 8 m. Corridoi di passaggio: 1,5 m.' },
      { t: '4. COLLEGAMENTI IMPIANTISTICI', p: 'Alimentazione elettrica da quadro QE-14 (potenza disponibile 40 kW, predisposizione completata). Aria compressa derivata da rete principale (6 bar). Rete dati in fibra dal centro stella CS-03 (già cablato, test OTDR in corso). Scarico condense collegato a rete di stabilimento.' },
      { t: '5. NORMATIVE E VINCOLI', p: 'Distanza minima da uscite di emergenza: 3 m · rispetto del piano di evacuazione · illuminazione di sicurezza già presente · nessun vincolo antincendio specifico. Verifica sismica zona 3 completata per la struttura di fissaggio.' },
      { t: '6. ELENCO MODIFICHE', p: 'Modifiche introdotte rispetto alla rev. 3: spostamento di 1,2 m dell\'area manutenzione per liberare accesso a quadro QE-14; integrazione di una postazione ergonomica operatore con schermo HMI orientabile.' },
    ],
    footer: 'Layout · rev. 4 · approvato Engineering e Plant Manager',
  },
  checklist: {
    header: 'CHECK-LIST TECNICA',
    sections: [
      { t: 'IDENTIFICAZIONE', p: 'Check-list {TITLE} · progetto {PROJECT} · sito {SITE}. Compilata da: Engineering Industrial · validata da: Plant Manager.' },
      { t: 'DOCUMENTAZIONE', p: '[✓] Manuale uso e manutenzione (IT) · [✓] Schemi elettrici EPLAN · [✓] Schema pneumatico · [✓] Lista ricambi strategici · [·] Manuale di configurazione software (in review) · [✓] Dichiarazione CE · [✓] Fascicolo tecnico.' },
      { t: 'SICUREZZA', p: '[✓] Analisi rischi secondo ISO 12100 · [✓] Valutazione PL secondo ISO 13849-1 · [✓] Verifica barriere ottiche e interblocchi · [✓] Test fungo di emergenza da tutte le postazioni · [✓] Verifica LOTO · [✓] DVR aggiornato · [·] Formazione operatori (pianificata per la settimana successiva).' },
      { t: 'FUNZIONALITÀ', p: '[✓] Boot di sistema e diagnostica iniziale OK · [✓] Comunicazione OPC UA verso MES verificata · [✓] Comunicazione PLC verso SCADA verificata · [·] Test carico produzione 72h (in corso) · [·] Verifica KPI prestazionali a regime (in corso) · [✓] Backup PLC e immagini HMI archiviati.' },
      { t: 'CYBERSECURITY OT', p: '[✓] Segmentazione di rete verificata (VLAN dedicata) · [✓] Firewall regole allineate a policy Industrial · [✓] Utenti locali disabilitati, accesso solo via AD centralizzato · [✓] Log forwarded al SIEM di stabilimento · [·] Patch management plan firmato dal vendor (in review).' },
      { t: 'ESITO', p: 'Non conformità rilevate: 0 critiche · 2 minori (chiusura prevista entro 7 giorni) · 1 osservazione migliorativa. Conclusione: pronto per avvio test carico produzione di 72 ore, preventivo al rilascio in esercizio definitivo.' },
    ],
    footer: 'Check-list approvata · Industrial Engineering & Operations',
  },
};

// Fallback per tipi non coperti
function templateFor(type) {
  const key = (type || '').toLowerCase();
  if (PDF_TEMPLATES[type]) return PDF_TEMPLATES[type];
  if (PDF_TEMPLATES[key]) return PDF_TEMPLATES[key];
  // map comuni
  if (/offerta/i.test(type)) return PDF_TEMPLATES.offerta;
  if (/capitolato/i.test(type)) return PDF_TEMPLATES.capitolato;
  if (/specifica/i.test(type)) return PDF_TEMPLATES.specifica;
  if (/verbale|minuta|meeting/i.test(type)) return PDF_TEMPLATES.verbale;
  if (/sal/i.test(type)) return PDF_TEMPLATES.SAL;
  if (/contratt/i.test(type)) return PDF_TEMPLATES.contratto;
  if (/rda/i.test(type)) return PDF_TEMPLATES.rda;
  if (/layout/i.test(type)) return PDF_TEMPLATES.layout;
  if (/checklist/i.test(type)) return PDF_TEMPLATES.checklist;
  return PDF_TEMPLATES.specifica;
}

// Risolve placeholder {TOKEN} con dati documento
function fillTokens(text, ctx) {
  const map = {
    TITLE: ctx.title || '—',
    PROJECT: ctx.project || '—',
    SITE: ctx.site || 'Cameri (NO)',
    AMOUNT: ctx.amount || '—',
    SAL_N: ctx.salN || '04',
    PROGRESS: ctx.progress || '62',
    PROGRESS_V: ctx.progressV || '58',
    GUARANTEE: ctx.guarantee || '—',
    NET: ctx.net || '—',
    RDA_ID: ctx.rdaId || 'RdA-2026-000',
    CDC: ctx.cdc || 'CC-CPX-2026',
    REQ: ctx.req || 'Marco Ferretti',
    DATE: ctx.date || new Date().toISOString().slice(0,10),
    PRIORITY: ctx.priority || 'Alta',
    VENDORS: ctx.vendors || 'Siemens Italia, ABB Italia',
  };
  return text.replace(/\{(\w+)\}/g, (_, k) => map[k] ?? ('{' + k + '}'));
}

// Entry point: generateDocPdf(doc) → Blob (application/pdf)
async function generateDocPdf(doc) {
  const PDFLib = await loadPdfLib();
  const { PDFDocument, StandardFonts, rgb } = PDFLib;

  const pdf = await PDFDocument.create();
  pdf.setTitle(doc.title || 'Documento');
  pdf.setAuthor('Veridanto · CAPEX Platform — by Leaven Consulting');
  pdf.setProducer('Veridanto Agentic AI CAPEX (Leaven Consulting)');
  pdf.setCreator('Veridanto CAPEX Platform');
  pdf.setCreationDate(new Date());

  const font = await pdf.embedFont(StandardFonts.Helvetica);
  const bold = await pdf.embedFont(StandardFonts.HelveticaBold);
  const oblique = await pdf.embedFont(StandardFonts.HelveticaOblique);

  const tpl = templateFor(doc.type);
  const ctx = {
    title: doc.title,
    project: doc.project,
    site: doc.site,
    amount: doc.amount,
    vendor: doc.vendor,
    rdaId: doc.id,
    ...doc._ctx,
  };

  // stile
  const W = 595.28, H = 841.89;            // A4
  const M = 56;                            // margine
  const INK = rgb(0.08, 0.10, 0.14);
  const MUTED = rgb(0.42, 0.45, 0.52);
  const LINE = rgb(0.82, 0.82, 0.80);
  const ACCENT = rgb(0.70, 0.21, 0.12);    // mattone
  const BRASS = rgb(0.54, 0.42, 0.18);

  let page = pdf.addPage([W, H]);
  let y = H - M;
  let pageNo = 1;

  // ---- helpers -------------------------------------------------
  function drawBrand(pageRef, pn) {
    // Header band
    pageRef.drawRectangle({ x: 0, y: H - 48, width: W, height: 48, color: rgb(0.97, 0.96, 0.93) });
    // mark
    pageRef.drawRectangle({ x: M, y: H - 36, width: 22, height: 22, color: ACCENT });
    pageRef.drawText('AI', { x: M + 5.5, y: H - 30, size: 9, font: bold, color: rgb(1,1,1) });
    pageRef.drawText('LEAVEN GROUP SERVICES', { x: M + 30, y: H - 22, size: 8, font: bold, color: INK });
    pageRef.drawText('CAPEX · Agentic AI Platform', { x: M + 30, y: H - 32, size: 7, font, color: MUTED });
    pageRef.drawText(tpl.header, { x: W - M - 150, y: H - 26, size: 9, font: bold, color: ACCENT });
    pageRef.drawText('Rif. ' + (doc.project || doc.id || '—'), { x: W - M - 150, y: H - 38, size: 7, font, color: MUTED });
    // footer
    pageRef.drawLine({ start: { x: M, y: 48 }, end: { x: W - M, y: 48 }, thickness: 0.5, color: LINE });
    pageRef.drawText(tpl.footer, { x: M, y: 36, size: 7, font, color: MUTED });
    pageRef.drawText('Pag. ' + pn, { x: W - M - 30, y: 36, size: 7, font, color: MUTED });
    pageRef.drawText('Documento generato · ' + new Date().toLocaleDateString('it-IT'), { x: W - M - 200, y: 22, size: 6.5, font, color: MUTED });
  }

  function newPage() {
    page = pdf.addPage([W, H]);
    pageNo += 1;
    drawBrand(page, pageNo);
    y = H - 72;
  }

  function ensureSpace(h) {
    if (y - h < 70) newPage();
  }

  function wrap(txt, width, f, size) {
    const words = txt.split(/\s+/);
    const lines = [];
    let cur = '';
    for (const w of words) {
      const trial = cur ? cur + ' ' + w : w;
      const wpx = f.widthOfTextAtSize(trial, size);
      if (wpx > width) { if (cur) lines.push(cur); cur = w; }
      else cur = trial;
    }
    if (cur) lines.push(cur);
    return lines;
  }

  // ---- render --------------------------------------------------
  drawBrand(page, pageNo);
  y = H - 72;

  // Title block
  ensureSpace(90);
  const title = doc.title || tpl.header;
  const titleLines = wrap(title, W - 2*M, bold, 20);
  for (const l of titleLines) {
    page.drawText(l, { x: M, y, size: 20, font: bold, color: INK });
    y -= 24;
  }
  y -= 4;

  // Meta row
  const metaLeft = [
    ['Progetto', doc.project || '—'],
    ['Sito', doc.site || '—'],
    ['Tipologia', (doc.type || '—').toString().toUpperCase()],
  ];
  const metaRight = [
    ['Rev.', doc.rev || '1.0'],
    ['Data', (doc.updated || new Date().toISOString().slice(0,10))],
    ['Classif.', doc.classif || 'Riservato'],
  ];
  const metaY = y - 2;
  metaLeft.forEach((m, i) => {
    page.drawText(m[0].toUpperCase(), { x: M + i*140, y: metaY, size: 6.5, font: bold, color: MUTED });
    page.drawText(m[1], { x: M + i*140, y: metaY - 11, size: 10, font, color: INK });
  });
  metaRight.forEach((m, i) => {
    const x = W - M - 3*80 + i*80;
    page.drawText(m[0].toUpperCase(), { x, y: metaY, size: 6.5, font: bold, color: MUTED });
    page.drawText(String(m[1]), { x, y: metaY - 11, size: 10, font, color: INK });
  });
  y = metaY - 28;
  page.drawLine({ start: { x: M, y }, end: { x: W - M, y }, thickness: 0.5, color: LINE });
  y -= 18;

  // Sections
  for (const sec of tpl.sections) {
    ensureSpace(50);
    page.drawText(sec.t, { x: M, y, size: 10.5, font: bold, color: ACCENT });
    y -= 14;
    const p = fillTokens(sec.p, ctx);
    const lines = wrap(p, W - 2*M, font, 10);
    for (const ln of lines) {
      ensureSpace(14);
      page.drawText(ln, { x: M, y, size: 10, font, color: INK });
      y -= 13.6;
    }
    y -= 10;
  }

  // AI footer badge
  ensureSpace(40);
  y -= 6;
  page.drawRectangle({ x: M, y: y - 28, width: W - 2*M, height: 32, color: rgb(0.98, 0.96, 0.90), borderColor: BRASS, borderWidth: 0.5 });
  page.drawText('NOTA AI', { x: M + 10, y: y - 10, size: 7, font: bold, color: BRASS });
  const aiNote = 'Documento di esempio generato dalla piattaforma Veridanto Agentic AI CAPEX. I contenuti sono sintetici e rappresentativi; nel contesto produttivo, ogni sezione è derivata da archivio storico, comunicazioni e requisiti di progetto, sotto supervisione umana.';
  const aiLines = wrap(aiNote, W - 2*M - 20, oblique, 8);
  let yy = y - 20;
  for (const ln of aiLines) {
    page.drawText(ln, { x: M + 10, y: yy, size: 8, font: oblique, color: INK });
    yy -= 10;
  }

  const bytes = await pdf.save();
  return new Blob([bytes], { type: 'application/pdf' });
}

// ---------- Download + cached URL ---------------------------------
const _urlCache = new Map();
async function getDocPdfUrl(doc) {
  const key = (doc.id || doc.title) + '|' + (doc.type || '');
  if (_urlCache.has(key)) return _urlCache.get(key);
  const blob = await generateDocPdf(doc);
  const url = URL.createObjectURL(blob);
  _urlCache.set(key, url);
  return url;
}

async function downloadDocPdf(doc) {
  const url = await getDocPdfUrl(doc);
  const a = document.createElement('a');
  a.href = url;
  a.download = (doc.title || 'documento').replace(/[^\w\-]+/g, '_').slice(0, 80) + '.pdf';
  document.body.appendChild(a);
  a.click();
  a.remove();
}

// ---------- PDFViewer modal --------------------------------------
function PDFViewer({ open, doc, onClose }) {
  const [url, setUrl] = React.useState(null);
  const [err, setErr] = React.useState(null);
  const [loading, setLoading] = React.useState(false);

  React.useEffect(() => {
    if (!open || !doc) { setUrl(null); setErr(null); return; }
    let alive = true;
    setLoading(true); setErr(null);
    getDocPdfUrl(doc).then(u => { if (alive) { setUrl(u); setLoading(false); } })
      .catch(e => { if (alive) { setErr(String(e)); setLoading(false); } });
    return () => { alive = false; };
  }, [open, doc]);

  if (!open || !doc) return null;
  return (
    <div className="modal-backdrop" onClick={onClose}>
      <div className="modal lg" style={{ width: 'min(1080px, 98vw)', height: 'min(88vh, 900px)', display: 'flex', flexDirection: 'column' }} onClick={(e) => e.stopPropagation()}>
        <div className="modal-header">
          <Icon name="file_pdf" size={14} />
          <div className="title">{doc.title}</div>
          <div style={{ flex: 1 }} />
          <Btn size="sm" variant="ghost" onClick={() => downloadDocPdf(doc)}><Icon name="download" size={12}/> Scarica</Btn>
          <button className="btn ghost icon" onClick={onClose}><Icon name="x" /></button>
        </div>
        <div style={{ flex: 1, background: 'var(--bg-0)', position: 'relative', overflow: 'hidden' }}>
          {loading && (
            <div style={{ position: 'absolute', inset: 0, display: 'flex', alignItems: 'center', justifyContent: 'center', color: 'var(--text-2)', fontSize: 12 }}>
              <div className="row" style={{ gap: 8 }}><Icon name="sparkle" size={13}/> Generazione PDF in corso…</div>
            </div>
          )}
          {err && (
            <div style={{ position: 'absolute', inset: 0, display: 'flex', alignItems: 'center', justifyContent: 'center', color: 'var(--err)', fontSize: 12 }}>
              Impossibile generare il PDF. ({err})
            </div>
          )}
          {url && <iframe src={url} style={{ width: '100%', height: '100%', border: 'none', background: 'white' }} title={doc.title} />}
        </div>
      </div>
    </div>
  );
}

Object.assign(window, { generateDocPdf, getDocPdfUrl, downloadDocPdf, PDFViewer });
