(function () {
    function normalize(text) {
        return (text || "").toString().toLocaleLowerCase("es-AR").normalize("NFD").replace(/[\u0300-\u036f]/g, "");
    }

    function cellText(row) {
        return Array.from(row.children).map((cell) => cell.innerText.trim());
    }

    function download(filename, text) {
        const blob = new Blob([text], { type: "text/csv;charset=utf-8" });
        const url = URL.createObjectURL(blob);
        const link = document.createElement("a");
        link.href = url;
        link.download = filename;
        document.body.appendChild(link);
        link.click();
        link.remove();
        URL.revokeObjectURL(url);
    }

    function csvEscape(value) {
        const text = (value || "").replace(/\s+/g, " ").trim();
        return `"${text.replace(/"/g, '""')}"`;
    }

    function visibleRows(table) {
        return Array.from(table.querySelectorAll(".table-row")).filter((row) => row.style.display !== "none");
    }

    function matchedRows(table) {
        return Array.from(table.querySelectorAll(".table-row")).filter((row) => row.dataset.filtered !== "0");
    }

    function storageKey(table, title) {
        const path = window.location.pathname.replace(/[^\w\d-]+/g, "_");
        const name = title.replace(/[^\w\d-]+/g, "_");
        return `perley:datatable:${path}:${name}`;
    }

    function readState(key) {
        try {
            return JSON.parse(localStorage.getItem(key) || "{}");
        } catch (_error) {
            return {};
        }
    }

    function writeState(key, state) {
        localStorage.setItem(key, JSON.stringify(state));
    }

    function resetRows(table) {
        Array.from(table.querySelectorAll(".table-row"))
            .sort((a, b) => Number(a.dataset.originalIndex) - Number(b.dataset.originalIndex))
            .forEach((row) => table.appendChild(row));
    }

    function exportCsv(table, title) {
        const headers = Array.from(table.querySelectorAll(".table-head > span")).map((cell) => cell.innerText.trim());
        const rows = visibleRows(table).map(cellText);
        const csv = [headers, ...rows].map((row) => row.map(csvEscape).join(",")).join("\n");
        download(`${title.replace(/[^\w\d-]+/g, "_")}.csv`, `\ufeff${csv}`);
    }

    function printTable(table, title) {
        const headers = Array.from(table.querySelectorAll(".table-head > span")).map((cell) => cell.innerText.trim());
        const rows = visibleRows(table).map(cellText);
        const win = window.open("", "_blank", "noopener,noreferrer");
        if (!win) return;

        const head = headers.map((header) => `<th>${header}</th>`).join("");
        const body = rows.map((row) => `<tr>${row.map((cell) => `<td>${cell}</td>`).join("")}</tr>`).join("");
        win.document.write(`
            <!doctype html>
            <html lang="es">
            <head>
                <meta charset="utf-8">
                <title>${title}</title>
                <style>
                    body { font-family: system-ui, sans-serif; color: #172026; }
                    h1 { font-size: 20px; }
                    table { border-collapse: collapse; width: 100%; }
                    th, td { border: 1px solid #d9e0e7; padding: 8px; text-align: left; vertical-align: top; }
                    th { background: #f3f5f7; }
                </style>
            </head>
            <body>
                <h1>${title}</h1>
                <table><thead><tr>${head}</tr></thead><tbody>${body}</tbody></table>
            </body>
            </html>
        `);
        win.document.close();
        win.focus();
        win.print();
    }

    function applyPagination(table, state, controls) {
        const rows = matchedRows(table);
        const pageSize = Number(state.pageSize || 10);
        const totalPages = Math.max(1, Math.ceil(rows.length / pageSize));
        const page = Math.min(Math.max(Number(state.page || 1), 1), totalPages);
        state.page = page;

        table.querySelectorAll(".table-row").forEach((row) => {
            row.style.display = "none";
        });
        rows.forEach((row, index) => {
            const visible = index >= (page - 1) * pageSize && index < page * pageSize;
            row.style.display = visible ? "" : "none";
        });

        const pageInfo = controls.querySelector("[data-dt-page-info]");
        const prev = controls.querySelector("[data-dt-prev]");
        const next = controls.querySelector("[data-dt-next]");
        if (pageInfo) pageInfo.textContent = `Pagina ${page} de ${totalPages}`;
        if (prev) prev.disabled = page <= 1;
        if (next) next.disabled = page >= totalPages;
    }

    function applyFilter(table, query, state, controls) {
        const q = normalize(query);
        let count = 0;
        table.querySelectorAll(".table-row").forEach((row) => {
            const match = normalize(row.innerText).includes(q);
            row.dataset.filtered = match ? "1" : "0";
            if (match) count += 1;
        });
        const counter = controls.querySelector("[data-dt-count]");
        if (counter) counter.textContent = `${count} filas`;
        applyPagination(table, state, controls);
    }

    function sortRows(table, columnIndex, direction) {
        const rows = Array.from(table.querySelectorAll(".table-row"));
        rows.sort((a, b) => {
            const av = normalize(a.children[columnIndex] ? a.children[columnIndex].innerText : "");
            const bv = normalize(b.children[columnIndex] ? b.children[columnIndex].innerText : "");
            return av.localeCompare(bv, "es-AR", { numeric: true }) * direction;
        });
        rows.forEach((row) => table.appendChild(row));
    }

    function setupTable(table) {
        const title = table.dataset.datatableTitle || "tabla";
        const key = storageKey(table, title);
        let state = readState(key);
        Array.from(table.querySelectorAll(".table-row")).forEach((row, index) => {
            row.dataset.originalIndex = String(index);
        });
        const controls = document.createElement("div");
        controls.className = "datatable-controls";
        controls.innerHTML = `
            <label class="datatable-search">
                <span class="sr-only">Buscar en tabla</span>
                <input type="search" placeholder="Buscar en esta tabla">
            </label>
            <span class="datatable-count" data-dt-count></span>
            <label class="datatable-page-size">
                <span class="sr-only">Filas por pagina</span>
                <select data-dt-page-size>
                    <option value="10">10 filas</option>
                    <option value="25">25 filas</option>
                    <option value="50">50 filas</option>
                    <option value="100">100 filas</option>
                </select>
            </label>
            <div class="datatable-actions">
                <button type="button" data-dt-export>Exportar Excel</button>
                <button type="button" data-dt-print>PDF</button>
                <button type="button" data-dt-reset>Reset</button>
            </div>
            <div class="datatable-pagination">
                <button type="button" data-dt-prev>Anterior</button>
                <span data-dt-page-info></span>
                <button type="button" data-dt-next>Siguiente</button>
            </div>
        `;
        table.parentNode.insertBefore(controls, table);

        const input = controls.querySelector("input");
        const pageSize = controls.querySelector("[data-dt-page-size]");
        state = { page: 1, pageSize: 10, ...state };
        input.value = state.query || "";
        pageSize.value = String(state.pageSize || 10);
        input.addEventListener("input", () => {
            state = { ...state, query: input.value, page: 1 };
            writeState(key, state);
            applyFilter(table, input.value, state, controls);
        });
        pageSize.addEventListener("change", () => {
            state = { ...state, pageSize: Number(pageSize.value), page: 1 };
            writeState(key, state);
            applyFilter(table, input.value, state, controls);
        });
        controls.querySelector("[data-dt-export]").addEventListener("click", () => exportCsv(table, title));
        controls.querySelector("[data-dt-print]").addEventListener("click", () => printTable(table, title));
        controls.querySelector("[data-dt-prev]").addEventListener("click", () => {
            state = { ...state, page: Math.max(1, Number(state.page || 1) - 1) };
            writeState(key, state);
            applyPagination(table, state, controls);
        });
        controls.querySelector("[data-dt-next]").addEventListener("click", () => {
            state = { ...state, page: Number(state.page || 1) + 1 };
            writeState(key, state);
            applyPagination(table, state, controls);
        });
        controls.querySelector("[data-dt-reset]").addEventListener("click", () => {
            state = { page: 1, pageSize: 10 };
            localStorage.removeItem(key);
            input.value = "";
            pageSize.value = "10";
            resetRows(table);
            table.querySelectorAll(".table-head > span").forEach((header) => {
                header.dataset.direction = "1";
                header.removeAttribute("aria-sort");
            });
            applyFilter(table, "", state, controls);
        });

        table.querySelectorAll(".table-head > span").forEach((header, index) => {
            header.setAttribute("role", "button");
            header.setAttribute("tabindex", "0");
            header.dataset.direction = "1";
            const activate = () => {
                const direction = Number(header.dataset.direction || "1");
                sortRows(table, index, direction);
                state = { ...state, sortColumn: index, sortDirection: direction, page: 1 };
                writeState(key, state);
                table.querySelectorAll(".table-head > span").forEach((item) => item.removeAttribute("aria-sort"));
                header.setAttribute("aria-sort", direction === 1 ? "ascending" : "descending");
                header.dataset.direction = String(direction * -1);
            };
            header.addEventListener("click", activate);
            header.addEventListener("keydown", (event) => {
                if (event.key === "Enter" || event.key === " ") {
                    event.preventDefault();
                    activate();
                }
            });
        });

        if (Number.isInteger(state.sortColumn)) {
            sortRows(table, state.sortColumn, state.sortDirection || 1);
            const header = table.querySelectorAll(".table-head > span")[state.sortColumn];
            if (header) {
                header.dataset.direction = String((state.sortDirection || 1) * -1);
                header.setAttribute("aria-sort", (state.sortDirection || 1) === 1 ? "ascending" : "descending");
            }
        }
        applyFilter(table, input.value, state, controls);
    }

    document.addEventListener("DOMContentLoaded", () => {
        document.querySelectorAll("[data-datatable]").forEach(setupTable);
    });
})();
