/**
 * Table optimisée avec lazy loading et virtualisation
 */

import React, { memo, useCallback, useMemo } from 'react';
import { Table, TableBody, TableCell, TableHead, TableHeader, TableRow } from '@/components/ui/table';
import { Button } from '@/components/ui/button';
import { Badge } from '@/components/ui/badge';
import { ChevronLeft, ChevronRight, MoreHorizontal } from 'lucide-react';

export interface LazyTableColumn<T> {
  key: keyof T | string;
  header: string;
  render?: (value: any, item: T, index: number) => React.ReactNode;
  sortable?: boolean;
  width?: string;
}

export interface LazyTableProps<T> {
  data: T[];
  columns: LazyTableColumn<T>[];
  loading?: boolean;
  pagination?: {
    page: number;
    limit: number;
    total: number;
    totalPages: number;
    hasNext: boolean;
    hasPrev: boolean;
  };
  onPageChange?: (page: number) => void;
  onSort?: (column: keyof T, direction: 'asc' | 'desc') => void;
  itemHeight?: number;
  maxHeight?: string;
  emptyMessage?: string;
  loadingRows?: number;
}

/**
 * Ligne de tableau mémorisée pour éviter les re-renders
 */
const TableRowMemo = memo(<T,>({ 
  item, 
  columns, 
  index 
}: { 
  item: T; 
  columns: LazyTableColumn<T>[]; 
  index: number;
}) => {
  return (
    <TableRow key={`row-${index}`} data-testid={`table-row-${index}`}>
      {columns.map((column, colIndex) => {
        const value = typeof column.key === 'string' && column.key.includes('.') 
          ? column.key.split('.').reduce((obj: any, key) => obj?.[key], item)
          : (item as any)[column.key];

        return (
          <TableCell 
            key={`cell-${index}-${colIndex}`}
            style={{ width: column.width }}
          >
            {column.render ? column.render(value, item, index) : String(value)}
          </TableCell>
        );
      })}
    </TableRow>
  );
});

TableRowMemo.displayName = 'TableRowMemo';

/**
 * Skeleton pour les lignes en chargement
 */
const LoadingRow = memo(<T,>({ columns }: { columns: LazyTableColumn<T>[] }) => (
  <TableRow>
    {columns.map((_, index) => (
      <TableCell key={`loading-${index}`}>
        <div className="h-4 bg-gray-200 rounded animate-pulse" />
      </TableCell>
    ))}
  </TableRow>
));

(LoadingRow as any).displayName = 'LoadingRow';

/**
 * Composant de pagination optimisé
 */
const PaginationControls = memo(({ 
  pagination, 
  onPageChange 
}: { 
  pagination: LazyTableProps<any>['pagination'];
  onPageChange?: (page: number) => void;
}) => {
  if (!pagination || !onPageChange) return null;

  const { page, totalPages, hasNext, hasPrev } = pagination;
  
  const handlePageChange = useCallback((newPage: number) => {
    if (newPage >= 1 && newPage <= totalPages) {
      onPageChange(newPage);
    }
  }, [onPageChange, totalPages]);

  // Générer les numéros de pages visibles
  const getVisiblePages = useMemo(() => {
    const delta = 2;
    const range = [];
    const rangeWithDots = [];

    for (let i = Math.max(2, page - delta); i <= Math.min(totalPages - 1, page + delta); i++) {
      range.push(i);
    }

    if (page - delta > 2) {
      rangeWithDots.push(1, '...');
    } else {
      rangeWithDots.push(1);
    }

    rangeWithDots.push(...range);

    if (page + delta < totalPages - 1) {
      rangeWithDots.push('...', totalPages);
    } else {
      if (totalPages > 1) {
        rangeWithDots.push(totalPages);
      }
    }

    return rangeWithDots;
  }, [page, totalPages]);

  return (
    <div className="flex items-center justify-between px-2">
      <div className="flex items-center space-x-6 lg:space-x-8">
        <div className="flex items-center space-x-2">
          <p className="text-sm font-medium">
            Page {page} sur {totalPages}
          </p>
        </div>
      </div>
      
      <div className="flex items-center space-x-2">
        <Button
          variant="outline"
          size="sm"
          onClick={() => handlePageChange(page - 1)}
          disabled={!hasPrev}
          data-testid="prev-page"
        >
          <ChevronLeft className="h-4 w-4" />
          Précédent
        </Button>

        <div className="flex items-center space-x-1">
          {getVisiblePages.map((pageNum, index) => (
            <React.Fragment key={index}>
              {pageNum === '...' ? (
                <Button variant="outline" size="sm" disabled>
                  <MoreHorizontal className="h-4 w-4" />
                </Button>
              ) : (
                <Button
                  variant={pageNum === page ? "default" : "outline"}
                  size="sm"
                  onClick={() => handlePageChange(Number(pageNum))}
                  data-testid={`page-${pageNum}`}
                >
                  {pageNum}
                </Button>
              )}
            </React.Fragment>
          ))}
        </div>

        <Button
          variant="outline"
          size="sm"
          onClick={() => handlePageChange(page + 1)}
          disabled={!hasNext}
          data-testid="next-page"
        >
          Suivant
          <ChevronRight className="h-4 w-4" />
        </Button>
      </div>
    </div>
  );
});

PaginationControls.displayName = 'PaginationControls';

/**
 * Table principale optimisée
 */
export function LazyTable<T>({
  data,
  columns,
  loading = false,
  pagination,
  onPageChange,
  onSort,
  itemHeight = 48,
  maxHeight = '600px',
  emptyMessage = 'Aucune donnée disponible',
  loadingRows = 5
}: LazyTableProps<T>) {
  
  // Mémoiser les colonnes pour éviter les re-renders
  const memoizedColumns = useMemo(() => columns, [columns]);
  
  // Mémoiser les données pour éviter les re-calculs
  const memoizedData = useMemo(() => data, [data]);
  
  // Callback mémorisé pour le tri
  const handleSort = useCallback((column: LazyTableColumn<T>) => {
    if (column.sortable && onSort) {
      // Logique de tri simple - peut être étendue
      onSort(column.key as keyof T, 'asc');
    }
  }, [onSort]);

  // Rendu des lignes de données
  const renderRows = useMemo(() => {
    if (loading) {
      return Array.from({ length: loadingRows }, (_, index) => (
        <LoadingRow<T> key={`loading-${index}`} columns={memoizedColumns} />
      ));
    }

    if (memoizedData.length === 0) {
      return (
        <TableRow>
          <TableCell colSpan={memoizedColumns.length} className="text-center py-8">
            <div className="text-gray-500">
              {emptyMessage}
            </div>
          </TableCell>
        </TableRow>
      );
    }

    return memoizedData.map((item, index) => (
      <TableRowMemo
        key={`item-${index}`}
        item={item}
        columns={memoizedColumns}
        index={index}
      />
    ));
  }, [loading, memoizedData, memoizedColumns, loadingRows, emptyMessage]);

  return (
    <div className="space-y-4">
      {/* Table avec hauteur maximale et scroll */}
      <div className="rounded-md border">
        <div style={{ maxHeight }} className="overflow-auto">
          <Table>
            <TableHeader>
              <TableRow>
                {memoizedColumns.map((column, index) => (
                  <TableHead 
                    key={`header-${index}`}
                    className={column.sortable ? "cursor-pointer select-none hover:bg-gray-50" : ""}
                    onClick={() => column.sortable && handleSort(column)}
                    style={{ width: column.width }}
                  >
                    <div className="flex items-center space-x-1">
                      <span>{column.header}</span>
                      {column.sortable && (
                        <Badge variant="outline" className="ml-1 text-xs">
                          ↕
                        </Badge>
                      )}
                    </div>
                  </TableHead>
                ))}
              </TableRow>
            </TableHeader>
            <TableBody>
              {renderRows}
            </TableBody>
          </Table>
        </div>
      </div>

      {/* Pagination */}
      {pagination && (
        <PaginationControls 
          pagination={pagination} 
          onPageChange={onPageChange} 
        />
      )}
    </div>
  );
}

export default memo(LazyTable) as typeof LazyTable;