import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
import { Icon } from "@powerhousedao/design-system";
import { useState } from "react";
import { twMerge } from "tailwind-merge";
import { FilterBar } from "./filter-bar.js";
function formatCellValue(value) {
    if (value === null)
        return "NULL";
    if (value === undefined)
        return "";
    if (typeof value === "object")
        return JSON.stringify(value);
    if (typeof value === "function")
        return "[function]";
    if (typeof value === "symbol")
        return value.toString();
    return String(value);
}
function escapeCsvValue(value) {
    // If the value contains comma, newline, or double quote, wrap it in quotes and escape quotes
    if (value.includes(",") || value.includes("\n") || value.includes('"')) {
        return `"${value.replace(/"/g, '""')}"`;
    }
    return value;
}
function rowToCsv(row, columns) {
    return columns
        .map((column) => {
        const value = formatCellValue(row[column.name]);
        return escapeCsvValue(value);
    })
        .join(",");
}
function rowsToCsv(rows, columns) {
    const header = columns.map((col) => escapeCsvValue(col.name)).join(",");
    const dataRows = rows.map((row) => rowToCsv(row, columns));
    return [header, ...dataRows].join("\n");
}
async function copyToClipboard(text) {
    await navigator.clipboard.writeText(text);
}
function SortIcon({ direction, active, }) {
    if (!active) {
        return (_jsx(Icon, { className: "opacity-0 group-hover:opacity-50", name: "CaretSort", size: 12 }));
    }
    return (_jsx(Icon, { className: direction === "asc" ? "rotate-180" : undefined, name: "TriangleDown", size: 12 }));
}
export function TableView({ columns, rows, pagination, onPageChange, onSort, currentSort, loading = false, filters, onFiltersChange, }) {
    const { offset, limit, total } = pagination;
    const currentPage = Math.floor(offset / limit);
    const totalPages = total !== null ? Math.ceil(total / limit) : 0;
    const startItem = total === 0 ? 0 : offset + 1;
    const endItem = total !== null ? Math.min(offset + limit, total) : offset + rows.length;
    const goToPage = (page) => {
        onPageChange(page * limit);
    };
    const handleSort = (columnName) => {
        if (!onSort)
            return;
        const newDirection = currentSort?.column === columnName && currentSort.direction === "asc"
            ? "desc"
            : "asc";
        onSort({ column: columnName, direction: newDirection });
    };
    const getVisiblePages = () => {
        const maxVisible = 3;
        if (totalPages <= maxVisible) {
            return Array.from({ length: totalPages }, (_, i) => i);
        }
        const start = Math.max(0, Math.min(currentPage - 1, totalPages - maxVisible));
        const end = Math.min(totalPages - 1, start + maxVisible - 1);
        const pages = [];
        for (let i = start; i <= end; i++) {
            pages.push(i);
        }
        return pages;
    };
    const visiblePages = getVisiblePages();
    const [copying, setCopying] = useState(false);
    const [copiedRowIndex, setCopiedRowIndex] = useState(null);
    const handleCopyAll = async () => {
        if (rows.length === 0)
            return;
        setCopying(true);
        try {
            const csv = rowsToCsv(rows, columns);
            await copyToClipboard(csv);
            setTimeout(() => setCopying(false), 1000);
        }
        catch (err) {
            console.error("Failed to copy to clipboard:", err);
            setCopying(false);
        }
    };
    const handleCopyRow = async (rowIndex) => {
        if (rowIndex < 0 || rowIndex >= rows.length)
            return;
        setCopiedRowIndex(rowIndex);
        try {
            const csv = rowToCsv(rows[rowIndex], columns);
            await copyToClipboard(csv);
            setTimeout(() => setCopiedRowIndex(null), 1000);
        }
        catch (err) {
            console.error("Failed to copy to clipboard:", err);
            setCopiedRowIndex(null);
        }
    };
    return (_jsxs("div", { className: "flex h-full flex-col gap-2", children: [onFiltersChange && (_jsx(FilterBar, { columns: columns, filters: filters, onFiltersChange: onFiltersChange })), _jsxs("div", { className: "flex shrink-0 items-center justify-between text-sm", children: [_jsxs("div", { className: "flex items-center gap-2", children: [_jsx("span", { className: "text-gray-600", children: loading
                                    ? "Loading..."
                                    : total !== null
                                        ? `Showing ${startItem.toLocaleString()}-${endItem.toLocaleString()} of ${total.toLocaleString()}`
                                        : `Showing ${rows.length.toLocaleString()} rows` }), rows.length > 0 && (_jsxs("button", { className: "flex items-center gap-1 rounded border border-gray-300 bg-white px-2 py-1 text-xs text-gray-700 hover:bg-gray-100 disabled:cursor-not-allowed disabled:opacity-50", disabled: loading || copying, onClick: handleCopyAll, title: "Copy all rows as CSV", type: "button", children: [_jsx(Icon, { name: copying ? "Check" : "Copy", size: 14 }), copying ? "Copied!" : "Copy All"] }))] }), total !== null && total > limit && (_jsxs("div", { className: "flex gap-1", children: [_jsx("button", { className: "rounded border border-gray-300 bg-white px-2 py-1 text-xs text-gray-700 hover:bg-gray-100 disabled:cursor-not-allowed disabled:opacity-50", disabled: currentPage === 0, onClick: () => goToPage(0), type: "button", children: "First" }), _jsx("button", { className: "rounded border border-gray-300 bg-white px-2 py-1 text-xs text-gray-700 hover:bg-gray-100 disabled:cursor-not-allowed disabled:opacity-50", disabled: currentPage === 0, onClick: () => goToPage(currentPage - 1), type: "button", children: _jsx(Icon, { className: "rotate-90", name: "ChevronDown", size: 14 }) }), visiblePages[0] > 0 && (_jsx("span", { className: "flex items-center px-1 text-xs text-gray-500", children: "..." })), visiblePages.map((page) => (_jsx("button", { className: twMerge("min-w-8 rounded border px-2 py-1 text-xs", page === currentPage
                                    ? "border-blue-500 bg-blue-50 text-blue-700"
                                    : "border-gray-300 bg-white text-gray-700 hover:bg-gray-100"), onClick: () => goToPage(page), type: "button", children: page + 1 }, page))), visiblePages[visiblePages.length - 1] < totalPages - 1 && (_jsx("span", { className: "flex items-center px-1 text-xs text-gray-500", children: "..." })), _jsx("button", { className: "rounded border border-gray-300 bg-white px-2 py-1 text-xs text-gray-700 hover:bg-gray-100 disabled:cursor-not-allowed disabled:opacity-50", disabled: currentPage >= totalPages - 1, onClick: () => goToPage(currentPage + 1), type: "button", children: _jsx(Icon, { className: "-rotate-90", name: "ChevronDown", size: 14 }) }), _jsx("button", { className: "rounded border border-gray-300 bg-white px-2 py-1 text-xs text-gray-700 hover:bg-gray-100 disabled:cursor-not-allowed disabled:opacity-50", disabled: currentPage >= totalPages - 1, onClick: () => goToPage(totalPages - 1), type: "button", children: "Last" })] }))] }), _jsx("div", { className: twMerge("max-h-full overflow-auto rounded-lg border border-gray-300 transition-opacity", loading && "pointer-events-none opacity-50"), children: _jsxs("table", { className: "w-full border-collapse", children: [_jsx("thead", { className: "sticky top-0 bg-gray-100", children: _jsxs("tr", { children: [_jsx("th", { className: "w-12 px-2 py-2 text-center text-xs font-medium text-gray-600", children: _jsx("span", { className: "sr-only", children: "Copy" }) }), columns.map((column, index) => {
                                        const isActive = currentSort?.column === column.name;
                                        const sortDirection = isActive ? currentSort.direction : "asc";
                                        return (_jsx("th", { className: twMerge("group px-3 py-2 text-left text-xs font-medium text-gray-600", index > 0 && "border-l border-gray-300", onSort &&
                                                "cursor-pointer hover:bg-gray-200 hover:text-gray-900"), onClick: () => onSort && handleSort(column.name), children: _jsxs("div", { className: "flex items-center gap-1", children: [_jsx("span", { className: "truncate", children: column.name }), onSort && (_jsx(SortIcon, { active: isActive, direction: sortDirection }))] }) }, column.name));
                                    })] }) }), _jsx("tbody", { children: rows.length === 0 ? (_jsx("tr", { children: _jsx("td", { className: "px-3 py-8 text-center text-sm text-gray-500", colSpan: columns.length + 1, children: "No data" }) })) : (rows.map((row, rowIndex) => (_jsxs("tr", { className: "odd:bg-white even:bg-gray-50 hover:bg-blue-50", children: [_jsx("td", { className: "px-2 py-2 text-center", children: _jsx("button", { className: "flex items-center justify-center rounded p-1 text-gray-500 hover:bg-gray-200 hover:text-gray-700", onClick: () => void handleCopyRow(rowIndex), title: "Copy row as CSV", type: "button", children: _jsx(Icon, { name: copiedRowIndex === rowIndex ? "Check" : "Copy", size: 14 }) }) }), columns.map((column, colIndex) => (_jsx("td", { className: twMerge("px-3 py-2 text-xs text-gray-900", colIndex > 0 && "border-l border-gray-300"), children: _jsx("span", { className: twMerge("block truncate", row[column.name] === null && "italic text-gray-400"), title: formatCellValue(row[column.name]), children: formatCellValue(row[column.name]) }) }, column.name)))] }, rowIndex)))) })] }) })] }));
}
//# sourceMappingURL=table-view.js.map