import React, { forwardRef, useMemo, useState, useEffect, TableHTMLAttributes } from 'react';
import { clsx } from 'clsx';

export interface TableColumn<T = any> {
  key: string;
  title: string;
  dataIndex?: keyof T;
  render?: (value: any, record: T, index: number) => React.ReactNode;
  width?: string | number;
  align?: 'left' | 'center' | 'right';
  sortable?: boolean;
  sortKey?: string;
  className?: string;
  headerClassName?: string;
  fixed?: 'left' | 'right';
}

export interface TableProps<T = any> extends Omit<TableHTMLAttributes<HTMLTableElement>, 'onSelect'> {
  columns: TableColumn<T>[];
  data: T[];
  loading?: boolean;
  size?: 'sm' | 'md' | 'lg';
  variant?: 'default' | 'striped' | 'bordered' | 'borderless';
  hover?: boolean;
  sticky?: boolean;
  rowSelection?: {
    type?: 'checkbox' | 'radio';
    selectedRowKeys?: React.Key[];
    onSelect?: (record: T, selected: boolean, selectedRows: T[], nativeEvent: Event) => void;
    onSelectAll?: (selected: boolean, selectedRows: T[], changeRows: T[]) => void;
    onSelectInvert?: (selectedRowKeys: React.Key[]) => void;
    getCheckboxProps?: (record: T) => { disabled?: boolean; name?: string };
    hideSelectAll?: boolean;
    preserveSelectedRowKeys?: boolean;
  };
  pagination?: {
    current?: number;
    pageSize?: number;
    total?: number;
    showSizeChanger?: boolean;
    showQuickJumper?: boolean;
    showTotal?: (total: number, range: [number, number]) => string;
    onChange?: (page: number, pageSize: number) => void;
    position?: 'top' | 'bottom' | 'both';
  };
  sort?: {
    field?: string;
    order?: 'asc' | 'desc';
    multiple?: boolean;
  };
  onSort?: (field: string, order: 'asc' | 'desc' | null) => void;
  expandable?: {
    expandedRowKeys?: React.Key[];
    onExpand?: (expanded: boolean, record: T) => void;
    onExpandedRowsChange?: (expandedKeys: React.Key[]) => void;
    expandedRowRender?: (record: T, index: number) => React.ReactNode;
    rowExpandable?: (record: T) => boolean;
    expandRowByClick?: boolean;
    defaultExpandAllRows?: boolean;
    indentSize?: number;
  };
  rowKey?: string | ((record: T) => React.Key);
  onRow?: (record: T, index: number) => React.HTMLAttributes<HTMLTableRowElement>;
  locale?: {
    emptyText?: string;
    selectAll?: string;
    selectRow?: string;
    expand?: string;
    collapse?: string;
  };
  scroll?: {
    x?: string | number | true;
    y?: string | number;
  };
  summary?: (data: T[]) => React.ReactNode;
}

export interface TablePaginationProps {
  current: number;
  pageSize: number;
  total: number;
  showSizeChanger?: boolean;
  showQuickJumper?: boolean;
  showTotal?: (total: number, range: [number, number]) => string;
  onChange?: (page: number, pageSize: number) => void;
  className?: string;
}

const Table = forwardRef<HTMLTableElement, TableProps>(({
  columns,
  data,
  loading = false,
  size = 'md',
  variant = 'default',
  hover = true,
  sticky = false,
  rowSelection,
  pagination,
  sort,
  onSort,
  expandable,
  rowKey = 'id',
  onRow,
  locale = {
    emptyText: 'No hay datos disponibles',
    selectAll: 'Seleccionar todo',
    selectRow: 'Seleccionar fila',
    expand: 'Expandir fila',
    collapse: 'Contraer fila',
  },
  scroll,
  summary,
  className,
  ...props
}, ref) => {
  const [sortState, setSortState] = useState<{ field?: string; order?: 'asc' | 'desc' }>({
    field: sort?.field,
    order: sort?.order,
  });
  const [selectedRowKeys, setSelectedRowKeys] = useState<React.Key[]>(
    rowSelection?.selectedRowKeys || []
  );
  const [expandedRowKeys, setExpandedRowKeys] = useState<React.Key[]>(
    expandable?.expandedRowKeys || (expandable?.defaultExpandAllRows ? data.map(getRowKey) : [])
  );

  function getRowKey(record: any, index?: number): React.Key {
    if (typeof rowKey === 'function') {
      return rowKey(record);
    }
    return record[rowKey] || index || 0;
  }

  // Update local state when props change
  useEffect(() => {
    if (rowSelection?.selectedRowKeys) {
      setSelectedRowKeys(rowSelection.selectedRowKeys);
    }
  }, [rowSelection?.selectedRowKeys]);

  useEffect(() => {
    if (expandable?.expandedRowKeys) {
      setExpandedRowKeys(expandable.expandedRowKeys);
    }
  }, [expandable?.expandedRowKeys]);

  // Handle sorting
  const handleSort = (field: string) => {
    let newOrder: 'asc' | 'desc' | null = 'asc';
    
    if (sortState.field === field) {
      newOrder = sortState.order === 'asc' ? 'desc' : sortState.order === 'desc' ? null : 'asc';
    }

    setSortState({ field: newOrder ? field : undefined, order: newOrder || undefined });
    onSort?.(field, newOrder);
  };

  // Handle row selection
  const handleSelectRow = (record: any, selected: boolean, event: Event) => {
    const key = getRowKey(record);
    let newSelectedKeys = [...selectedRowKeys];
    
    if (rowSelection?.type === 'radio') {
      newSelectedKeys = selected ? [key] : [];
    } else {
      if (selected) {
        newSelectedKeys.push(key);
      } else {
        newSelectedKeys = newSelectedKeys.filter(k => k !== key);
      }
    }
    
    setSelectedRowKeys(newSelectedKeys);
    const selectedRows = data.filter(item => newSelectedKeys.includes(getRowKey(item)));
    rowSelection?.onSelect?.(record, selected, selectedRows, event);
  };

  const handleSelectAll = (selected: boolean) => {
    const selectableData = data.filter(record => {
      const checkboxProps = rowSelection?.getCheckboxProps?.(record);
      return !checkboxProps?.disabled;
    });
    
    const newSelectedKeys = selected ? selectableData.map(getRowKey) : [];
    const changeRows = selected ? selectableData : selectedRowKeys.map(key => data.find(item => getRowKey(item) === key)).filter(Boolean);
    
    setSelectedRowKeys(newSelectedKeys);
    const selectedRows = data.filter(item => newSelectedKeys.includes(getRowKey(item)));
    rowSelection?.onSelectAll?.(selected, selectedRows, changeRows);
  };

  // Handle row expansion
  const handleExpand = (record: any, expanded: boolean) => {
    const key = getRowKey(record);
    let newExpandedKeys = [...expandedRowKeys];
    
    if (expanded) {
      newExpandedKeys.push(key);
    } else {
      newExpandedKeys = newExpandedKeys.filter(k => k !== key);
    }
    
    setExpandedRowKeys(newExpandedKeys);
    expandable?.onExpand?.(expanded, record);
    expandable?.onExpandedRowsChange?.(newExpandedKeys);
  };

  // Processed data for current page
  const processedData = useMemo(() => {
    let result = [...data];

    // Apply pagination if needed
    if (pagination) {
      const { current = 1, pageSize = 10 } = pagination;
      const start = (current - 1) * pageSize;
      const end = start + pageSize;
      result = result.slice(start, end);
    }

    return result;
  }, [data, pagination]);

  // Table classes
  const sizeClasses = {
    sm: 'text-xs',
    md: 'text-sm',
    lg: 'text-base',
  };

  const variantClasses = {
    default: 'border-collapse border border-table-border',
    striped: 'border-collapse',
    bordered: 'border-collapse border border-table-border',
    borderless: 'border-collapse',
  };

  const tableClasses = clsx(
    'w-full bg-table-bg',
    sizeClasses[size],
    variantClasses[variant],
    {
      'table-fixed': scroll?.x,
    },
    className
  );

  const containerClasses = clsx(
    'overflow-auto',
    {
      'max-h-96': scroll?.y,
    }
  );

  // Render loading state
  if (loading) {
    return (
      <div className="flex items-center justify-center p-8">
        <div className="flex items-center space-x-2">
          <div className="animate-spin rounded-full h-6 w-6 border-b-2 border-color-primary"></div>
          <span className="text-text-secondary">Cargando...</span>
        </div>
      </div>
    );
  }

  // Render empty state
  if (processedData.length === 0) {
    return (
      <div className="flex items-center justify-center p-8">
        <div className="text-center">
          <div className="text-text-tertiary mb-2">
            <svg className="w-12 h-12 mx-auto" fill="none" stroke="currentColor" viewBox="0 0 24 24">
              <path strokeLinecap="round" strokeLinejoin="round" strokeWidth={1} d="M9 12h6m-6 4h6m2 5H7a2 2 0 01-2-2V5a2 2 0 012-2h5.586a1 1 0 01.707.293l5.414 5.414a1 1 0 01.293.707V19a2 2 0 01-2 2z" />
            </svg>
          </div>
          <p className="text-text-secondary">{locale.emptyText}</p>
        </div>
      </div>
    );
  }

  const renderHeader = () => {
    const hasSelection = rowSelection && !rowSelection.hideSelectAll;
    const hasExpansion = expandable;
    
    return (
      <thead className={clsx('bg-table-header-bg', { 'sticky top-0 z-10': sticky })}>
        <tr>
          {hasSelection && (
            <th className="px-4 py-3 text-left font-medium text-text-primary border-b border-table-border w-12">
              {rowSelection.type !== 'radio' && (
                <input
                  type="checkbox"
                  className="rounded border-input-border focus:ring-color-primary"
                  checked={selectedRowKeys.length === data.length && data.length > 0}
                  indeterminate={selectedRowKeys.length > 0 && selectedRowKeys.length < data.length}
                  onChange={(e) => handleSelectAll(e.target.checked)}
                  aria-label={locale.selectAll}
                />
              )}
            </th>
          )}
          {hasExpansion && (
            <th className="px-4 py-3 text-left font-medium text-text-primary border-b border-table-border w-12"></th>
          )}
          {columns.map((column) => {
            const isSorted = sortState.field === (column.sortKey || column.key);
            
            return (
              <th
                key={column.key}
                className={clsx(
                  'px-4 py-3 font-medium text-text-primary border-b border-table-border',
                  {
                    'text-left': column.align === 'left' || !column.align,
                    'text-center': column.align === 'center',
                    'text-right': column.align === 'right',
                    'cursor-pointer hover:bg-table-row-hover': column.sortable,
                  },
                  column.headerClassName
                )}
                style={{ width: column.width }}
                onClick={column.sortable ? () => handleSort(column.sortKey || column.key) : undefined}
              >
                <div className="flex items-center gap-2">
                  <span>{column.title}</span>
                  {column.sortable && (
                    <span className="flex flex-col">
                      <svg
                        className={clsx('w-3 h-3', {
                          'text-color-primary': isSorted && sortState.order === 'asc',
                          'text-text-quaternary': !isSorted || sortState.order !== 'asc',
                        })}
                        fill="currentColor"
                        viewBox="0 0 20 20"
                      >
                        <path d="M14.707 12.707a1 1 0 01-1.414 0L10 9.414l-3.293 3.293a1 1 0 01-1.414-1.414l4-4a1 1 0 011.414 0l4 4a1 1 0 010 1.414z" />
                      </svg>
                      <svg
                        className={clsx('w-3 h-3 -mt-1', {
                          'text-color-primary': isSorted && sortState.order === 'desc',
                          'text-text-quaternary': !isSorted || sortState.order !== 'desc',
                        })}
                        fill="currentColor"
                        viewBox="0 0 20 20"
                      >
                        <path d="M5.293 7.293a1 1 0 011.414 0L10 10.586l3.293-3.293a1 1 0 111.414 1.414l-4 4a1 1 0 01-1.414 0l-4-4a1 1 0 010-1.414z" />
                      </svg>
                    </span>
                  )}
                </div>
              </th>
            );
          })}
        </tr>
      </thead>
    );
  };

  const renderBody = () => (
    <tbody>
      {processedData.map((record, index) => {
        const key = getRowKey(record, index);
        const isSelected = selectedRowKeys.includes(key);
        const isExpanded = expandedRowKeys.includes(key);
        const canExpand = expandable?.rowExpandable?.(record) !== false;
        const rowProps = onRow?.(record, index) || {};

        return (
          <React.Fragment key={key}>
            <tr
              {...rowProps}
              className={clsx(
                'transition-colors duration-150',
                {
                  'bg-table-row-hover': hover && !isSelected,
                  'bg-table-row-selected': isSelected,
                  'odd:bg-bg-secondary': variant === 'striped' && !isSelected,
                  'border-b border-table-border': variant !== 'borderless',
                  'cursor-pointer': expandable?.expandRowByClick,
                },
                rowProps.className
              )}
              onClick={expandable?.expandRowByClick ? () => handleExpand(record, !isExpanded) : rowProps.onClick}
            >
              {rowSelection && (
                <td className="px-4 py-3 border-b border-table-border">
                  <input
                    type={rowSelection.type || 'checkbox'}
                    className="rounded border-input-border focus:ring-color-primary"
                    checked={isSelected}
                    onChange={(e) => handleSelectRow(record, e.target.checked, e.nativeEvent)}
                    disabled={rowSelection.getCheckboxProps?.(record)?.disabled}
                    name={rowSelection.getCheckboxProps?.(record)?.name}
                    aria-label={`${locale.selectRow} ${index + 1}`}
                  />
                </td>
              )}
              {expandable && (
                <td className="px-4 py-3 border-b border-table-border">
                  {canExpand && (
                    <button
                      type="button"
                      className="text-text-tertiary hover:text-text-primary transition-colors duration-150 focus:outline-none focus:ring-2 focus:ring-color-primary/20 rounded p-1"
                      onClick={(e) => {
                        e.stopPropagation();
                        handleExpand(record, !isExpanded);
                      }}
                      aria-label={isExpanded ? locale.collapse : locale.expand}
                    >
                      <svg
                        className={clsx('w-4 h-4 transform transition-transform duration-150', {
                          'rotate-90': isExpanded,
                        })}
                        fill="none"
                        stroke="currentColor"
                        viewBox="0 0 24 24"
                      >
                        <path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M9 5l7 7-7 7" />
                      </svg>
                    </button>
                  )}
                </td>
              )}
              {columns.map((column) => {
                const value = column.dataIndex ? record[column.dataIndex] : record;
                const content = column.render ? column.render(value, record, index) : value;

                return (
                  <td
                    key={column.key}
                    className={clsx(
                      'px-4 py-3 border-b border-table-border',
                      {
                        'text-left': column.align === 'left' || !column.align,
                        'text-center': column.align === 'center',
                        'text-right': column.align === 'right',
                      },
                      column.className
                    )}
                    style={{ width: column.width }}
                  >
                    {content}
                  </td>
                );
              })}
            </tr>
            {isExpanded && expandable?.expandedRowRender && (
              <tr>
                <td
                  colSpan={columns.length + (rowSelection ? 1 : 0) + (expandable ? 1 : 0)}
                  className="px-4 py-0 border-b border-table-border bg-bg-secondary"
                >
                  <div className="py-4" style={{ paddingLeft: expandable.indentSize || 24 }}>
                    {expandable.expandedRowRender(record, index)}
                  </div>
                </td>
              </tr>
            )}
          </React.Fragment>
        );
      })}
      {summary && (
        <tr className="bg-table-header-bg border-t-2 border-table-border font-medium">
          <td colSpan={columns.length + (rowSelection ? 1 : 0) + (expandable ? 1 : 0)}>
            {summary(data)}
          </td>
        </tr>
      )}
    </tbody>
  );

  return (
    <div className="space-y-4">
      <div className={containerClasses}>
        <table
          ref={ref}
          className={tableClasses}
          {...props}
        >
          {renderHeader()}
          {renderBody()}
        </table>
      </div>
      
      {pagination && (
        <TablePagination
          current={pagination.current || 1}
          pageSize={pagination.pageSize || 10}
          total={pagination.total || data.length}
          showSizeChanger={pagination.showSizeChanger}
          showQuickJumper={pagination.showQuickJumper}
          showTotal={pagination.showTotal}
          onChange={pagination.onChange}
        />
      )}
    </div>
  );
});

const TablePagination: React.FC<TablePaginationProps> = ({
  current,
  pageSize,
  total,
  showSizeChanger = false,
  showQuickJumper = false,
  showTotal,
  onChange,
  className,
}) => {
  const totalPages = Math.ceil(total / pageSize);
  const startRecord = (current - 1) * pageSize + 1;
  const endRecord = Math.min(current * pageSize, total);

  const handlePageChange = (page: number) => {
    if (page >= 1 && page <= totalPages && page !== current) {
      onChange?.(page, pageSize);
    }
  };

  const handleSizeChange = (newSize: number) => {
    const newTotalPages = Math.ceil(total / newSize);
    const newPage = current > newTotalPages ? newTotalPages : current;
    onChange?.(newPage || 1, newSize);
  };

  const renderPageButtons = () => {
    const buttons = [];
    const maxVisible = 7;
    let startPage = Math.max(1, current - Math.floor(maxVisible / 2));
    let endPage = Math.min(totalPages, startPage + maxVisible - 1);

    if (endPage - startPage + 1 < maxVisible) {
      startPage = Math.max(1, endPage - maxVisible + 1);
    }

    // Previous button
    buttons.push(
      <button
        key="prev"
        type="button"
        className="px-3 py-2 text-sm font-medium text-text-secondary border border-border-primary rounded-l-md hover:bg-bg-secondary disabled:opacity-50 disabled:cursor-not-allowed transition-colors duration-150"
        disabled={current === 1}
        onClick={() => handlePageChange(current - 1)}
      >
        Anterior
      </button>
    );

    // First page and ellipsis
    if (startPage > 1) {
      buttons.push(
        <button
          key={1}
          type="button"
          className="px-3 py-2 text-sm font-medium text-text-secondary border-t border-b border-border-primary hover:bg-bg-secondary transition-colors duration-150"
          onClick={() => handlePageChange(1)}
        >
          1
        </button>
      );
      
      if (startPage > 2) {
        buttons.push(
          <span key="start-ellipsis" className="px-3 py-2 text-sm text-text-tertiary border-t border-b border-border-primary">
            ...
          </span>
        );
      }
    }

    // Page number buttons
    for (let page = startPage; page <= endPage; page++) {
      buttons.push(
        <button
          key={page}
          type="button"
          className={clsx(
            'px-3 py-2 text-sm font-medium border-t border-b border-border-primary transition-colors duration-150',
            {
              'bg-color-primary text-text-inverse': page === current,
              'text-text-secondary hover:bg-bg-secondary': page !== current,
            }
          )}
          onClick={() => handlePageChange(page)}
        >
          {page}
        </button>
      );
    }

    // Last page and ellipsis
    if (endPage < totalPages) {
      if (endPage < totalPages - 1) {
        buttons.push(
          <span key="end-ellipsis" className="px-3 py-2 text-sm text-text-tertiary border-t border-b border-border-primary">
            ...
          </span>
        );
      }
      
      buttons.push(
        <button
          key={totalPages}
          type="button"
          className="px-3 py-2 text-sm font-medium text-text-secondary border-t border-b border-border-primary hover:bg-bg-secondary transition-colors duration-150"
          onClick={() => handlePageChange(totalPages)}
        >
          {totalPages}
        </button>
      );
    }

    // Next button
    buttons.push(
      <button
        key="next"
        type="button"
        className="px-3 py-2 text-sm font-medium text-text-secondary border border-border-primary rounded-r-md hover:bg-bg-secondary disabled:opacity-50 disabled:cursor-not-allowed transition-colors duration-150"
        disabled={current === totalPages}
        onClick={() => handlePageChange(current + 1)}
      >
        Siguiente
      </button>
    );

    return buttons;
  };

  return (
    <div className={clsx('flex items-center justify-between', className)}>
      <div className="flex items-center gap-4">
        {showTotal && (
          <span className="text-sm text-text-secondary">
            {showTotal(total, [startRecord, endRecord])}
          </span>
        )}
        {showSizeChanger && (
          <div className="flex items-center gap-2">
            <span className="text-sm text-text-secondary">Mostrar</span>
            <select
              className="px-2 py-1 text-sm border border-border-primary rounded-md bg-input-bg focus:outline-none focus:ring-2 focus:ring-color-primary/20"
              value={pageSize}
              onChange={(e) => handleSizeChange(Number(e.target.value))}
            >
              {[10, 20, 50, 100].map(size => (
                <option key={size} value={size}>{size}</option>
              ))}
            </select>
            <span className="text-sm text-text-secondary">por página</span>
          </div>
        )}
      </div>
      
      <div className="flex items-center gap-4">
        {showQuickJumper && (
          <div className="flex items-center gap-2">
            <span className="text-sm text-text-secondary">Ir a</span>
            <input
              type="number"
              min={1}
              max={totalPages}
              className="w-16 px-2 py-1 text-sm text-center border border-border-primary rounded-md bg-input-bg focus:outline-none focus:ring-2 focus:ring-color-primary/20"
              onKeyPress={(e) => {
                if (e.key === 'Enter') {
                  const page = Number((e.target as HTMLInputElement).value);
                  handlePageChange(page);
                }
              }}
            />
          </div>
        )}
        
        <div className="flex">
          {renderPageButtons()}
        </div>
      </div>
    </div>
  );
};

Table.displayName = 'Table';

export default Table;
export { TablePagination };