import type { FC } from 'react'
import { useMemo, useState } from 'react'
import Body from './Body'
import Head from './Head'
import type { Column, Row, SelectingRow, ValueType } from './typing'
import { SortingFunction } from './typing'
import { defaultFormatValue } from './utils'

type SortableTableProps = {
  columns: Column[]
  formatValue?: (value: ValueType) => string
  sortByColumn?: number
  defaultSortingFunction?: SortingFunction
  className?: string
  loading?: boolean
} & (
  | {
      rows: Row[]
      allSelected?: never
      onSelectAll?: never
      onDeselectAll?: never
    }
  | {
      rows: SelectingRow[]
      allSelected: boolean
      onSelectAll: () => void
      onDeselectAll: () => void
    }
)

const SortableTable: FC<SortableTableProps> = ({
  columns: columnsUnfiltered,
  rows,
  formatValue = defaultFormatValue,
  sortByColumn: defaultSortByColumn = 0,
  defaultSortingFunction = SortingFunction.ASC,
  className,
  loading,
  allSelected,
  onSelectAll,
  onDeselectAll,
}) => {
  const columns = useMemo(
    () => columnsUnfiltered.filter(column => column.display !== false),
    [columnsUnfiltered]
  )

  const sortByColumn = useMemo(
    () =>
      defaultSortByColumn &&
      defaultSortByColumn >= 0 &&
      defaultSortByColumn < columns.length
        ? defaultSortByColumn
        : 0,
    [columns.length, defaultSortByColumn]
  )

  const [selectedColumnIndex, setSelectedColumnIndex] = useState(sortByColumn)
  const [sortingFunction, setSortingFunction] = useState<SortingFunction[]>(
    columns.map((_column, i) =>
      i === sortByColumn && defaultSortingFunction
        ? defaultSortingFunction
        : SortingFunction.ASC
    )
  )

  // can't do this directly in the props because of a false-positive TS error
  const selectingHeadProps = useMemo(
    () =>
      allSelected !== undefined
        ? { allSelected, onSelectAll, onDeselectAll }
        : {},
    [allSelected, onDeselectAll, onSelectAll]
  )
  const selectingBodyProps = useMemo(
    () => (allSelected !== undefined ? { selectingRows: rows } : { rows }),
    [allSelected, rows]
  )

  return (
    <div style={{ height: '100%', overflowY: 'auto' }}>
      <table
        style={{
          borderCollapse: 'collapse',
          tableLayout: 'fixed',
          width: '100%',
        }}
        className={className}
      >
        <Head
          columns={columns}
          selectedColumnIndex={selectedColumnIndex}
          setSelectedColumnIndex={setSelectedColumnIndex}
          sortingFunction={sortingFunction}
          setSortingFunction={setSortingFunction}
          {...selectingHeadProps}
        />
        <Body
          columnsLength={columns.length}
          selectedColumnIndex={selectedColumnIndex}
          sortingFunction={sortingFunction}
          formatValue={formatValue}
          loading={loading}
          {...selectingBodyProps}
        />
      </table>
    </div>
  )
}

export default SortableTable
