import {
  ellipsized,
  highlighted,
  highlightedOnActive,
  highlightedOnHover,
} from '@/analyst/utilities'
import { Checkbox, NonIdealState, Spinner } from '@blueprintjs/core'
import { cx } from '@emotion/css'
import { useCallback, type FC } from 'react'
import { checkbox, clickable, preWrappedOnHover, tableCell } from './classes'
import type { Row, SelectingRow, ValueType } from './typing'
import { SortingFunction } from './typing'
import { ascSorting, descSorting } from './utils'

type BodyProps = {
  columnsLength: number
  formatValue?: (value: ValueType) => string
  loading?: boolean
  selectedColumnIndex: number
  sortingFunction: SortingFunction[]
} & (
  | { rows: Row[]; selectingRows?: never }
  | { rows?: never; selectingRows: SelectingRow[] }
)

const Body: FC<BodyProps> = ({
  columnsLength,
  rows,
  selectingRows,
  formatValue,
  loading,
  selectedColumnIndex,
  sortingFunction,
}) => {
  const rowClass = useCallback(
    (row: Row | SelectingRow) => {
      const className = cx(highlightedOnHover, row.class, {
        [clickable]: row.onClick !== undefined,
        [highlightedOnActive]: row.onClick !== undefined,
      })

      if (selectingRows === undefined) return className
      return cx(className, { [highlighted]: (row as SelectingRow).isSelected })
    },
    [selectingRows]
  )

  const MaybeCheckbox = ({ row }: { row: Row | SelectingRow }) => {
    if (selectingRows === undefined) return null

    const selectingRow = row as SelectingRow
    return (
      <td className={tableCell}>
        <Checkbox
          className={checkbox}
          checked={selectingRow.isSelected}
          onChange={selectingRow.onClick}
        />
      </td>
    )
  }

  if (loading || rows?.length === 0 || selectingRows?.length === 0) {
    return (
      <tbody>
        <tr>
          <td colSpan={columnsLength} className={tableCell}>
            {loading ? (
              <Spinner />
            ) : (
              <NonIdealState
                title='No data'
                icon='low-voltage-pole'
                description='There is no data to display'
              />
            )}
          </td>
        </tr>
      </tbody>
    )
  }

  return (
    <tbody>
      {(rows || selectingRows)
        .sort((a, b) =>
          sortingFunction[selectedColumnIndex] === SortingFunction.ASC
            ? ascSorting(
                a.values[selectedColumnIndex],
                b.values[selectedColumnIndex]
              )
            : descSorting(
                a.values[selectedColumnIndex],
                b.values[selectedColumnIndex]
              )
        )
        .map(row => (
          <tr key={row.id} className={rowClass(row)} onClick={row.onClick}>
            <MaybeCheckbox row={row} />
            {row.columns.map((column, j) => (
              <td
                key={column.id}
                className={cx(tableCell, ellipsized, preWrappedOnHover)}
                style={{
                  ...column.style,
                  ...column.valueStyle,
                }}
              >
                {formatValue!(row.values[j])}
              </td>
            ))}
          </tr>
        ))}
    </tbody>
  )
}
export default Body
