function colIdxToLetter(n) {
    let s = "";
    n = n + 1;
    while (n > 0) {
        const m = (n - 1) % 26;
        s = String.fromCharCode(65 + m) + s;
        n = Math.floor((n - m) / 26);
    }
    return s;
}

function escapeXmlText(txt) {
    return String(txt ?? "")
        .replace(/&/g, "&amp;")
        .replace(/</g, "&lt;")
        .replace(/>/g, "&gt;");
}

function readCellText($cell, sheet, xlsx) {
    const t = $cell.attr("t");
    if (t === "inlineStr") {
        const tNode = $cell.find("is t");
        return tNode.length ? tNode.text() : "";
    }
    if (t === "s") {
        const v = $cell.find("v").text();
        const idx = parseInt(v, 10);
        const sst = xlsx.xl["sharedStrings.xml"];
        if (!sst) return "";
        const si = $("sst si", sst).eq(idx);
        if (!si.length) return "";

        let out = "";
        si.find("t").each(function () {
            out += $(this).text();
        });
        return out;
    }

    const vNode = $cell.find("v");
    return vNode.length ? vNode.text() : "";
}

function newexportaction(e, dt, button, config, cb) {
    const self = this;
    const settings = dt.settings()[0];
    const isServerSide = settings.oFeatures && settings.oFeatures.bServerSide;
    const hasAjax = !!settings.ajax;

    const customizeHeaderExcel = function (xlsx) {
        const sheet = xlsx.xl.worksheets["sheet1.xml"];
        const styles = xlsx.xl["styles.xml"];

        // --- crea background azzurro ---
        const fills = $("fills", styles);
        fills.append(
            '<fill><patternFill patternType="solid">' +
                '<fgColor rgb="FFDDEBF7"/><bgColor indexed="64"/>' +
                "</patternFill></fill>",
        );
        const fillId = $("fill", styles).length - 1;
        fills.attr("count", $("fill", styles).length); // aggiorna count

        // --- crea FONT bold nero ---
        const fonts = $("fonts", styles);
        fonts.append(
            '<font><b/><sz val="11"/><color rgb="FF000000"/><name val="Calibri"/></font>',
        );
        const fontId = $("font", styles).length - 1;
        fonts.attr("count", $("font", styles).length); // aggiorna count

        // --- crea XF senza bordi, bold + fill azzurro ---
        const cellXfs = $("cellXfs", styles);
        cellXfs.append(
            `<xf xfId="0" applyFont="1" applyFill="1" borderId="0" fontId="${fontId}" fillId="${fillId}">
                    <alignment vertical="center"/>
                </xf>`,
        );
        const xfId = $("cellXfs xf", styles).length - 1;
        cellXfs.attr("count", $("cellXfs xf", styles).length); // aggiorna count

        // --- applica lo stile alla PRIMA riga (header) ---
        $("row:first c", sheet).attr("s", xfId);
    };

    const alignLeftCells = function (xlsx, config) {
        let leftCols = Array.isArray(config.exportLeftCols)
            ? [...config.exportLeftCols]
            : [];
        if (leftCols.length === 0 && dt && dt.columns) {
            const headerIdxs = [];
            $(dt.columns().header()).each(function (i, th) {
                if ($(th).hasClass("export-left")) headerIdxs.push(i);
            });
            leftCols = headerIdxs;
        }

        if (leftCols.length) {
            const sheet = xlsx.xl.worksheets["sheet1.xml"];
            const styles = xlsx.xl["styles.xml"];

            const cellXfs = $("cellXfs", styles);
            cellXfs.append(
                `<xf xfId="0" applyAlignment="1">
                        <alignment horizontal="left" vertical="center"/>
                    </xf>`,
            );
            const leftXfId = $("cellXfs xf", styles).length - 1;
            cellXfs.attr("count", $("cellXfs xf", styles).length);

            leftCols.forEach(function (colIdx) {
                const colLetter = colIdxToLetter(colIdx);

                $('row:not(:first) c[r^="' + colLetter + '"]', sheet).each(
                    function () {
                        const cell = $(this);
                        const sAttr = cell.attr("s");
                        if (sAttr === undefined) {
                            cell.attr("s", leftXfId);
                        } else {
                            const xfs = $("cellXfs xf", styles);
                            const baseXf = xfs.eq(parseInt(sAttr, 10)).clone();
                            if (baseXf.find("alignment").length === 0) {
                                baseXf.append(
                                    '<alignment horizontal="left" vertical="center"/>',
                                );
                            } else {
                                baseXf
                                    .find("alignment")
                                    .attr("horizontal", "left")
                                    .attr("vertical", "center");
                            }
                            cellXfs.append(baseXf);

                            const newId = $("cellXfs xf", styles).length - 1;
                            cellXfs.attr(
                                "count",
                                $("cellXfs xf", styles).length,
                            );
                            cell.attr("s", newId);
                        }
                    },
                );
            });
        }
    };

    const forceAllCellsAsText = function (xlsx) {
        const sheet = xlsx.xl.worksheets["sheet1.xml"];
        if (!sheet) return;

        $("worksheet sheetData row c", sheet).each(function () {
            const $cell = $(this);
            const text = readCellText($cell, sheet, xlsx);
            // sostituisco contenuto con inline string
            $cell.attr("t", "inlineStr");
            $cell.find("v").remove();
            $cell.find("is").remove();
            const safe = escapeXmlText(text);
            $cell.append(`<is><t>${safe}</t></is>`);
            // NON tocco l’attributo 's' (stile) se già esiste
        });
    };

    // --- CLIENT-SIDE ---
    if (!isServerSide || !hasAjax) {
        // Esporta tutte le righe lato client
        const origExportOptions = config.exportOptions
            ? { ...config.exportOptions }
            : {};
        config.exportOptions = config.exportOptions || {};
        config.exportOptions.modifier = {
            ...(config.exportOptions.modifier || {}),
            page: "all",
        };

        // PDF: tabella full-width
        // const isPdf = button[0].className.indexOf('buttons-pdf') >= 0;
        // const origCustomize = config.customize;
        // if (isPdf) {
        //     config.customize = function(doc) {
        //         const table = doc.content[1] && doc.content[1].table ? doc.content[1].table : null;
        //         if (table && table.body && table.body[0]) {
        //             table.widths = Array(table.body[0].length).fill('*');
        //         }
        //         if (typeof origCustomize === 'function') origCustomize(doc);
        //     };
        // }

        const cls = button[0].className;

        if (cls.includes("buttons-copy")) {
            $.fn.dataTable.ext.buttons.copyHtml5.action.call(
                self,
                e,
                dt,
                button,
                config,
                cb,
            );
        } else if (cls.includes("buttons-excel")) {
            const origCustomize = config.customize;
            const origTitle = config.title;
            const origFilename = config.filename;

            config.filename =
                typeof origFilename !== "undefined" ? origFilename : origTitle;
            config.title = null;

            config.customize = function (xlsx) {
                if (typeof origCustomize === "function") origCustomize(xlsx);
                customizeHeaderExcel(xlsx);
                alignLeftCells(xlsx, config);
                forceAllCellsAsText(xlsx);
            };

            ($.fn.dataTable.ext.buttons.excelHtml5.available(dt, config)
                ? $.fn.dataTable.ext.buttons.excelHtml5
                : $.fn.dataTable.ext.buttons.excelFlash
            ).action.call(self, e, dt, button, config, cb);

            config.customize = origCustomize;
            config.title = origTitle;
            config.filename = origFilename;
        } else if (cls.includes("buttons-csv")) {
            ($.fn.dataTable.ext.buttons.csvHtml5.available(dt, config)
                ? $.fn.dataTable.ext.buttons.csvHtml5
                : $.fn.dataTable.ext.buttons.csvFlash
            ).action.call(self, e, dt, button, config, cb);
        } else if (cls.includes("buttons-pdf")) {
            ($.fn.dataTable.ext.buttons.pdfHtml5.available(dt, config)
                ? $.fn.dataTable.ext.buttons.pdfHtml5
                : $.fn.dataTable.ext.buttons.pdfFlash
            ).action.call(self, e, dt, button, config, cb);
        } else if (cls.includes("buttons-print")) {
            $.fn.dataTable.ext.buttons.print.action.call(
                self,
                e,
                dt,
                button,
                config,
                cb,
            );
        }

        // Ripristina config
        config.exportOptions = origExportOptions;
        // if (isPdf) config.customize = origCustomize;

        if (typeof cb === "function") cb();
        return;
    }

    // --- SERVER-SIDE + AJAX: fetch completo poi export ---
    const info = dt.page.info();
    const oldStart = info.start;
    const oldLength = info.length;
    const targetLength = info.recordsTotal > 0 ? info.recordsTotal : 2147483647;

    dt.one("preXhr", function (e2, s, data) {
        data.start = 0;
        data.length = targetLength;

        dt.one("preDraw", function (e3, stg) {
            const cls = button[0].className;

            if (cls.includes("buttons-copy")) {
                $.fn.dataTable.ext.buttons.copyHtml5.action.call(
                    self,
                    e,
                    dt,
                    button,
                    config,
                    cb,
                );
            } else if (cls.includes("buttons-excel")) {
                const origCustomize = config.customize;
                const origTitle = config.title;
                const origFilename = config.filename;

                config.filename =
                    typeof origFilename !== "undefined"
                        ? origFilename
                        : origTitle;
                config.title = null;

                config.customize = function (xlsx) {
                    if (typeof origCustomize === "function") {
                        origCustomize(xlsx);
                    }
                    customizeHeaderExcel(xlsx);
                    alignLeftCells(xlsx, config);
                    forceAllCellsAsText(xlsx);
                };

                ($.fn.dataTable.ext.buttons.excelHtml5.available(dt, config)
                    ? $.fn.dataTable.ext.buttons.excelHtml5
                    : $.fn.dataTable.ext.buttons.excelFlash
                ).action.call(self, e, dt, button, config, cb);

                config.customize = origCustomize;
                config.title = origTitle;
                config.filename = origFilename;
            } else if (cls.includes("buttons-csv")) {
                ($.fn.dataTable.ext.buttons.csvHtml5.available(dt, config)
                    ? $.fn.dataTable.ext.buttons.csvHtml5
                    : $.fn.dataTable.ext.buttons.csvFlash
                ).action.call(self, e, dt, button, config, cb);
            } else if (cls.includes("buttons-pdf")) {
                // Full-width PDF
                // const origCustomize = config.customize;
                // config.customize = function(doc) {
                //     const t = doc.content[1] && doc.content[1].table ? doc.content[1].table : null;
                //     if (t && t.body && t.body[0]) t.widths = Array(t.body[0].length).fill('*');
                //     if (typeof origCustomize === 'function') origCustomize(doc);
                // };
                ($.fn.dataTable.ext.buttons.pdfHtml5.available(dt, config)
                    ? $.fn.dataTable.ext.buttons.pdfHtml5
                    : $.fn.dataTable.ext.buttons.pdfFlash
                ).action.call(self, e, dt, button, config, cb);
                // config.customize = origCustomize;
            } else if (cls.includes("buttons-print")) {
                $.fn.dataTable.ext.buttons.print.action.call(
                    self,
                    e,
                    dt,
                    button,
                    config,
                    cb,
                );
            }

            dt.one("preXhr", function (e4, s2, data2) {
                data2.start = oldStart;
                data2.length = oldLength;
                stg._iDisplayStart = oldStart;
            });

            setTimeout(() => {
                dt.ajax.reload(() => {
                    if (typeof cb === "function") cb();
                }, false);
            }, 0);

            return false;
        });
    });

    dt.ajax.reload();
}
