'use client';

import { useState, useMemo, useEffect } from 'react';
import { ChevronUp, ChevronDown, Search, Download, Eye, Loader2, Trash2 } from 'lucide-react';
import { Input } from './input';
import { Button } from './button';
import { EmptyState, NoSearchResults } from './empty-state';
import { cn } from '../../lib/utils';

export interface Column<T> {
    key: keyof T | string;
    label: string;
    sortable?: boolean;
    render?: (row: T) => React.ReactNode;
    className?: string;
}

interface DataTableProps<T> {
    columns: Column<T>[];
    data: T[];
    searchable?: boolean;
    exportable?: boolean;
    onRowClick?: (row: T) => void;
    emptyMessage?: string;
    pageSize?: number;
    // Server-side props
    serverSide?: boolean;
    pageCount?: number;
    currentPage?: number;
    onPageChange?: (page: number) => void;
    isLoading?: boolean;
    onSearch?: (query: string) => void;
    // Selection props
    selectable?: boolean;
    onSelectionChange?: (selectedRows: T[]) => void;
    // Bulk actions
    bulkActions?: {
        label: string;
        icon?: React.ElementType;
        onClick: (selectedRows: T[]) => void;
        variant?: 'primary' | 'secondary' | 'danger';
    }[];
}

export function DataTable<T extends Record<string, any>>({
    columns,
    data,
    searchable = false,
    exportable = false,
    onRowClick,
    emptyMessage = 'No data available',
    pageSize = 10,
    serverSide = false,
    pageCount = 1,
    currentPage = 1,
    onPageChange,
    isLoading = false,
    onSearch,
    selectable = false,
    onSelectionChange,
    bulkActions = [],
}: DataTableProps<T>) {
    const [search, setSearch] = useState('');
    const [sortKey, setSortKey] = useState<string | null>(null);
    const [sortDirection, setSortDirection] = useState<'asc' | 'desc'>('asc');
    const [internalPage, setInternalPage] = useState(1);
    const [hiddenColumns, setHiddenColumns] = useState<Set<string>>(new Set());
    const [selectedRowIds, setSelectedRowIds] = useState<Set<string | number>>(new Set());

    const activePage = serverSide ? currentPage : internalPage;
    const activePageCount = serverSide ? pageCount : Math.ceil(data.length / pageSize);

    // Debounce search for server-side
    useEffect(() => {
        if (serverSide && onSearch) {
            const timer = setTimeout(() => {
                onSearch(search);
            }, 500);
            return () => clearTimeout(timer);
        }
    }, [search, serverSide, onSearch]);

    // Filter data based on search (client-side only)
    const filteredData = useMemo(() => {
        if (serverSide) return data;
        if (!search) return data;

        return data.filter((row) =>
            Object.values(row).some((value) =>
                String(value).toLowerCase().includes(search.toLowerCase())
            )
        );
    }, [data, search, serverSide]);

    // Sort data (client-side only)
    const sortedData = useMemo(() => {
        if (serverSide) return filteredData;
        if (!sortKey) return filteredData;

        return [...filteredData].sort((a, b) => {
            const aVal = a[sortKey];
            const bVal = b[sortKey];

            if (aVal === bVal) return 0;

            const comparison = aVal < bVal ? -1 : 1;
            return sortDirection === 'asc' ? comparison : -comparison;
        });
    }, [filteredData, sortKey, sortDirection, serverSide]);

    // Paginate data (client-side only)
    const paginatedData = useMemo(() => {
        if (serverSide) return data;
        const start = (internalPage - 1) * pageSize;
        return sortedData.slice(start, start + pageSize);
    }, [sortedData, internalPage, pageSize, serverSide, data]);

    // Handle sorting
    const handleSort = (key: string) => {
        if (sortKey === key) {
            setSortDirection(sortDirection === 'asc' ? 'desc' : 'asc');
        } else {
            setSortKey(key);
            setSortDirection('asc');
        }
    };

    // Handle selection
    const toggleSelectAll = () => {
        if (selectedRowIds.size === paginatedData.length && paginatedData.length > 0) {
            setSelectedRowIds(new Set());
            onSelectionChange?.([]);
        } else {
            const newSelected = new Set(paginatedData.map(row => row.id));
            setSelectedRowIds(newSelected);
            onSelectionChange?.(paginatedData);
        }
    };

    const toggleSelectRow = (row: T) => {
        const newSelected = new Set(selectedRowIds);
        if (newSelected.has(row.id)) {
            newSelected.delete(row.id);
        } else {
            newSelected.add(row.id);
        }
        setSelectedRowIds(newSelected);

        const selectedRows = paginatedData.filter(r => newSelected.has(r.id));
        onSelectionChange?.(selectedRows);
    };

    // Export to CSV
    const handleExport = () => {
        const rowsToExport = selectedRowIds.size > 0
            ? paginatedData.filter(r => selectedRowIds.has(r.id))
            : sortedData;

        const csv = [
            columns.filter(c => !hiddenColumns.has(String(c.key))).map((c) => c.label).join(','),
            ...rowsToExport.map((row) =>
                columns
                    .filter(c => !hiddenColumns.has(String(c.key)))
                    .map((c) => {
                        const value = row[c.key as keyof T];
                        return typeof value === 'string' && value.includes(',')
                            ? `"${value}"`
                            : value;
                    })
                    .join(',')
            ),
        ].join('\n');

        const blob = new Blob([csv], { type: 'text/csv' });
        const url = URL.createObjectURL(blob);
        const a = document.createElement('a');
        a.href = url;
        a.download = `export-${Date.now()}.csv`;
        a.click();
    };

    // Toggle column visibility
    const toggleColumn = (key: string) => {
        const newHidden = new Set(hiddenColumns);
        if (newHidden.has(key)) {
            newHidden.delete(key);
        } else {
            newHidden.add(key);
        }
        setHiddenColumns(newHidden);
    };

    const visibleColumns = columns.filter((c) => !hiddenColumns.has(String(c.key)));

    if (!isLoading && data.length === 0 && !search) {
        return <EmptyState title={emptyMessage} icon="inbox" />;
    }

    return (
        <div className="space-y-4">
            {/* Toolbar */}
            <div className="flex flex-wrap items-center justify-between gap-4">
                {searchable && (
                    <div className="flex-1 max-w-sm">
                        <div className="relative">
                            <Search className="absolute left-3 top-1/2 h-4 w-4 -translate-y-1/2 text-slate-400" />
                            <input
                                type="text"
                                placeholder="Search..."
                                value={search}
                                onChange={(e) => setSearch(e.target.value)}
                                className="h-10 w-full rounded-lg border border-slate-200 pl-9 pr-4 text-sm focus:border-brand focus:outline-none focus:ring-2 focus:ring-brand/20 dark:border-slate-700 dark:bg-slate-900 dark:text-white"
                            />
                        </div>
                    </div>
                )}

                <div className="flex items-center gap-2">
                    {selectedRowIds.size > 0 && bulkActions.map((action, idx) => (
                        <Button
                            key={idx}
                            variant={action.variant || 'secondary'}
                            size="sm"
                            onClick={() => action.onClick(paginatedData.filter(r => selectedRowIds.has(r.id)))}
                        >
                            {action.icon && <action.icon className="h-4 w-4 mr-1" />}
                            {action.label} ({selectedRowIds.size})
                        </Button>
                    ))}

                    {/* Column visibility toggle */}
                    <div className="relative group">
                        <Button variant="outline" size="sm">
                            <Eye className="h-4 w-4 mr-1" />
                            Columns
                        </Button>
                        <div className="absolute right-0 top-full mt-2 w-48 rounded-lg border border-slate-200 bg-white p-2 shadow-lg opacity-0 invisible group-hover:opacity-100 group-hover:visible transition-all z-10 dark:border-slate-700 dark:bg-slate-900">
                            {columns.map((col) => (
                                <label
                                    key={String(col.key)}
                                    className="flex items-center gap-2 p-2 hover:bg-slate-50 rounded cursor-pointer dark:hover:bg-slate-800"
                                >
                                    <input
                                        type="checkbox"
                                        checked={!hiddenColumns.has(String(col.key))}
                                        onChange={() => toggleColumn(String(col.key))}
                                        className="rounded"
                                    />
                                    <span className="text-sm">{col.label}</span>
                                </label>
                            ))}
                        </div>
                    </div>

                    {exportable && (
                        <Button variant="outline" size="sm" onClick={handleExport}>
                            <Download className="h-4 w-4 mr-1" />
                            Export CSV
                        </Button>
                    )}
                </div>
            </div>

            {/* Table */}
            <div className="overflow-x-auto rounded-lg border border-slate-200 dark:border-slate-700 relative">
                {isLoading && (
                    <div className="absolute inset-0 bg-white/50 dark:bg-slate-900/50 z-10 flex items-center justify-center backdrop-blur-sm">
                        <Loader2 className="h-8 w-8 animate-spin text-brand" />
                    </div>
                )}
                <table className="w-full">
                    <thead className="bg-slate-50 dark:bg-slate-800">
                        <tr>
                            {selectable && (
                                <th className="px-6 py-3 w-4">
                                    <input
                                        type="checkbox"
                                        checked={selectedRowIds.size === paginatedData.length && paginatedData.length > 0}
                                        onChange={toggleSelectAll}
                                        className="rounded border-slate-300 text-brand focus:ring-brand"
                                    />
                                </th>
                            )}
                            {visibleColumns.map((column) => (
                                <th
                                    key={String(column.key)}
                                    className={`px-6 py-3 text-left text-xs font-semibold uppercase tracking-wider text-slate-600 dark:text-slate-300 ${column.sortable ? 'cursor-pointer select-none hover:bg-slate-100 dark:hover:bg-slate-700' : ''
                                        } ${column.className || ''}`}
                                    onClick={() => column.sortable && handleSort(String(column.key))}
                                >
                                    <div className="flex items-center gap-2">
                                        {column.label}
                                        {column.sortable && sortKey === column.key && (
                                            sortDirection === 'asc' ? (
                                                <ChevronUp className="h-4 w-4" />
                                            ) : (
                                                <ChevronDown className="h-4 w-4" />
                                            )
                                        )}
                                    </div>
                                </th>
                            ))}
                        </tr>
                    </thead>
                    <tbody className="divide-y divide-slate-200 bg-white dark:divide-slate-700 dark:bg-slate-900">
                        {paginatedData.length === 0 && !isLoading ? (
                            <tr>
                                <td colSpan={visibleColumns.length + (selectable ? 1 : 0)} className="px-6 py-8 text-center text-slate-500">
                                    No results found
                                </td>
                            </tr>
                        ) : (
                            paginatedData.map((row, index) => (
                                <tr
                                    key={row.id || index}
                                    onClick={() => onRowClick?.(row)}
                                    className={`transition-colors ${onRowClick
                                        ? 'cursor-pointer hover:bg-slate-50 dark:hover:bg-slate-800'
                                        : ''
                                        } ${selectedRowIds.has(row.id) ? 'bg-brand/5' : ''}`}
                                >
                                    {selectable && (
                                        <td className="px-6 py-4" onClick={(e) => e.stopPropagation()}>
                                            <input
                                                type="checkbox"
                                                checked={selectedRowIds.has(row.id)}
                                                onChange={() => toggleSelectRow(row)}
                                                className="rounded border-slate-300 text-brand focus:ring-brand"
                                            />
                                        </td>
                                    )}
                                    {visibleColumns.map((column) => (
                                        <td
                                            key={String(column.key)}
                                            className="px-6 py-4 text-sm text-slate-900 dark:text-slate-100"
                                        >
                                            {column.render
                                                ? column.render(row)
                                                : (row[column.key as keyof T] as React.ReactNode)}
                                        </td>
                                    ))}
                                </tr>
                            ))
                        )}
                    </tbody>
                </table>
            </div>

            {/* Pagination */}
            {activePageCount > 1 && (
                <div className="flex items-center justify-between">
                    <p className="text-sm text-slate-600 dark:text-slate-400">
                        Page {activePage} of {activePageCount}
                    </p>
                    <div className="flex gap-2">
                        <Button
                            variant="outline"
                            size="sm"
                            onClick={() => {
                                if (serverSide && onPageChange) {
                                    onPageChange(activePage - 1);
                                } else {
                                    setInternalPage((p) => Math.max(1, p - 1));
                                }
                            }}
                            disabled={activePage === 1 || isLoading}
                        >
                            Previous
                        </Button>
                        <div className="flex items-center gap-1">
                            {Array.from({ length: Math.min(activePageCount, 5) }, (_, i) => {
                                let pageNum;
                                if (activePageCount <= 5) {
                                    pageNum = i + 1;
                                } else if (activePage <= 3) {
                                    pageNum = i + 1;
                                } else if (activePage >= activePageCount - 2) {
                                    pageNum = activePageCount - 4 + i;
                                } else {
                                    pageNum = activePage - 2 + i;
                                }

                                return (
                                    <button
                                        key={i}
                                        onClick={() => {
                                            if (serverSide && onPageChange) {
                                                onPageChange(pageNum);
                                            } else {
                                                setInternalPage(pageNum);
                                            }
                                        }}
                                        className={`h-8 w-8 rounded text-sm font-medium transition-colors ${activePage === pageNum
                                            ? 'bg-brand text-white'
                                            : 'hover:bg-slate-100 dark:hover:bg-slate-800'
                                            }`}
                                        disabled={isLoading}
                                    >
                                        {pageNum}
                                    </button>
                                );
                            })}
                        </div>
                        <Button
                            variant="outline"
                            size="sm"
                            onClick={() => {
                                if (serverSide && onPageChange) {
                                    onPageChange(activePage + 1);
                                } else {
                                    setInternalPage((p) => Math.min(activePageCount, p + 1));
                                }
                            }}
                            disabled={activePage === activePageCount || isLoading}
                        >
                            Next
                        </Button>
                    </div>
                </div>
            )}
        </div>
    );
}
