import { useMemo, type ReactNode } from 'react';
import {
  ChevronUp,
  ChevronDown,
  ChevronsUpDown,
  ChevronLeft,
  ChevronRight,
  ChevronsLeft,
  ChevronsRight,
} from 'lucide-react';
import { cn } from '@utils/cn';
import { Spinner } from '@components/atoms/Spinner';
import { Button } from '@components/atoms/Button';

export interface Column<T> {
  key: string;
  header: string;
  accessor?: keyof T | ((row: T) => ReactNode);
  sortable?: boolean;
  width?: string;
  align?: 'left' | 'center' | 'right';
  render?: (row: T) => ReactNode;
}

export interface DataTableProps<T> {
  data: T[];
  columns: Column<T>[];
  isLoading?: boolean;
  emptyMessage?: string;
  // Pagination
  pagination?: {
    page: number;
    limit: number;
    total: number;
    totalPages?: number;
    onPageChange: (page: number) => void;
    onLimitChange?: (limit: number) => void;
  };
  // Sorting
  sorting?: {
    sortBy: string | null;
    sortOrder: 'asc' | 'desc';
    onSort: (key: string) => void;
  };
  // Selection
  selection?: {
    selectedIds: Set<string>;
    onSelect: (id: string) => void;
    onSelectAll: () => void;
    getRowId: (row: T) => string;
  };
  // Row actions
  onRowClick?: (row: T) => void;
  rowClassName?: (row: T) => string;
  className?: string;
}

const alignClasses = {
  left: 'text-left',
  center: 'text-center',
  right: 'text-right',
};

export function DataTable<T>({
  data,
  columns,
  isLoading = false,
  emptyMessage = 'No hay datos disponibles',
  pagination,
  sorting,
  selection,
  onRowClick,
  rowClassName,
  className,
}: DataTableProps<T>) {
  const getCellValue = (row: T, column: Column<T>): ReactNode => {
    // If render function is provided, use it directly
    if (column.render) {
      return column.render(row);
    }

    // Otherwise, use accessor
    const accessor = column.accessor;
    if (!accessor) {
      return null;
    }

    if (typeof accessor === 'function') {
      return accessor(row);
    }

    return row[accessor] as ReactNode;
  };

  const renderSortIcon = (column: Column<T>) => {
    if (!column.sortable || !sorting) return null;

    if (sorting.sortBy !== column.key) {
      return <ChevronsUpDown className="ml-1 h-4 w-4 text-gray-400" />;
    }

    return sorting.sortOrder === 'asc' ? (
      <ChevronUp className="ml-1 h-4 w-4 text-primary-600" />
    ) : (
      <ChevronDown className="ml-1 h-4 w-4 text-primary-600" />
    );
  };

  const allSelected = useMemo(() => {
    if (!selection || data.length === 0) return false;
    return data.every((row) => selection.selectedIds.has(selection.getRowId(row)));
  }, [selection, data]);

  const someSelected = useMemo(() => {
    if (!selection || data.length === 0) return false;
    const selectedCount = data.filter((row) =>
      selection.selectedIds.has(selection.getRowId(row))
    ).length;
    return selectedCount > 0 && selectedCount < data.length;
  }, [selection, data]);

  const totalPages = pagination
    ? pagination.totalPages ?? Math.ceil(pagination.total / pagination.limit)
    : 1;

  return (
    <div className={cn('overflow-hidden rounded-lg border bg-white', className)}>
      <div className="overflow-x-auto">
        <table className="min-w-full divide-y divide-gray-200">
          <thead className="bg-gray-50">
            <tr>
              {/* Selection checkbox */}
              {selection && (
                <th className="w-12 px-4 py-3">
                  <input
                    type="checkbox"
                    checked={allSelected}
                    ref={(el) => {
                      if (el) el.indeterminate = someSelected;
                    }}
                    onChange={selection.onSelectAll}
                    className="h-4 w-4 rounded border-gray-300 text-primary-600 focus:ring-primary-500"
                  />
                </th>
              )}
              {columns.map((column) => (
                <th
                  key={column.key}
                  className={cn(
                    'px-4 py-3 text-xs font-medium uppercase tracking-wider text-gray-500',
                    alignClasses[column.align || 'left'],
                    column.sortable && sorting && 'cursor-pointer hover:bg-gray-100'
                  )}
                  style={{ width: column.width }}
                  onClick={() => {
                    if (column.sortable && sorting) {
                      sorting.onSort(column.key);
                    }
                  }}
                >
                  <div className={cn('flex items-center', column.align === 'right' && 'justify-end', column.align === 'center' && 'justify-center')}>
                    {column.header}
                    {renderSortIcon(column)}
                  </div>
                </th>
              ))}
            </tr>
          </thead>
          <tbody className="divide-y divide-gray-200 bg-white">
            {isLoading ? (
              <tr>
                <td
                  colSpan={columns.length + (selection ? 1 : 0)}
                  className="px-4 py-12 text-center"
                >
                  <div className="flex items-center justify-center">
                    <Spinner size="lg" />
                  </div>
                </td>
              </tr>
            ) : data.length === 0 ? (
              <tr>
                <td
                  colSpan={columns.length + (selection ? 1 : 0)}
                  className="px-4 py-12 text-center text-gray-500"
                >
                  {emptyMessage}
                </td>
              </tr>
            ) : (
              data.map((row, rowIndex) => {
                const rowId = selection ? selection.getRowId(row) : String(rowIndex);
                const isSelected = selection?.selectedIds.has(rowId);

                return (
                  <tr
                    key={rowId}
                    className={cn(
                      'transition-colors',
                      onRowClick && 'cursor-pointer hover:bg-gray-50',
                      isSelected && 'bg-primary-50',
                      rowClassName?.(row)
                    )}
                    onClick={() => onRowClick?.(row)}
                  >
                    {selection && (
                      <td className="w-12 px-4 py-3" onClick={(e) => e.stopPropagation()}>
                        <input
                          type="checkbox"
                          checked={isSelected}
                          onChange={() => selection.onSelect(rowId)}
                          className="h-4 w-4 rounded border-gray-300 text-primary-600 focus:ring-primary-500"
                        />
                      </td>
                    )}
                    {columns.map((column) => (
                      <td
                        key={column.key}
                        className={cn(
                          'whitespace-nowrap px-4 py-3 text-sm text-gray-900',
                          alignClasses[column.align || 'left']
                        )}
                      >
                        {getCellValue(row, column)}
                      </td>
                    ))}
                  </tr>
                );
              })
            )}
          </tbody>
        </table>
      </div>

      {/* Pagination */}
      {pagination && (
        <div className="flex items-center justify-between border-t bg-gray-50 px-4 py-3">
          <div className="flex items-center gap-2 text-sm text-gray-500">
            <span>
              Mostrando {Math.min((pagination.page - 1) * pagination.limit + 1, pagination.total)}{' '}
              - {Math.min(pagination.page * pagination.limit, pagination.total)} de{' '}
              {pagination.total}
            </span>
            {pagination.onLimitChange && (
              <select
                value={pagination.limit}
                onChange={(e) => pagination.onLimitChange?.(Number(e.target.value))}
                className="rounded border-gray-300 text-sm focus:border-primary-500 focus:ring-primary-500"
              >
                <option value={10}>10</option>
                <option value={25}>25</option>
                <option value={50}>50</option>
                <option value={100}>100</option>
              </select>
            )}
          </div>

          <div className="flex items-center gap-1">
            <Button
              variant="outline"
              size="sm"
              onClick={() => pagination.onPageChange(1)}
              disabled={pagination.page === 1}
            >
              <ChevronsLeft className="h-4 w-4" />
            </Button>
            <Button
              variant="outline"
              size="sm"
              onClick={() => pagination.onPageChange(pagination.page - 1)}
              disabled={pagination.page === 1}
            >
              <ChevronLeft className="h-4 w-4" />
            </Button>
            <span className="px-3 text-sm text-gray-600">
              {pagination.page} / {totalPages}
            </span>
            <Button
              variant="outline"
              size="sm"
              onClick={() => pagination.onPageChange(pagination.page + 1)}
              disabled={pagination.page >= totalPages}
            >
              <ChevronRight className="h-4 w-4" />
            </Button>
            <Button
              variant="outline"
              size="sm"
              onClick={() => pagination.onPageChange(totalPages)}
              disabled={pagination.page >= totalPages}
            >
              <ChevronsRight className="h-4 w-4" />
            </Button>
          </div>
        </div>
      )}
    </div>
  );
}
