import { useState, useMemo, useCallback } from 'react';
import { Checkbox } from '@/components/ui/checkbox';
import { Pagination } from '@/components/navigation/Pagination';
import { cn } from '@/lib/utils';
import { ArrowUpDown, ArrowUp, ArrowDown } from 'lucide-react';

export interface TableColumn<T> {
  key: string;
  header: string;
  render?: (row: T, index: number) => React.ReactNode;
  sortable?: boolean;
  width?: string;
  align?: 'left' | 'center' | 'right';
}

export interface TableProps<T> {
  columns: TableColumn<T>[];
  data: T[];
  onSort?: (column: string, direction: 'asc' | 'desc') => void;
  onRowClick?: (row: T, index: number) => void;
  selectable?: boolean;
  onSelectionChange?: (selectedRows: T[]) => void;
  getRowId?: (row: T, index: number) => string;
  paginated?: boolean;
  itemsPerPage?: number;
  emptyMessage?: string;
  className?: string;
  rowClassName?: (row: T, index: number) => string;
  // CRITIQUE FIX #40: Ajouter aria-label pour l'accessibilité
  'aria-label'?: string;
  'aria-labelledby'?: string;
}

/**
 * Composant Table avec tri, pagination, sélection, et actions.
 */
export function Table<T extends Record<string, any>>({
  columns,
  data,
  onSort,
  onRowClick,
  selectable = false,
  onSelectionChange,
  getRowId,
  paginated = false,
  itemsPerPage = 10,
  emptyMessage = 'Aucune donnée disponible',
  className,
  rowClassName,
  'aria-label': ariaLabel,
  'aria-labelledby': ariaLabelledBy,
}: TableProps<T>) {
  const [selectedRows, setSelectedRows] = useState<Set<string>>(new Set());
  const [sortColumn, setSortColumn] = useState<string | null>(null);
  const [sortDirection, setSortDirection] = useState<'asc' | 'desc'>('asc');
  const [currentPage, setCurrentPage] = useState(1);

  const getRowKey = useCallback(
    (row: T, index: number): string => {
      if (getRowId) {
        return getRowId(row, index);
      }
      return index.toString();
    },
    [getRowId],
  );

  const handleSort = useCallback(
    (columnKey: string) => {
      const column = columns.find((col) => col.key === columnKey);
      if (!column?.sortable) return;

      let newDirection: 'asc' | 'desc' = 'asc';
      if (sortColumn === columnKey) {
        newDirection = sortDirection === 'asc' ? 'desc' : 'asc';
      }

      setSortColumn(columnKey);
      setSortDirection(newDirection);
      onSort?.(columnKey, newDirection);
    },
    [columns, sortColumn, sortDirection, onSort],
  );

  const handleSelectAll = useCallback(
    (checked: boolean) => {
      const paginatedData = paginated ? paginatedDataMemo : data;
      const newSelected = new Set<string>();

      if (checked) {
        paginatedData.forEach((row, index) => {
          const absoluteIndex = paginated
            ? (currentPage - 1) * itemsPerPage + index
            : index;
          newSelected.add(getRowKey(row, absoluteIndex));
        });
      }

      setSelectedRows(newSelected);
      if (onSelectionChange) {
        const selectedData = data.filter((row, index) =>
          newSelected.has(getRowKey(row, index)),
        );
        onSelectionChange(selectedData);
      }
    },
    [data, paginated, currentPage, itemsPerPage, getRowKey, onSelectionChange],
  );

  const handleSelectRow = useCallback(
    (row: T, index: number, checked: boolean) => {
      const rowKey = getRowKey(row, index);
      const newSelected = new Set(selectedRows);

      if (checked) {
        newSelected.add(rowKey);
      } else {
        newSelected.delete(rowKey);
      }

      setSelectedRows(newSelected);
      if (onSelectionChange) {
        const selectedData = data.filter((r, i) =>
          newSelected.has(getRowKey(r, i)),
        );
        onSelectionChange(selectedData);
      }
    },
    [selectedRows, data, getRowKey, onSelectionChange],
  );

  const totalPages = useMemo(
    () => Math.ceil(data.length / itemsPerPage),
    [data.length, itemsPerPage],
  );

  const paginatedDataMemo = useMemo(() => {
    if (!paginated) return data;
    const start = (currentPage - 1) * itemsPerPage;
    const end = start + itemsPerPage;
    return data.slice(start, end);
  }, [data, paginated, currentPage, itemsPerPage]);

  const displayedData = paginated ? paginatedDataMemo : data;

  const isAllSelected = useMemo(() => {
    if (displayedData.length === 0) return false;
    return displayedData.every((row, index) => {
      const absoluteIndex = paginated
        ? (currentPage - 1) * itemsPerPage + index
        : index;
      return selectedRows.has(getRowKey(row, absoluteIndex));
    });
  }, [
    displayedData,
    selectedRows,
    paginated,
    currentPage,
    itemsPerPage,
    getRowKey,
  ]);

  const isIndeterminate = useMemo(() => {
    if (displayedData.length === 0) return false;
    const selectedCount = displayedData.filter((row, index) => {
      const absoluteIndex = paginated
        ? (currentPage - 1) * itemsPerPage + index
        : index;
      return selectedRows.has(getRowKey(row, absoluteIndex));
    }).length;
    return selectedCount > 0 && selectedCount < displayedData.length;
  }, [
    displayedData,
    selectedRows,
    paginated,
    currentPage,
    itemsPerPage,
    getRowKey,
  ]);

  const getSortIcon = (columnKey: string) => {
    if (sortColumn !== columnKey) {
      return <ArrowUpDown className="h-4 w-4 text-muted-foreground" />;
    }
    return sortDirection === 'asc' ? (
      <ArrowUp className="h-4 w-4" />
    ) : (
      <ArrowDown className="h-4 w-4" />
    );
  };

  return (
    <div className={cn('w-full', className)}>
      <div className="rounded-md border">
        <div className="overflow-x-auto">
          {/* CRITIQUE FIX #40: Ajouter aria-label pour l'accessibilité */}
          <table
            className="w-full border-collapse"
            aria-label={ariaLabel}
            aria-labelledby={ariaLabelledBy}
          >
            <thead>
              <tr className="border-b bg-muted/50">
                {selectable && (
                  <th className="w-12 p-4">
                    <Checkbox
                      checked={isAllSelected}
                      onCheckedChange={(checked) =>
                        handleSelectAll(checked === true)
                      }
                      className={cn(
                        isIndeterminate &&
                          'data-[state=checked]:bg-primary data-[state=checked]:text-primary-foreground',
                      )}
                    />
                  </th>
                )}
                {columns.map((column) => (
                  <th
                    key={column.key}
                    className={cn(
                      'p-4 text-left font-medium',
                      column.align === 'center' && 'text-center',
                      column.align === 'right' && 'text-right',
                      column.sortable && 'cursor-pointer hover:bg-muted/80',
                      column.width && `w-[${column.width}]`,
                    )}
                    style={column.width ? { width: column.width } : undefined}
                    onClick={() => column.sortable && handleSort(column.key)}
                  >
                    <div
                      className={cn(
                        'flex items-center gap-2',
                        column.align === 'center' && 'justify-center',
                        column.align === 'right' && 'justify-end',
                      )}
                    >
                      <span>{column.header}</span>
                      {column.sortable && getSortIcon(column.key)}
                    </div>
                  </th>
                ))}
              </tr>
            </thead>
            <tbody>
              {displayedData.length === 0 ? (
                <tr>
                  <td
                    colSpan={columns.length + (selectable ? 1 : 0)}
                    className="p-8 text-center text-muted-foreground"
                  >
                    {emptyMessage}
                  </td>
                </tr>
              ) : (
                displayedData.map((row, index) => {
                  const absoluteIndex = paginated
                    ? (currentPage - 1) * itemsPerPage + index
                    : index;
                  const rowKey = getRowKey(row, absoluteIndex);
                  const isSelected = selectedRows.has(rowKey);

                  return (
                    <tr
                      key={rowKey}
                      className={cn(
                        'border-b transition-colors',
                        isSelected && 'bg-muted/50',
                        onRowClick && 'cursor-pointer hover:bg-muted/50',
                        rowClassName && rowClassName(row, absoluteIndex),
                      )}
                      onClick={() => onRowClick?.(row, absoluteIndex)}
                    >
                      {selectable && (
                        <td className="p-4">
                          <Checkbox
                            checked={isSelected}
                            onCheckedChange={(checked) =>
                              handleSelectRow(
                                row,
                                absoluteIndex,
                                checked === true,
                              )
                            }
                            onClick={(e) => e.stopPropagation()}
                          />
                        </td>
                      )}
                      {columns.map((column) => (
                        <td
                          key={column.key}
                          className={cn(
                            'p-4',
                            column.align === 'center' && 'text-center',
                            column.align === 'right' && 'text-right',
                          )}
                        >
                          {column.render
                            ? column.render(row, absoluteIndex)
                            : (row[column.key] ?? '')}
                        </td>
                      ))}
                    </tr>
                  );
                })
              )}
            </tbody>
          </table>
        </div>
      </div>

      {paginated && totalPages > 1 && (
        <div className="mt-4 flex justify-center">
          <Pagination
            currentPage={currentPage}
            totalPages={totalPages}
            onPageChange={setCurrentPage}
          />
        </div>
      )}
    </div>
  );
}
