import React, { type ReactNode, type ComponentProps } from 'react';
import {
  type TableProps as RACTableProps,
  ResizableTableContainer,
  ColumnResizer,
  Table as RACTable,
  TableBody,
  Cell,
} from 'react-aria-components';
import { TableHeader } from './TableHeader';
import { Column } from './Column';
import { Row } from './Row';

interface ColumnType {
  id: string;
  name: ReactNode;
  isRowHeader?: boolean;
  // TODO support width constraints for resizable columns
}

interface RowType {
  id: string;
  textValue?: string;
  [key: string]: ReactNode; // TODO can we make this more specific?
}

interface TableProps<C, R> extends RACTableProps {
  columns?: C[];
  rows?: R[];
  resizableColumns?: boolean;
  dragColumnHeader?: ComponentProps<typeof TableHeader>['dragColumnHeader'];
  renderEmptyState?: ComponentProps<typeof TableBody>['renderEmptyState'];
  // TODO maybe a custom "selectall" component? Is it doable with react-aria-components?
}

/**
 * A wrapper around the `react-aria-components` Table component.
 *
 * See https://react-spectrum.adobe.com/react-aria/Table.html
 */
export function Table<C extends ColumnType, R extends RowType>({
  columns,
  rows,
  resizableColumns,
  dragColumnHeader,
  renderEmptyState,
  ...otherProps
}: TableProps<C, R>) {
  let table = null;
  if (Array.isArray(columns) && Array.isArray(rows)) {
    table = (
      <RACTable {...otherProps}>
        <TableHeader columns={columns} dragColumnHeader={dragColumnHeader}>
          {(column) => (
            <Column isRowHeader={column.isRowHeader}>
              {resizableColumns && (
                <div className="flex-wrapper">
                  <span tabIndex={-1} className="column-name">
                    {column.name}
                  </span>
                  <ColumnResizer />
                </div>
              )}
              {!resizableColumns && column.name}
            </Column>
          )}
        </TableHeader>
        <TableBody items={rows} renderEmptyState={renderEmptyState}>
          {(item) => (
            <Row columns={columns} textValue={item.textValue}>
              {(column) => <Cell>{item[column.id]}</Cell>}
            </Row>
          )}
        </TableBody>
      </RACTable>
    );
  } else {
    table = <RACTable {...otherProps} />;

    if (Array.isArray(columns)) {
      console.warn('The Table component was given columns but no rows');
    } else if (Array.isArray(rows)) {
      console.warn('The Table component was given rows but no columns');
    }
  }

  if (resizableColumns) {
    return <ResizableTableContainer>{table}</ResizableTableContainer>;
  } else {
    return table;
  }
}
