/** @type {import("../plugins/filesaver")} */
const FileSaver = globalThis.saveAs;


function cleanFileName(s) {
    return (s || "")
        .toString()
        .trim()
        .toLowerCase()
        .replace(/\s+/g, "_")
        .replace(/[^\w.\-]/g, "");
}
function getExt(file) {
    const n = file?.name || "";
    const i = n.lastIndexOf(".");
    return i >= 0 ? n.slice(i) : ""; // conserva estensione originale
}
// Tronca (NON arrotonda) a 3 cifre decimali e restituisce stringa tipo "49.180"
function tronca3_format(n) {
    const num = Number(n);
    if (isNaN(num)) return n; // se non è numero, restituisce com'è
    return (Math.floor(num * 1000) / 1000).toFixed(3);
}

// Tronca (NON arrotonda) a 2 cifre decimali e restituisce stringa tipo "30000.00"
function tronca2_format(n) {
    const num = Number(n);
    if (isNaN(num)) return n;
    return (Math.floor(num * 100) / 100).toFixed(2);
}

function riempi(codice) {
    var codice_fiscale = codice;
    const cuaa = ($("#cuua").val() || codice_fiscale).toUpperCase();
    var versione = $("#versione").val();
    versione = versione.replace(".", "_");
    const outputPath = `${codice_fiscale}_Verbale_Di_Istruttoria_` + versione + `.xlsx`;
    var righe_tabella = $("#investimenti tbody tr");
    var righe_investimenti = [];

    // Tabella 1
    righe_tabella.each(function () {
        var id = $(this).attr("id");
        if (id.substring(0, 21) == "categoria_interventi_") {
            var descrizione_interventi = $(this).find("td:eq(1) textarea");
            var importo_previsto_imponibile = $(this).find("td:eq(2) input");
            var aliquota_contributo = $(this).find("td:eq(3) input");
            var contributo_richiesto = $(this).find("td:eq(4) input");
            righe_investimenti.push([
                { tab1: [descrizione_interventi.val(), importo_previsto_imponibile.val(), aliquota_contributo.val(), contributo_richiesto.val()] },
            ]);
        }
        if (id == "totale_spdi") {
            var importo_previsto_imponibile_totale = $("#importo_previsto_totale").attr("valore");
            var aliquota_contributo_totale = $("#aliquota_contributo").attr("valore");
            var contributo_richiesto_totale = $("#contributo_richiesto").attr("valore");
            righe_investimenti.push([
                { tab1_tot: [importo_previsto_imponibile_totale, aliquota_contributo_totale, contributo_richiesto_totale] }
            ]);
        }
    });



    // Sezione Anagrafica
    righe_investimenti.push([{ nome: $("#nome").val() }]);
    righe_investimenti.push([{ cognome: $("#cognome").val() }]);
    righe_investimenti.push([{ data_nascita: getFormattedDate($("#data-nascita").val()) }]);
    righe_investimenti.push([{ luogo_nascita: $("#luogo-nascita").val() }]);
    righe_investimenti.push([{ provincia_nascita: $("#provincia-nascita").val() }]);
    righe_investimenti.push([{ cuua: $("#cuua").val() }]);
    righe_investimenti.push([{ residenza: $("#residenza").val() }]);
    righe_investimenti.push([{ provincia: $("#provincia").val() }]);
    righe_investimenti.push([{ indirizzo: $("#indirizzo").val() }]);
    righe_investimenti.push([{ civico: $("#civico").val() }]);
    righe_investimenti.push([{ pec: $("#pec").val() }]);
    righe_investimenti.push([{ email_aziendale: $("#email_aziendale").val() }]);
    righe_investimenti.push([{ telefono: $("#telefono").val() }]);
    righe_investimenti.push([{ qualifica: $("input[name=qualifica]:checked").val() }]);
    righe_investimenti.push([{ denominazione: $("#denominazione").val() }]);
    righe_investimenti.push([{ sede: $("#sede").val() }]);
    righe_investimenti.push([{ sede_indirizzo: $("#sede_indirizzo").val() }]);
    righe_investimenti.push([{ civico_sede: $("#civico_sede").val() }]);
    righe_investimenti.push([{ ccia: $("#ccia-riferimento").val() }]);
    righe_investimenti.push([{ rea: $("#numero-rea").val() }]);
    righe_investimenti.push([{ inps: $("#numero-inps").val() }]);


    // Dati Bancari
    righe_investimenti.push([{ iban: $("#iban").val() }]);
    righe_investimenti.push([{ istituto_credito: $("#istituto-credito").val() }]);
    righe_investimenti.push([{ agenzia_banca: $("#agenzia_banca").val() }]);

    // Localizzazione Investimento
    righe_investimenti.push([{ provincia_localizzazione: $("#provincia-localizzazione").val() }]);
    righe_investimenti.push([{ comune_localizzazione: $("#comune-localizzazione").val() }]);
    righe_investimenti.push([{ foglio: $("#foglio").val() }]);
    righe_investimenti.push([{ particella: $("#particella").val() }]);

    var totale_localizzazioni = $("#numero_localizzazioni_investimenti").val();
    for (let i = 2; i <= totale_localizzazioni; i++) {
        righe_investimenti.push([{ [`provincia_localizzazione_${i}`]: $("#provincia-localizzazione").val() }]);
        righe_investimenti.push([{ [`comune_localizzazione_${i}`]: $("#comune-localizzazione_" + i).val() }]);
        righe_investimenti.push([{ [`foglio_${i}`]: $("#foglio_" + i).val() }]);
        righe_investimenti.push([{ [`particella_${i}`]: $("#particella_" + i).val() }]);
    }

    // Dati riepilogativi intervento
    righe_investimenti.push([{ tempo_investimenti: $("#tempo_realizzazione_investimenti").val() }]);
    righe_investimenti.push([{ PST_colture_allevamenti: $("#pst_colture").val() }]);
    righe_investimenti.push([{ PST_aziendale: $("#pst_aziendale").val() }]);
    righe_investimenti.push([{ fascicolo: $("#numero_fascicolo").val() }]);

    // Dati tipo ditta
    let tipi = [
        $("input[name=tipo_richiedente]:checked").val() === "ditta" ? "SI" : "NO",
        $("input[name=tipo_richiedente]:checked").val() === "societa" ? "SI" : "NO"
    ]
    righe_investimenti.push([{ is_Ditta: tipi[0] }]);
    righe_investimenti.push([{ is_Other: tipi[1] }]);

    // Tecnico Competente
    righe_investimenti.push([{ nome_tecnico: $("#nome-tecnico").val() }]);
    righe_investimenti.push([{ cognome_tecnico: $("#cognome-tecnico").val() }]);
    righe_investimenti.push([{ comune_studio: $("#comune-studio-professionale").val() }]);
    righe_investimenti.push([{ provincia_studio: $("#provincia-studio-professionale").val() }]);
    righe_investimenti.push([{ indirizzo_studio: $("#indirizzo-studio-professionale").val() }]);
    righe_investimenti.push([{ civico_studio: $("#civico-studio-professionale").val() }]);
    righe_investimenti.push([{ recapito_tecnico: $("#recapito-tecnico").val() }]);
    righe_investimenti.push([{ pec_tecnico: $("#pec-tecnico").val() }]);
    righe_investimenti.push([{ mail_tecnico: $("#mail-tecnico").val() }]);
    righe_investimenti.push([{ provincia_tecnico: $("#provincia-ordine-tecnico").val() }]);
    righe_investimenti.push([{ ordine_tecnico: $("#ordine-tecnico").val() }]);
    righe_investimenti.push([{ niscrizione_tecnico: $("#numero-iscrizione-ordine-tecnico").val() }]);

    // Sezione cantierabilità

    // Elenco allegati aggiunti
    const fileInputs = [
        // base (ditta individuale)
        ["Copia documento di identità", 'doc_identita'],
        ["Autorizzazione proprietario/comproprietario (ove pertinente)", 'autorizzazione_proprietario'],
        ["Scheda tecnica di auto-valutazione (perizia asseverata)", 'scheda_autovalutazione'],
        ["Documenti per convalida punteggio auto-attribuito", 'doc_convalida_punteggio'],
        ["Relazione tecnico–agronomica (perizia asseverata)", 'relazione_agronomica'],
        ["Computo metrico estimativo", 'computo_metrico'],
        ["Planimetria catastale ante/post investimento", 'planimetria_catastale'],
        ["Disegni delle opere (piante, sezioni)", 'disegni_opere'],
        ["Perizia di congruità (ove pertinente)", 'perizia_congruita'],
        ["Valutazione tecnica indipendente (ove pertinente)", 'valutazione_indipendente'],
        ["Analisi prezzi (ove pertinente)", 'analisi_prezzi'],
        ["Contratto professionista + preventivo", 'contratto_professionista'],
        ["Autorizzazioni / pareri / nulla osta (o dichiarazione progettista)", 'autorizzazioni_pareri'],
        ["Contratti di affitto/comodato (ove pertinenti)", 'contratti_affitto_comodato'],
        ["Autocert. conoscenza obblighi", 'autocert_conoscenza_obblighi'],
        ["Autocert. iscrizioni CCIAA/INPS + antimafia", 'autocert_iscrizioni_antimafia'],
        ["Autocert. di non aver beneficiato di altri aiuti", 'dich_no_altri_aiuti'],
        ["Certificato di destinazione urbanistica (ove pertinente)", 'cert_destinazione_urbanistica'],

        // aggiuntivi per società/associazioni/cooperative
        ["Atto costitutivo e statuto (società/associazioni/cooperative)", 'atto_costitutivo_statuto'],
        ["Elenco soci firmato (società/associazioni/cooperative)", 'elenco_soci'],
        ["Delibera organo competente (società/associazioni/cooperative)", 'delibera_organo_competente'],
    ];
    // PRIMA del forEach (opzionale, ma chiaro):
    if (!window.RENAMED_BY_FIELD) window.RENAMED_BY_FIELD = {};

    fileInputs.forEach(([label, name]) => {
        const el = document.querySelector(`input[name="${name}"]`);
        if (el && el.files && el.files.length) {
            const f = el.files[0];
            const newFileName = `${cuaa}_${cleanFileName(name)}${getExt(f)}`;

            righe_investimenti.push([{ all: `${newFileName}` }]);

            if (!window.RENAMED_FILES) window.RENAMED_FILES = [];
            window.RENAMED_FILES.push({ file: f, name: newFileName });

            // <<< AGGIUNGI QUESTO >>>
            window.RENAMED_BY_FIELD[name] = newFileName;

        } else {
            righe_investimenti.push([{ all: `${label}: -` }]);
        }
    });
    // alla fine di riempi(...)
    return genera_template(outputPath, righe_investimenti);
}

function setTables(sheet, tableHeader, rows, isTab1, colWidths = [50, 24, 20, 24]) {
    // Imposta larghezze colonne manualmente (senza sovrascrivere l’intero oggetto sheet.columns)
    colWidths.forEach((w, i) => sheet.getColumn(i + 1).width = w);

    // Crea riga header
    const header = sheet.addRow(tableHeader);
    header.height = 58;
    header.eachCell((cell) => {
        cell.alignment = { horizontal: 'center', vertical: 'middle', wrapText: true };
        cell.font = { bold: true, size: 11 };
        cell.fill = { type: 'pattern', pattern: 'solid', fgColor: { argb: 'FFFFFF' } };
        cell.border = {
            top: { style: 'thin' }, left: { style: 'thin' },
            bottom: { style: 'thin' }, right: { style: 'thin' }
        };
    });
    header.commit();

    // Crea righe tabella
    for (let i = 0; i < rows.length; i++) {
        let row;

        if (isTab1) {
            // Righe normali della tabella 1
            if (rows[i][0].tab1) {
                const [descrizione, importo, aliquota, contributo] = rows[i][0].tab1;

                row = sheet.addRow([
                    descrizione,
                    importo,
                    tronca3_format(aliquota),     // ⬅️ tronca ALIQUOTA a 3 decimali
                    tronca2_format(contributo)    // ⬅️ tronca CONTRIBUTO a 2 decimali
                ]);
            }
            // Riga "Totale"
            else if (rows[i][0].tab1_tot) {
                const [importoTot, aliquotaTot, contributoTot] = rows[i][0].tab1_tot;

                row = sheet.addRow([
                    'Totale',
                    importoTot,
                    tronca3_format(aliquotaTot),   // ⬅️ tronca ALIQUOTA totale a 3 decimali
                    tronca2_format(contributoTot)  // ⬅️ tronca CONTRIBUTO totale a 2 decimali
                ]);

                row.getCell(1).alignment = { horizontal: 'right', vertical: 'middle' };
                row.getCell(1).font = { bold: true, size: 11 };
            }
        }

        if (row) {
            row.eachCell((cell) => {
                cell.border = {
                    top: { style: 'thin' }, left: { style: 'thin' },
                    bottom: { style: 'thin' }, right: { style: 'thin' }
                };
            });
        }
    }
}
function extract_data_by_key(rows, keys) {
    const data = [];
    for (let i = 0; i < rows.length; i++) {
        const obj = rows[i][0];
        keys.forEach(key => {
            if (obj[key]) {
                data.push(obj[key]);
            }
        });
    }
    return data;
}

function setOtherData(sheet, sezione, columnHeader, rows, keys) {
    const data = extract_data_by_key(rows, keys);

    if (sezione != '') {
        const rowIndex = sheet.rowCount + 1;
        sheet.mergeCells(`A${rowIndex}:B${rowIndex}`);
        sheet.getCell(rowIndex, 1).value = sezione;
        sheet.getCell(rowIndex, 1).alignment = { horizontal: 'center', vertical: 'middle' };
        sheet.getCell(rowIndex, 1).font = { bold: true, size: 11 };
        sheet.getCell(rowIndex, 1).border = {
            top: { style: 'thin' },
            left: { style: 'thin' },
            bottom: { style: 'thin' },
            right: { style: 'thin' }
        };
    }

    columnHeader.forEach((field, index) => {
        let row;
        if (Array.isArray(data[index])) {
            if (data[index].some(obj => obj.hasOwnProperty("ric_val") || obj.hasOwnProperty("ril_val"))) {
                row = sheet.addRow([field, ...data[index].map(obj => Object.values(obj)).flat()]);
            } else {
                row = sheet.addRow([field, ...data[index]]);
            }
        } else {
            row = sheet.addRow([field, data[index]]);
        }
        row.getCell(1).font = { bold: true };
        row.eachCell((cell, index) => {
            if (index > 1) {
                row.getCell(index).alignment = { wrapText: true };
            }
            if (cell.value) {
                cell.border = {
                    top: { style: 'thin' },
                    left: { style: 'thin' },
                    bottom: { style: 'thin' },
                    right: { style: 'thin' }
                };
            }
        });
    });
}

function getFormattedDate(date) {
    var date = date.split("-");
    var anno = date[0];
    var mese = date[1];
    var giorno = date[2];

    return giorno + '/' + mese + '/' + anno;
}

function generateChecklistData(ws, righe_investimenti) {

    // Tabella PEC
    const pecHeader = [
        'DATA TRASMISSIONE PEC (GG/MM/AAAA)',
        'ORA TRASMISSIONE PEC (HH:MM)',
    ];
    const pec_keys = [
        '',
        ''
    ];
    setOtherData(ws, '', pecHeader, righe_investimenti, pec_keys);
    ws.addRow([]);

    // Tabella protocollo
    const protocolloHeader = [
        'N PROTOCOLLO ACQUISIZIONE ISTANZA',
        'DATA PROTOCOLLO ACQUISIZIONE ISTANZA (GG/MM/AAAA)'
    ];
    const protocollo_keys = [
        '',
        ''
    ];
    setOtherData(ws, '', protocolloHeader, righe_investimenti, protocollo_keys);
    ws.addRow([]);

    // Tabella età anagrafica titolare/rappresentante legale
    const etaTitRapprHeader = [
        'DATA DI NASCITA TITOLARE/RAPPRESENTANTE LEGALE'
    ];
    const etaTitRappr_keys = [
        'data_nascita'
    ];
    setOtherData(ws, '', etaTitRapprHeader, righe_investimenti, etaTitRappr_keys);
    ws.addRow([]);

    // Tabella funzionario istruttore
    const istruttorerHeader = [
        'NOME FUNZIONARIO ISTRUTTORE',
        'COGNOME FUNZIONARIO ISTRUTTORE'
    ];
    const istruttore_keys = [
        '',
        ''
    ];
    setOtherData(ws, '', istruttorerHeader, righe_investimenti, istruttore_keys);
    ws.addRow([]);


    // Tabella interventi (1)
    ws.mergeCells('A24:D24');
    ws.getCell('A24').value = 'Tab. 1 - Piano degli investimenti';
    ws.getCell('A24').alignment = { horizontal: 'center', vertical: 'middle' };
    ws.getCell('A24').font = { bold: true, size: 11 };
    ws.getCell('A24').border = {
        top: { style: 'thin' },
        left: { style: 'thin' },
        bottom: { style: 'thin' },
        right: { style: 'thin' }
    };
    const interventoHeader = [
        'Descrizione Interventi',
        'Importo Imponibile\npreventivato/computato',
        'Aliquota del contributo',
        'Contributo richiesto'
    ];
    setTables(ws, interventoHeader, righe_investimenti, true, [60, 22, 20, 22]);
    ws.addRow([]);
    ws.addRow([]);


    // Tabella PST (2)
    const PSTHeader = [
        'Produzione Standard Totale (PST) colture e allevamenti',
        'Produzione Standard Totale Aziendale - PST'
    ];
    const PST_keys = [
        "PST_colture_allevamenti",
        "PST_aziendale"
    ];
    setOtherData(ws, "Tab. 2 - Produzione Standard Totale dell'azienda", PSTHeader, righe_investimenti, PST_keys);
    ws.addRow([]);
    ws.addRow([]);


    // Tabella PST (3)
    const FascicoloHeader = [
        'Fascicolo aziendale N°'
    ];
    const Fascicolo_keys = [
        "fascicolo"
    ];
    setOtherData(ws, "Tab. 3 - Produzione Standard Totale dell'azienda", FascicoloHeader, righe_investimenti, Fascicolo_keys);
    ws.addRow([]);
    ws.addRow([]);


    // Tabella tipo ditta
    const DittaHeader = [
        'Ditta individuale',
        'Società/Associazione/Cooperativa'
    ];
    const Ditta_keys = [
        "is_Ditta",
        "is_Other"
    ];
    setOtherData(ws, "", DittaHeader, righe_investimenti, Ditta_keys);

    ws.addRow([]);
    ws.addRow([]);


    // Tabella allegati
    ws.addRow(["Documentazione essenziale", "Allegata", "Convalidata"]);
    var headerRow = ws.getRow(ws.rowCount);
    //headerRow.height = 42;
    headerRow.eachCell((cell, colNumber) => {
        cell.alignment = {
            horizontal: 'center',
            vertical: 'middle'
        };
        cell.font = { bold: true };
        //cell.fill = { type: 'pattern', pattern: 'solid', fgColor: { argb: 'BFBFBF' } };
        cell.border = {
            top: { style: 'thin' },
            left: { style: 'thin' },
            bottom: { style: 'thin' },
            right: { style: 'thin' }
        };
        ws.getColumn(colNumber).width = ws.columns[colNumber - 1].width;
    });
    headerRow.commit();

    /*
    let versione = $("#versione").val();
    versione = versione.replace(".", "_");
    const base = outputPath.split("_")[0];
    */

    // Helper: prendi il nome rinominato se esiste, altrimenti l’originale, altrimenti "-"
    const getFileName = (name) => {
        if (window.RENAMED_BY_FIELD && window.RENAMED_BY_FIELD[name]) {
            return window.RENAMED_BY_FIELD[name];
        }
        const el = document.querySelector(`input[name="${name}"]`);
        return (el && el.files && el.files.length) ? el.files[0].name : "-";
    };

    const f_doc_identita = getFileName("doc_identita");
    const f_autorizzazione_proprietario = getFileName("autorizzazione_proprietario");
    const f_scheda_autovalutazione = getFileName("scheda_autovalutazione");
    const f_doc_convalida_punteggio = getFileName("doc_convalida_punteggio");
    const f_relazione_agronomica = getFileName("relazione_agronomica");
    const f_computo_metrico = getFileName("computo_metrico");
    const f_planimetria_catastale = getFileName("planimetria_catastale");
    const f_disegni_opere = getFileName("disegni_opere");
    const f_perizia_congruita = getFileName("perizia_congruita");
    const f_valutazione_indipendente = getFileName("valutazione_indipendente");
    const f_analisi_prezzi = getFileName("analisi_prezzi");
    const f_contratto_professionista = getFileName("contratto_professionista");
    const f_autorizzazioni_pareri = getFileName("autorizzazioni_pareri");
    const f_contratti_affitto_comodato = getFileName("contratti_affitto_comodato");
    const f_autocert_conoscenza_obblighi = getFileName("autocert_conoscenza_obblighi");
    const f_autocert_iscriz_antimafia = getFileName("autocert_iscrizioni_antimafia");
    const f_autocert_no_doppie_agev = getFileName("autocert_no_doppie_agevolazioni");
    const f_cert_destinazione_urb = getFileName("cert_destinazione_urbanistica");
    const f_aiuti_pubblici = getFileName("dich_no_altri_aiuti");

    const checklist_data = [
        ["copia fotostatica del documento di identità *", f_doc_identita, ""],
        ["autorizzazione del proprietario/comproprietario del fondo ad effettuare l'investimento, ove pertinente e non espressamente previsto dai contratti di affitto o comodato d’uso contenente anche la dichiarazione di essere a conoscenza dei vincoli e degli obblighi che saranno assunti dallo stesso e dal richiedente", f_autorizzazione_proprietario, ""],
        ["scheda tecnica di auto-valutazione redatta in forma di perizia asseverata (non giurata) da parte del tecnico professionista *", f_scheda_autovalutazione, ""],
        ["documentazione comprovante il possesso dei requisiti e la sussistenza delle condizioni per la convalida del punteggio auto-attribuito così come individuata nelle tabelle criteri di selezione *", f_doc_convalida_punteggio, ""],
        ["relazione tecnico–agronomica, redatta e sottoscritta da un tecnico abilitato sotto forma di perizia asseverata *", f_relazione_agronomica, ""],
        ["computo metrico estimativo con apposto timbro, data e firma del progettista *", f_computo_metrico, ""],
        ["planimetria su base catastale ante e post investimento, riportante l’ubicazione dell’intervento da realizzare *", f_planimetria_catastale, ""],
        ["disegni delle opere da realizzare (piante, sezioni) con apposto timbro, data e firma del progettista *", f_disegni_opere, ""],
        ["perizia asseverata da parte del tecnico incaricato dal richiedente che attesti la congruità della spesa e/o l’esclusività per le opere e/o lavori non contemplati nel prezzario agricoltura vigente ove pertinente", f_perizia_congruita, ""],
        ["valutazione tecnica indipendente sui costi per le opere e/o lavori non contemplati nel prezzario agricoltura vigente ove pertinente", f_valutazione_indipendente, ""],
        ["analisi prezzi a firma del tecnico progettista per le opere e/o lavori non contemplati nel prezzario agricoltura vigente, ove pertinente", f_analisi_prezzi, ""],
        ["contratto stipulato tra il beneficiario ed il professionista/progettista, corredato dal preventivo del compenso professionale come previsto dalle disposizioni contenute nel Decreto del Ministero della Giustizia 20 luglio 2012 n. 140 e s.m.i *", f_contratto_professionista, ""],
        ["richieste agli Organi preposti per il rilascio delle autorizzazioni, nulla osta, permessi o pareri necessarie all’ottenimento della cantierabilità degli investimenti proposti a finanziamento (ove pertinenti) o, in alternativa, apposita dichiarazione del progettista, redatta in forma di perizia asseverata, che attesti e motivi la non necessità di acquisire i titoli abilitativi *", f_autorizzazioni_pareri, ""],
        ["copia dei contratti di affitto e/o comodato (ove pertinenti)", f_contratti_affitto_comodato, ""],
        ["autocertificazione del richiedente di essere a conoscenza delle disposizioni, delle condizioni e degli obblighi contenuti nell’ Avviso pubblico e nella normativa comunitaria, nazionale e regione di riferimento *", f_autocert_conoscenza_obblighi, ""],
        ["autocertificazione attestante l’iscrizione al Registro delle Imprese Agricole della CCIAA, all’INPS, che non risulta pendente alcun procedimento per le misure di prevenzione previste da decreto legislativo 159/2011 e non sussistono cause di divieto, di sospensione o di decadenza ai sensi dell’art. 67 dello stesso d.lgs. n. 159/2011 *", f_autocert_iscriz_antimafia, ""],
        ["autocertificazione del beneficiario attestante che per la stessa tipologia di investimento non sono state richieste ed ottenute, né saranno richieste in futuro altre agevolazioni ad enti pubblici regionali, nazionali e comunitari, e che ci si assume l’impegno nei cinque anni a decorrere dalla data del pagamento finale del sostegno, in caso di finanziamento, ad osservare gli impegni e gli obblighi riportati nel presente Avviso pubblico e nella normativa di riferimento *", f_autocert_no_doppie_agev, ""],
        ["certificato di destinazione urbanistica riguardante le particelle interessate all’intervento qualora non comprese in altra documentazione se prevista dalla normativa vigente. Tuttavia il certificato può essere sostituito, in caso di mancato rilascio entro i termini, nelle forme previste dall’art.30 del D.P.R. 6 giugno 2001, n. 380", f_cert_destinazione_urb, ""],
        ["dichiarazione di non aver beneficiato, per l’esecuzione dell’opera, di altri aiuti pubblici *", f_aiuti_pubblici, ""]
    ];

    checklist_data.forEach(el => {
        const row = ws.addRow(el);
        row.height = 52;
        row.alignment = { horizontal: 'center', vertical: 'middle', wrapText: true };
    });
    ws.eachRow((row) => {
        row.eachCell((cell) => {
            cell.border = {
                top: { style: 'thin' },
                left: { style: 'thin' },
                bottom: { style: 'thin' },
                right: { style: 'thin' }
            };
        });
    });


    // Allegati aggiuntivi per società/associazioni/cooperative
    const f_atto_costitutivo_statuto = getFileName("atto_costitutivo_statuto");
    const f_elenco_soci = getFileName("elenco_soci");
    const f_delibera_organo_competente = getFileName("delibera_organo_competente");

    // Tabella allegati
    ws.addRow(["Documentazione essenziale per le Società/Associazioni/Cooperative da presentare in aggiunta alla precedente documentazione, ove pertinente", "Allegata", "Convalidata"]);
    var headerRow = ws.getRow(ws.rowCount);
    //headerRow.height = 42;
    headerRow.eachCell((cell, colNumber) => {
        cell.alignment = {
            horizontal: 'center',
            vertical: 'middle'
        };
        cell.font = { bold: true };
        //cell.fill = { type: 'pattern', pattern: 'solid', fgColor: { argb: 'BFBFBF' } };
        cell.border = {
            top: { style: 'thin' },
            left: { style: 'thin' },
            bottom: { style: 'thin' },
            right: { style: 'thin' }
        };
        ws.getColumn(colNumber).width = ws.columns[colNumber - 1].width;
    });
    headerRow.commit();

    const checklist_other_data = [
        ["atto costitutivo e statuto sociale o altro atto avente valenza equipollente, con estremi di registrazione *", f_atto_costitutivo_statuto, ""],
        ["elenco complessivo dei soci, a firma del rappresentante legale *", f_elenco_soci, ""],
        ["delibera dell’organo competente della coop/società/associazione che approva l’iniziativa proposta, che delega il rappresentante legale a presentare domanda di sostegno e con la quale si autorizza il legale rappresentante ad assumere l’impegno finanziario di spesa per la parte non coperta dall’aiuto pubblico o a richiedere la concessione di fidi o di altre forme di garanzia *", f_delibera_organo_competente, ""]
    ];

    checklist_other_data.forEach(el => {
        const row = ws.addRow(el);
        row.height = 52;
        row.alignment = { horizontal: 'center', vertical: 'middle', wrapText: true };
    });
    ws.eachRow((row) => {
        row.eachCell((cell) => {
            cell.border = {
                top: { style: 'thin' },
                left: { style: 'thin' },
                bottom: { style: 'thin' },
                right: { style: 'thin' }
            };
        });
    });
}

function htmlTableToExcel(ws, tableSelector, opts) {
    const $ = window.jQuery;
    const $table = $(tableSelector);

    const o = Object.assign({ startRow: 1, startCol: 1, drawBorders: true, columnWidths: null }, opts || {});
    const BORDER = { top: { style: 'thin' }, right: { style: 'thin' }, bottom: { style: 'thin' }, left: { style: 'thin' } };

    const cleanText = ($td) => {
        if (!$td || !$td.length) return "";
        const c = $td.clone();
        c.find('a').each(function () { const $a = $(this); const t = ($a.text() || $a.attr('href') || '').trim(); $a.replaceWith(t); });
        c.find('div.form-file-hint, input').remove();
        return c.text().replace(/\s+\n/g, " ").replace(/\s+/g, " ").trim();
    };
    const getPointsFromCell = ($td) => {
        const c = $td.clone(); c.children().remove();
        const m = c.text().match(/(-?\d+)(?:[^\d]|$)/);
        return m ? parseInt(m[1], 10) : 0;
    };
    const hasAnyFileInCell = ($td) => {
        let ok = false;
        if ($td && $td.length) $td.find('input[type="file"]').each(function () { if (this.files && this.files.length) ok = true; });
        return ok;
    };

    const setBorders = (r1, c1, r2, c2) => {
        if (!o.drawBorders) return;
        for (let r = r1; r <= r2; r++) for (let c = c1; c <= c2; c++) {
            ws.getCell(r, c).border = {
                top: (r === r1) ? { style: 'thin' } : {},
                bottom: (r === r2) ? { style: 'thin' } : {},
                left: (c === c1) ? { style: 'thin' } : {},
                right: (c === c2) ? { style: 'thin' } : {}
            };
        }
    };

    const occupancy = {};
    const setOcc = (r, c) => (occupancy[`${r}:${c}`] = true);
    const isOcc = (r, c) => !!occupancy[`${r}:${c}`];

    let excelRow = o.startRow;
    if (o.columnWidths && o.columnWidths.length) ws.columns = o.columnWidths.map(w => ({ width: w }));

    const COL_A = o.startCol;
    const COL_B = o.startCol + 1;
    const COL_C = o.startCol + 2;
    const COL_D = o.startCol + 3;
    const COL_E = o.startCol + 4;
    const COL_F = o.startCol + 5;
    const COL_G = o.startCol + 6;
    const COL_H = o.startCol + 7;

    const mergePlansExtras = [];

    const processSection = ($section, isHead = false) => {
        $section.find('tr').each(function () {
            const $tr = $(this);
            let excelCol = o.startCol;
            let seenCheckbox = false;
            let plannedDocRs = 1;
            let plannedHasFiles = false;

            const nextFreeCol = () => { while (isOcc(excelRow, excelCol)) excelCol++; return excelCol; };

            if (!isHead) {
                const f = ws.getCell(excelRow, COL_F);
                f.value = "";
                f.alignment = { vertical: 'middle', horizontal: 'center', wrapText: true };
                setBorders(excelRow, COL_F, excelRow, COL_F);
            }

            $tr.children('th,td').each(function () {
                const $cell = $(this);
                nextFreeCol();

                const rs = Math.max(1, parseInt($cell.attr('rowspan') || '1', 10));
                const cs = Math.max(1, parseInt($cell.attr('colspan') || '1', 10));

                let value;
                let isCheckboxCell = false;
                if ($cell.find('input[type="checkbox"]').length) {
                    const checked = $cell.find('input[type="checkbox"]').is(':checked');
                    const pts = getPointsFromCell($cell);
                    value = checked ? pts : 0;
                    isCheckboxCell = true;
                } else {
                    value = cleanText($cell);
                }

                const xcell = ws.getCell(excelRow, excelCol);
                xcell.value = value || "";
                xcell.alignment = { vertical: 'top', wrapText: true };
                if ($cell.is('th')) { xcell.font = { bold: true }; xcell.alignment = { vertical: 'middle', horizontal: 'center', wrapText: true }; }
                if ($cell.hasClass('vertical-td')) { xcell.alignment = { textRotation: 90, vertical: 'middle', horizontal: 'center', wrapText: true }; xcell.font = { bold: true }; }

                for (let rr = 0; rr < rs; rr++) for (let cc = 0; cc < cs; cc++) if (!(rr === 0 && cc === 0)) setOcc(excelRow + rr, excelCol + cc);
                if (rs > 1 || cs > 1) ws.mergeCells(excelRow, excelCol, excelRow + rs - 1, excelCol + cs - 1);
                setBorders(excelRow, excelCol, excelRow + rs - 1, excelCol + cs - 1);

                if (isCheckboxCell) {
                    seenCheckbox = true;
                } else if (seenCheckbox) {
                    plannedDocRs = rs;
                    plannedHasFiles = hasAnyFileInCell($cell);
                    if (!isHead) {
                        if (rs > 1) {
                            mergePlansExtras.push({ col: COL_G, from: excelRow, to: excelRow + rs - 1, value: plannedHasFiles ? "SI" : "NO" });
                            mergePlansExtras.push({ col: COL_H, from: excelRow, to: excelRow + rs - 1, value: "" });
                            for (let rr = 0; rr < rs; rr++) { setOcc(excelRow + rr, COL_G); setOcc(excelRow + rr, COL_H); }
                        } else {
                            const g = ws.getCell(excelRow, COL_G);
                            g.value = plannedHasFiles ? "SI" : "NO";
                            g.alignment = { vertical: 'middle', horizontal: 'center' };
                            setBorders(excelRow, COL_G, excelRow, COL_G);

                            const h = ws.getCell(excelRow, COL_H);
                            h.value = "";
                            h.alignment = { vertical: 'middle', horizontal: 'center' };
                            setBorders(excelRow, COL_H, excelRow, COL_H);
                        }
                    }
                    seenCheckbox = false;
                }

                excelCol += cs;
            });

            if (isHead) {
                ws.getCell(o.startRow, COL_F).value = "Punteggio convalidato";
                ws.getCell(o.startRow, COL_F).font = { bold: true };
                ws.getCell(o.startRow, COL_F).alignment = { vertical: 'middle', horizontal: 'center', wrapText: true };
                setBorders(o.startRow, COL_F, o.startRow, COL_F);

                ws.getCell(o.startRow, COL_G).value = "Documentazione allegata si/no";
                ws.getCell(o.startRow, COL_G).font = { bold: true };
                ws.getCell(o.startRow, COL_G).alignment = { vertical: 'middle', horizontal: 'center', wrapText: true };
                setBorders(o.startRow, COL_G, o.startRow, COL_G);

                ws.getCell(o.startRow, COL_H).value = "Documentazione congrua si/no";
                ws.getCell(o.startRow, COL_H).font = { bold: true };
                ws.getCell(o.startRow, COL_H).alignment = { vertical: 'middle', horizontal: 'center', wrapText: true };
                setBorders(o.startRow, COL_H, o.startRow, COL_H);
            }

            excelRow++;
        });
    };

    const $thead = $table.children('thead');
    if ($thead.length) processSection($thead, true);

    const $tbody = $table.children('tbody');
    if ($tbody.length) processSection($tbody, false);

    mergePlansExtras.forEach(m => {
        ws.mergeCells(m.from, m.col, m.to, m.col);
        const c = ws.getCell(m.from, m.col);
        c.value = m.value;
        c.alignment = { vertical: 'middle', horizontal: 'center', wrapText: true };
        setBorders(m.from, m.col, m.to, m.col);
    });
}

async function genera_template(outputPath, righe_investimenti) {
    const workbook = new ExcelJS.Workbook();
    const sheet1 = workbook.addWorksheet('1_Anagrafica');
    const sheet2 = workbook.addWorksheet('2_Checklist');
    const sheet3 = workbook.addWorksheet('3_Criteri selezione');
    const sheet4 = workbook.addWorksheet('4_Input automazione');

    /* Primo worksheet */

    // ---- LARGHEZZE COLONNE FOGLIO 1 (Anagrafica) ----
    // Colonna A = etichette (larga), B = valori (più larga)
    sheet1.getColumn(1).width = 36;  // Etichette (es. "Provincia di nascita")
    sheet1.getColumn(2).width = 64;  // Valori inseriti

    // Se in A1:G4/A5:G12/A13:G16 hai i blocchi titolo/avviso/banner,
    // assicura qualche colonna di “respiro” anche oltre B:
    for (let c = 3; c <= 7; c++) sheet1.getColumn(c).width = 18;

    // (opzionale ma utile) rendi più leggibili le righe dei dati
    sheet1.properties.defaultRowHeight = 18;
    // Workaround bug ExcelJS per le immagini
    const imageId = workbook.addImage({
        base64: $('#png_regione_siciliana').attr('src').split(',')[1],
        extension: 'png'
    });
    sheet1.addImage(imageId, {
        tl: { col: 0, row: 0 },
        ext: { width: 60, height: 60 }
    });
    sheet1.mergeCells('A1:G4');
    sheet1.getCell('A1').value = 'Assessorato dell’agricoltura, dello sviluppo rurale e della pesca mediterranea\nDipartimento dell’agricoltura';
    sheet1.getCell('A1').alignment = { horizontal: 'center', vertical: 'middle', wrapText: true };
    sheet1.getCell('A1').font = { bold: true, size: 14 };
    sheet1.getCell('A1').fill = { type: 'pattern', pattern: 'solid', fgColor: { argb: 'FFFFFF' } };

    sheet1.mergeCells('A5:G12');
    sheet1.getCell('A5').value = 'Avviso per la realizzazione di progetti di investimento destinati a garantire la gestione sostenibile del ciclo\nintegrato delle acque in attuazione dell’asse 2 azione POC 2_3_02_01 del Piano Operativo Complementare POC\n2014/2020. (Avviso 2025)';
    sheet1.getCell('A5').alignment = { horizontal: 'center', vertical: 'middle', wrapText: true };
    sheet1.getCell('A5').fill = { type: 'pattern', pattern: 'solid', fgColor: { argb: 'D9D9D9' } };
    sheet1.getCell('A5').font = { size: 14 };

    sheet1.mergeCells('A13:G16');
    sheet1.getCell('A13').value = 'Verbale di ricevibilità/ammissibilità';
    sheet1.getCell('A13').alignment = { horizontal: 'center', vertical: 'middle' };
    sheet1.getCell('A13').font = { bold: true, size: 14, color: { argb: 'FFFFFF' } };
    sheet1.getCell('A13').fill = { type: 'pattern', pattern: 'solid', fgColor: { argb: '002060' } };

    const anagraficaHeader = [
        'Nome', 'Cognome', 'Data di nascita', 'Luogo di nascita', 'Provincia di nascita',
        'CUAA', 'Residenza', 'Provincia', 'Indirizzo', 'Civico', 'Pec Aziendale',
        'Mail Aziendale', 'Telefono/Cellulare', 'Qualifica', 'Denominazione', 'Sede Legale',
        'Indirizzo Sede Legale', 'Civico Sede Legale', 'Provincia di riferimento della CCIAA',
        'Numero REA', 'Numero iscrizione INPS'
    ];
    const anagrafica_keys = [
        "nome", "cognome", "data_nascita", "luogo_nascita", "provincia_nascita",
        "cuua", "residenza", "provincia", "indirizzo", "civico", "pec",
        "email_aziendale", "telefono", "qualifica", "denominazione", "sede",
        "sede_indirizzo", "civico_sede", "ccia", "rea", "inps"
    ];
    setOtherData(sheet1, 'Sezione Anagrafica', anagraficaHeader, righe_investimenti, anagrafica_keys);

    sheet1.addRow([]);
    sheet1.addRow([]);

    const bancariHeader = [
        'IBAN', 'Istituto di Credito', 'Agenzia'
    ];
    const bancari_keys = [
        "iban", "istituto_credito", "agenzia_banca"
    ];
    setOtherData(sheet1, 'Dati Bancari', bancariHeader, righe_investimenti, bancari_keys);

    sheet1.addRow([]);
    sheet1.addRow([]);

    let localizzazioneHeader = [
        'Provincia di localizzazione', 'Comune di localizzazione', 'Foglio', 'Particelle'
    ];
    let localizzazione_keys = [
        "provincia_localizzazione", "comune_localizzazione", "foglio", "particella"
    ];
    setOtherData(sheet1, 'Localizzazione Investimento n.1', localizzazioneHeader, righe_investimenti, localizzazione_keys);
    var totale_localizzazioni = $("#numero_localizzazioni_investimenti").val();
    for (let i = 2; i <= totale_localizzazioni; i++) {
        localizzazione_keys = [
            `provincia_localizzazione_${i}`, `comune_localizzazione_${i}`, `foglio_${i}`, `particella_${i}`
        ];
        setOtherData(sheet1, `Localizzazione Investimento n.${i}`, localizzazioneHeader, righe_investimenti, localizzazione_keys);
    }

    sheet1.addRow([]);
    sheet1.addRow([]);

    let tecnicoHeader;
    let tecnico_keys;
    tecnicoHeader = [
        'Nome', 'Cognome', 'Comune dello studio professionale', 'Provincia dello studio professionale', 'Indirizzo dello studio professionale', 'Civico dello studio professionale',
        'Telefono/Cellulare', 'PEC', 'Email', 'Provincia/Sezione/Regione di iscrizione all\'Ordine/Albo', 'Ordine/Albo di iscrizione', 'Numero di iscrizione'
    ];
    tecnico_keys = [
        "nome_tecnico", "cognome_tecnico", "comune_studio", "provincia_studio", "indirizzo_studio", "civico_studio",
        "recapito_tecnico", "pec_tecnico", "mail_tecnico", "provincia_tecnico", "ordine_tecnico", "niscrizione_tecnico"
    ];
    setOtherData(sheet1, 'Tecnico Competente', tecnicoHeader, righe_investimenti, tecnico_keys);


    /* Secondo worksheet */

    sheet2.addImage(imageId, {
        tl: { col: 0, row: 0 },
        ext: { width: 60, height: 60 }
    });

    sheet2.columns = [
        { key: 'id', width: 12 },
        { key: 'verifica', width: 70 }, // descrizioni lunghe
        { key: 'si', width: 12 },
        { key: 'no', width: 12 },
        { key: 'na', width: 12 },
        { key: 'documenti', width: 28 },
        { key: 'note', width: 28 }
    ];

    sheet2.mergeCells('A1:G4');
    sheet2.getCell('A1').value = 'Assessorato dell’agricoltura, dello sviluppo rurale e della pesca mediterranea\nDipartimento dell’agricoltura';
    sheet2.getCell('A1').alignment = { horizontal: 'center', vertical: 'middle', wrapText: true };
    sheet2.getCell('A1').font = { bold: true, size: 14 };
    sheet2.getCell('A1').fill = { type: 'pattern', pattern: 'solid', fgColor: { argb: 'FFFFFF' } };

    sheet2.mergeCells('A5:G8');
    sheet2.getCell('A5').value = 'VERBALE ISTRUTTORIA';
    sheet2.getCell('A5').alignment = { horizontal: 'center', vertical: 'middle' };
    sheet2.getCell('A5').font = { bold: true, size: 14, color: { argb: 'FFFFFF' } };
    sheet2.getCell('A5').fill = { type: 'pattern', pattern: 'solid', fgColor: { argb: '002060' } };

    generateChecklistData(sheet2, righe_investimenti);


    /* Terzo worksheet */
    sheet3.addImage(imageId, {
        tl: { col: 0, row: 0 },
        ext: { width: 60, height: 60 }
    });

    sheet3.mergeCells('A1:G4');
    sheet3.getCell('A1').value = 'Assessorato dell’agricoltura, dello sviluppo rurale e della pesca mediterranea\nDipartimento dell’agricoltura';
    sheet3.getCell('A1').alignment = { horizontal: 'center', vertical: 'middle', wrapText: true };
    sheet3.getCell('A1').font = { bold: true, size: 14 };
    sheet3.getCell('A1').fill = { type: 'pattern', pattern: 'solid', fgColor: { argb: 'FFFFFF' } };

    sheet3.mergeCells('A5:G8');
    sheet3.getCell('A5').value = 'VERBALE ISTRUTTORIA';
    sheet3.getCell('A5').alignment = { horizontal: 'center', vertical: 'middle' };
    sheet3.getCell('A5').font = { bold: true, size: 14, color: { argb: 'FFFFFF' } };
    sheet3.getCell('A5').fill = { type: 'pattern', pattern: 'solid', fgColor: { argb: '002060' } };

    sheet3.mergeCells('A9:G13');
    sheet3.getCell('A9').value = 'PUNTEGGIO AUTO ATTRIBUITO E CONVALIDATO';
    sheet3.getCell('A9').alignment = { horizontal: 'center', vertical: 'middle' };
    sheet3.getCell('A9').font = { bold: true, size: 14, color: { argb: 'FFFFFF' } };
    sheet3.getCell('A9').fill = { type: 'pattern', pattern: 'solid', fgColor: { argb: 'E4D96F' } };

    htmlTableToExcel(sheet3, 'table.table-tight', {
        startRow: 14,
        startCol: 1,
        columnWidths: [10, 28, 44, 12, 46, 16, 20, 22]
    });

    /* Quarto worksheet */
    sheet4.columns = [
        { header: 'N PROT', key: 'nprot', width: 15 },
        { header: 'DATA PROT', key: 'data_prot', width: 15 },
        { header: 'DATA INVIO PEC (GG/MM/AAAA)', key: 'data_pec', width: 20 },
        { header: 'ORA INVIO PEC (HH:MM)', key: 'ora_pec', width: 15 },
        { header: 'DATA NASCITA TITOLARE/RAPPRESENTANTE LEGALE', key: 'data_nascita', width: 20 },
        { header: 'DENOMINAZIONE', key: 'denominazione', width: 25 },
        { header: 'CUAA', key: 'cuaa', width: 15 },
        { header: 'IMPORTO SPESA RICHIESTO', key: 'imp_rich', width: 20 },
        { header: 'IMPORTO SPESA APPROVATO', key: 'imp_approv', width: 20 }, // vuota
        { header: 'CONTRIBUTO RICHIESTO', key: 'contr_rich', width: 20 },
        { header: 'CONTRIBUTO APPROVATO', key: 'contr_approv', width: 20 }, // vuota
        { header: 'INVESTIMENTI IN TERRITORI SOGGETTI A MAGGIORI DEFICIT PLUVIOMETRICI', key: 'deficit', width: 15 },
        { header: 'INVESTIMENTI PROPOSTI DA GIOVANE AGRICOLTORE', key: 'giovane', width: 15 },
        { header: 'IAP O COLTIVATORE DIRETTO', key: 'iap', width: 15 },
        { header: 'MANCATA PRESENTAZIONE DOMANDA DI SOSTEGNO A VALERE DEI BANDI PSC-POC-L.R. 23/2024', key: 'mancata', width: 25 },
        { header: 'DIMENSIONE ECONOMICA AZIENDALE COMPLESSIVA (PST)', key: 'pst', width: 20 },
        { header: 'CAPACITÀ TOTALE DI INVASO DELL’OPERA', key: 'invaso', width: 20 },
        { header: 'PROGETTI IMMEDIATAMENTE CANTIERABILI', key: 'cantierabile', width: 20 },
        { header: 'PUNTEGGIO AUTO ATTRIBUITO TOTALE', key: 'punteggio_auto', width: 20 },
        { header: 'PUNTEGGIO RICONOSCIUTO', key: 'punteggio_ric', width: 20 } // vuota
    ];
    // 👇 SUBITO DOPO, AGGIUNGI QUESTE RIGHE:
    sheet4.getColumn(2).numFmt = 'dd/mm/yyyy'; // DATA PROT
    sheet4.getColumn(3).numFmt = 'dd/mm/yyyy'; // DATA INVIO PEC
    sheet4.getColumn(4).numFmt = 'hh:mm';      // ORA INVIO PEC
    sheet4.getColumn(5).numFmt = 'dd/mm/yyyy'; // DATA NASCITA

    const excelFormulas = [
        // *** 2_Checklist ***
        "'2_Checklist'!B12", "'2_Checklist'!B13", "'2_Checklist'!B9",
        "'2_Checklist'!B10", "'2_Checklist'!B15",

        // *** 1_Anagrafica ***
        "'1_Anagrafica'!B32", "'1_Anagrafica'!B23",

        // Totale B
        'IFERROR(XLOOKUP("Totale",\'2_Checklist\'!A:A,\'2_Checklist\'!B:B,,0),INDEX(\'2_Checklist\'!B:B,MATCH("Totale",\'2_Checklist\'!A:A,0)))', "",

        // Totale D
        'IFERROR(XLOOKUP("Totale",\'2_Checklist\'!A:A,\'2_Checklist\'!D:D,,0),INDEX(\'2_Checklist\'!D:D,MATCH("Totale",\'2_Checklist\'!A:A,0)))', "",

        // *** 3_Criteri selezione ***
        "SUM('3_Criteri selezione'!D15:D17)",
        "'3_Criteri selezione'!D18",
        "'3_Criteri selezione'!D19",
        "'3_Criteri selezione'!D20",
        "SUM('3_Criteri selezione'!D21:D23)",
        "SUM('3_Criteri selezione'!D24:D27)",
        "'3_Criteri selezione'!D28",
        "'3_Criteri selezione'!D29",
        ""
    ];

    const r = sheet4.addRow([]);

    let colIndex = 1;
    for (let i = 0; i < excelFormulas.length; i++) {
        if (excelFormulas[i] != "") {
            r.getCell(colIndex).value = { formula: excelFormulas[i] };
        }
        colIndex++;
    }

    const buffer = await workbook.xlsx.writeBuffer();
    const xlsxBlob = new Blob([buffer], {
        type: 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet'
    });

    // memorizzo per lo ZIP
    LAST_EXCEL = { blob: xlsxBlob, filename: outputPath };

    // faccio anche il download locale come prima (se lo vuoi)
    // saveAs(xlsxBlob, outputPath);

    return true; // così posso fare await
}