/* eslint-disable react/jsx-key */
/* FIXME fix datable keys and remo eslint-disable */
import React, { PropsWithoutRef, RefAttributes } from 'react'
import useTheme from '../use-theme'
import GlobalFilter from './global-filter'
import SorterIcon from './sorter-icon'
import Pagination from '../pagination'

import {
  useTable,
  useSortBy,
  useGlobalFilter,
  usePagination,
  useRowSelect,
  SortingRule
} from 'react-table'

interface Props {
  className?: string
  columns: any
  selectable: boolean
  sortable?: boolean
  sortBy?: Array<SortingRule<any>>
  searchBar?: boolean
  pagination?: boolean
  pageSize?: number
  searchPadding?: number
  paginationPadding?: number
  selectedRowIds?: Record<string, boolean>
  data: Array<Record<string, unknown>>
  onClickRow?: (item: any) => void
  multiSelect?: boolean
  manualRowSelectedKey?: string
}

const defaultProps = {
  className: '',
  manualRowSelectedKey: 'isSelected',
  selectable: false,
  multiSelect: true,
  sortable: false,
  sortBy: [] as Array<SortingRule<any>>,
  searchBar: false,
  pagination: false,
  pageSize: 50,
  searchPadding: 1,
  paginationPadding: 1.5,
  selectedRowIds: {}
}

type NativeAttrs = Omit<React.HTMLAttributes<any>, keyof Props>
export type DataTableProps = Props & typeof defaultProps & NativeAttrs

const DataTable: React.FC<DataTableProps> = ({
  className,
  columns,
  data,
  manualRowSelectedKey,
  multiSelect,
  selectable,
  selectedRowIds,
  sortable,
  sortBy,
  searchBar,
  pagination,
  pageSize,
  searchPadding,
  paginationPadding,
  onClickRow
}) => {
  const hooks: any[] = []
  if (searchBar) {
    hooks.push(useGlobalFilter)
  }
  if (sortable) {
    hooks.push(useSortBy)
  }
  if (pagination) {
    hooks.push(usePagination)
  }
  if (selectable) {
    hooks.push(useRowSelect)
  }
  const {
    getTableProps,
    getTableBodyProps,
    headerGroups,
    page,
    rows,
    prepareRow,
    state,
    pageCount,
    toggleAllRowsSelected,
    gotoPage,
    ...tableProps
  } = useTable(
    {
      columns,
      data,
      disableSortBy: !sortable,
      initialState: { pageSize, selectedRowIds, sortBy },
      autoResetSelectedRows: false,
      manualRowSelectedKey
    } as any,
    ...hooks
  ) as any // FIXME: once new react-datatable types package has been releaesed

  let setGlobalFilter
  if (searchBar) {
    setGlobalFilter = tableProps.setGlobalFilter
  }
  const theme = useTheme()

  const tableRows = pagination ? page : rows

  return (
    <div className="table-wrapper">
      {searchBar && setGlobalFilter && (
        <div className="search-wrapper">
          <GlobalFilter globalFilter={state.globalFilter} setGlobalFilter={setGlobalFilter} />
        </div>
      )}
      <table className={className} {...getTableProps()} style={{ borderSpacing: 0, width: '100%' }}>
        <thead>
          {headerGroups.map((headerGroup: any) => (
            <tr {...headerGroup.getHeaderGroupProps()}>
              {headerGroup.headers.map((column: any) => (
                <th
                  key={column.name}
                  width={column.width}
                  {...column.getHeaderProps(sortable ? column.getSortByToggleProps() : undefined)}
                >
                  <div className="thead-box" style={column.style}>
                    {column.render('Header')}
                    {sortable && !column.disableSortBy && (
                      <SorterIcon
                        isSortedAsc={column.isSorted && !column.isSortedDesc}
                        isSortedDesc={column.isSorted && column.isSortedDesc}
                      />
                    )}
                  </div>
                </th>
              ))}
            </tr>
          ))}
        </thead>
        <tbody {...getTableBodyProps()}>
          {tableRows.map((row: any) => {
            prepareRow(row)
            let className = ''
            if (onClickRow || selectable) {
              className =
                row.isSelected || selectedRowIds[row.original[manualRowSelectedKey]]
                  ? 'selected'
                  : ''
            }
            return (
              <tr
                {...row.getRowProps()}
                className={className}
                onClick={
                  onClickRow &&
                  (() => {
                    onClickRow(row)
                    if (selectable) {
                      if (!multiSelect) {
                        toggleAllRowsSelected(false)
                      }
                      row.toggleRowSelected()
                    }
                  })
                }
              >
                {row.cells.map((cell: any) => {
                  return (
                    <td {...cell.getCellProps()}>
                      <div className="cell" style={cell.column.style}>
                        {cell.render('Cell')}
                      </div>
                    </td>
                  )
                })}
              </tr>
            )
          })}
        </tbody>
      </table>
      {pagination && (
        <div className="pagination-wrapper">
          <Pagination onChange={(i) => gotoPage(i - 1)} count={pageCount} />
        </div>
      )}
      <style jsx>{`
        .search-wrapper {
          padding: ${searchPadding}rem 0 0;
        }
        .pagination-wrapper {
          padding: ${paginationPadding}rem 0 0;
        }

        thead {
          border-collapse: separate;
          border-spacing: 0;
        }

        th {
          padding: 0 ${theme.layout.gapHalf};
          font-size: 0.75rem;
          font-weight: normal;
          text-align: left;
          letter-spacing: 0;
          vertical-align: center;
          min-height: 2.5rem;
          color: ${theme.palette.accents_10};
          background: ${theme.palette.accents_1};
          border-bottom: 1px solid ${theme.palette.border};
          border-top: 1px solid ${theme.palette.border};
          border-radius: 0;
        }

        th:nth-child(1) {
          border-bottom: 1px solid ${theme.palette.border};
          border-left: 1px solid ${theme.palette.border};
          border-top: 1px solid ${theme.palette.border};
          border-top-left-radius: ${theme.layout.radius};
          border-bottom-left-radius: ${theme.layout.radiusSmall};
        }

        th:last-child {
          border-bottom: 1px solid ${theme.palette.border};
          border-right: 1px solid ${theme.palette.border};
          border-top: 1px solid ${theme.palette.border};
          border-top-right-radius: ${theme.layout.radius};
          border-bottom-right-radius: ${theme.layout.radiusSmall};
        }

        .thead-box {
          display: flex;
          align-items: center;
          -webkit-box-align: center;
          min-height: 2.5rem;
          text-transform: uppercase;
        }

        tr:hover {
          background-color: ${theme.palette.accents_1};
        }

        tr :global(td) {
          padding: 0 ${theme.layout.gapHalf};
          border-bottom: 1px solid ${theme.palette.border};
          color: ${theme.palette.accents_10};
          font-size: 0.875rem;
          text-align: left;
        }

        tr :global(div.cell) {
          min-height: 2.125rem;
          display: flex;
          -webkit-box-align: center;
          align-items: center;
          flex-flow: row wrap;
        }
      `}</style>
    </div>
  )
}

type DataTableComponent<T, P> = React.ForwardRefExoticComponent<
  PropsWithoutRef<P> & RefAttributes<T>
>
type ComponentProps = Partial<typeof defaultProps> &
  Omit<Props, keyof typeof defaultProps> &
  NativeAttrs

DataTable.defaultProps = defaultProps

export default React.memo(DataTable) as DataTableComponent<HTMLDivElement, ComponentProps>
