import { ArrowSmDownIcon, ArrowSmUpIcon } from '@heroicons/react/solid';
import React, { useEffect } from 'react';
import { useTable, useRowSelect, Column, IdType, useSortBy } from 'react-table';

export interface ReactTableProps<T extends Record<string, unknown>> {
  columns: Column<T>[];
  data: T[];
  onRowClick?(row: T): void;
  pagination?: boolean;
  getSelectedRowIds?(rows: Record<IdType<T>, boolean>): void;
  selectable?: boolean;
  loading?: boolean;
}

const IndeterminateCheckbox = React.forwardRef(({ indeterminate, ...rest }: any, ref) => {
  const defaultRef = React.useRef(null);
  const resolvedRef: any = ref || defaultRef;

  React.useEffect(() => {
    resolvedRef.current.indeterminate = indeterminate;
  }, [resolvedRef, indeterminate]);

  return (
    <>
      <input
        type="checkbox"
        ref={resolvedRef}
        {...rest}
        className="focus:ring-primary-800 h-4 w-4 text-primary-700 border-gray-300 rounded"
      />
    </>
  );
});

export const Table = <T extends Record<string, unknown>>({
  columns,
  data,
  pagination = false,
  onRowClick,
  getSelectedRowIds,
  selectable = false,
  loading = false,
}: ReactTableProps<T>) => {
  const {
    getTableProps,
    getTableBodyProps,
    headerGroups,
    rows,
    prepareRow,
    pageCount,
    state: { selectedRowIds },
  } = useTable(
    {
      columns,
      data,
    },
    useSortBy,
    useRowSelect,
    selectable
      ? (hooks) => {
          hooks.visibleColumns.push((columns2) => [
            {
              id: 'selection',
              Header: ({ getToggleAllRowsSelectedProps }: { getToggleAllRowsSelectedProps: any }) => (
                <div>
                  <IndeterminateCheckbox {...getToggleAllRowsSelectedProps()} />
                </div>
              ),
              Cell: ({ row }: { row: any }) => (
                <div>
                  <IndeterminateCheckbox {...row.getToggleRowSelectedProps()} />
                </div>
              ),
              width: 16,
            },
            ...columns2,
          ]);
        }
      : () => {},
  );

  useEffect(() => {
    if (selectedRowIds && getSelectedRowIds) {
      getSelectedRowIds(selectedRowIds);
    }
  }, [selectedRowIds, getSelectedRowIds]);

  return (
    <>
      <table className="min-w-full divide-y divide-gray-200 table-auto" {...getTableProps()}>
        <thead className="bg-gray-50">
          {headerGroups.map((headerGroup: any, index: any) => (
            <tr {...headerGroup.getHeaderGroupProps()} key={index!}>
              {headerGroup.headers.map((column: any) => (
                <th
                  key={column}
                  {...column.getHeaderProps([
                    {
                      style: {
                        width: column.width ? column.width : 'auto !important',
                      },
                    },
                    column.getSortByToggleProps(),
                  ])}
                  scope="col"
                  className="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider"
                >
                  <div className="flex items-center">
                    <span>{column.render('Header')}</span>
                    {(column as any).isSorted ? (
                      (column as any).isSortedDesc ? (
                        <ArrowSmDownIcon className="w-4 h-4 text-gray-400 ml-1" />
                      ) : (
                        <ArrowSmUpIcon className="w-4 h-4 text-gray-400 ml-1" />
                      )
                    ) : (
                      ''
                    )}
                  </div>
                </th>
              ))}
            </tr>
          ))}
        </thead>
        <tbody {...getTableBodyProps()}>
          {!loading ? (
            rows.map((row: any, rowIndex) => {
              prepareRow(row);
              return (
                <tr
                  key={row}
                  {...row.getRowProps()}
                  className={rowIndex % 2 === 0 ? 'bg-white group' : 'bg-gray-50 group'}
                  onClick={onRowClick ? () => onRowClick(row.original as T) : () => {}}
                >
                  {row.cells.map((cell: any) => {
                    return (
                      <td
                        key={cell}
                        {...cell.getCellProps()}
                        className="px-6 py-4 whitespace-nowrap text-sm text-gray-500"
                      >
                        {cell.render('Cell')}
                      </td>
                    );
                  })}
                </tr>
              );
            })
          ) : (
            <tr>
              <td colSpan={4} className="py-24">
                <div className="flex flex-col justify-center items-center">
                  <div className="flex justify-center items-center border border-transparent text-base font-medium rounded-md text-white transition ease-in-out duration-150">
                    <svg
                      className="animate-spin h-6 w-6 text-primary"
                      xmlns="http://www.w3.org/2000/svg"
                      fill="none"
                      viewBox="0 0 24 24"
                    >
                      <circle className="opacity-50" cx="12" cy="12" r="10" stroke="currentColor" strokeWidth="4" />
                      <path
                        className="opacity-100"
                        fill="currentColor"
                        d="M4 12a8 8 0 018-8V0C5.373 0 0 5.373 0 12h4zm2 5.291A7.962 7.962 0 014 12H0c0 3.042 1.135 5.824 3 7.938l3-2.647z"
                      />
                    </svg>
                  </div>
                  <p className="text-sm text-primary-600 mt-2">Loading users</p>
                </div>
              </td>
            </tr>
          )}
        </tbody>
      </table>

      {pagination && pageCount > 1 && (
        <div className="bg-white px-4 py-3 flex items-center justify-between border-t border-gray-100 sm:px-6">
          <div className="flex-1 flex justify-between sm:hidden">
            <a
              href="#"
              className="relative inline-flex items-center px-4 py-2 border border-gray-300 text-sm font-medium rounded-md text-gray-700 bg-white hover:bg-gray-50"
            >
              Previous
            </a>
            <a
              href="#"
              className="ml-3 relative inline-flex items-center px-4 py-2 border border-gray-300 text-sm font-medium rounded-md text-gray-700 bg-white hover:bg-gray-50"
            >
              Next
            </a>
          </div>
          <div className="hidden sm:flex-1 sm:flex sm:items-center sm:justify-between">
            <div>
              <p className="text-sm text-gray-700">
                Showing <span className="font-medium">1</span> to <span className="font-medium">3</span> of{' '}
                <span className="font-medium">3</span> results
              </p>
            </div>
          </div>
        </div>
      )}
    </>
  );
};
