/* eslint-disable react/display-name */
import React, { useCallback } from "react";
import { Box, Flex } from "@chakra-ui/layout";
import { Table, Thead, Tr, Th, Tbody, Td } from "@chakra-ui/table";
import { MdArrowDropDown, MdArrowDropUp, MdArrowForward } from "react-icons/md";
import {
  IoMdArrowDroprightCircle,
  IoMdArrowDropdownCircle
} from "react-icons/io";

import {
  Column,
  useExpanded,
  useGlobalFilter,
  useGroupBy,
  usePagination,
  useRowSelect,
  useSortBy,
  useTable
} from "react-table";
import { PaginationControl } from "./PaginationControl";
import { HStack, IconButton, Select, Tag, Text } from "@chakra-ui/react";
import { IndeterminateCheckbox } from "./IndeterminateCheckbox";
import { GroupBy } from "./GroupBy";
import { GlobalFilter } from "./GlobalFilter";
import IDataGridProps from "./data-grid.types";

const DataGrid = ({
  columns,
  data,
  isSortable = false,
  showPagination = false,
  multiSelectPosition = "left",
  isMultiSelect = false,
  onRowSelection,
  updateMyData
}: IDataGridProps) => {
  const useMultiSelectHook = (hooks: any) => {
    hooks.visibleColumns.push((columns: any) => {
      const selectionColumn = {
        id: "selection",
        Header: ({
          getToggleAllPageRowsSelectedProps,
          getToggleAllRowsSelectedProps
        }: any) => (
          <Box>
            {!showPagination ? (
              <IndeterminateCheckbox {...getToggleAllRowsSelectedProps()} />
            ) : (
              <IndeterminateCheckbox {...getToggleAllPageRowsSelectedProps()} />
            )}
          </Box>
        ),
        Cell: ({ row }: any) => (
          <Box>
            <IndeterminateCheckbox {...row.getToggleRowSelectedProps()} />
          </Box>
        )
      };
      return multiSelectPosition === "left"
        ? [...columns, selectionColumn]
        : [selectionColumn, ...columns];
    });
  };

  function useControlledState(state: any, { instance }: any) {
    return React.useMemo(() => {
      if (state.groupBy.length) {
        return {
          ...state,
          hiddenColumns: [...state.hiddenColumns, ...state.groupBy].filter(
            (d, i, all) => all.indexOf(d) === i
          )
        };
      }
      return state;
    }, [state]);
  }

  const useExpanderHook = (hooks: any) => {
    hooks.useControlledState.push(useControlledState);
    hooks.visibleColumns.push((columns: any, { instance }: any) => {
      if (!instance.state.groupBy.length) {
        return columns;
      }

      return [
        {
          id: "expander",
          Header: ({ allColumns, state: { groupBy } }: any) => {
            return groupBy.map((columnId: any) => {
              const column = allColumns.find((d: any) => d.id === columnId);

              return (
                <HStack spacing={2} padding={0} {...column.getHeaderProps()}>
                  {" "}
                  {column.canGroupBy ? (
                    <Text fontSize="md" {...column.getGroupByToggleProps()}>
                      {column.isGrouped ? (
                        <IoMdArrowDroprightCircle />
                      ) : (
                        <IoMdArrowDropdownCircle />
                      )}
                    </Text>
                  ) : null}
                  <Text>{column.render("Header")}</Text>
                </HStack>
              );
            });
          },
          Cell: ({ row }: any) => {
            if (row.canExpand) {
              const groupedCell = row.allCells.find((d: any) => d.isGrouped);

              return (
                <HStack
                  spacing={2}
                  {...row.getToggleRowExpandedProps({
                    style: {}
                  })}
                >
                  <Text fontSize="md" color="gray.400">
                    {row.isExpanded ? (
                      <IoMdArrowDropdownCircle />
                    ) : (
                      <IoMdArrowDroprightCircle />
                    )}{" "}
                  </Text>
                  <Box>{groupedCell.render("Cell")}</Box>
                  <Tag bg="blue.500" borderRadius="full" color="white">
                    {row.subRows.length}
                  </Tag>
                </HStack>
              );
            }

            return null;
          }
        },
        ...columns
      ];
    });
  };
  const plugins: any[] = [
    useGroupBy,
    useGlobalFilter,
    isSortable ? useSortBy : null,
    useExpanded,
    useExpanderHook,
    showPagination ? usePagination : null,
    isMultiSelect ? useRowSelect : null,
    isMultiSelect ? useMultiSelectHook : null
  ];

  const {
    getTableProps,
    getTableBodyProps,
    headerGroups,
    prepareRow,
    page,
    canPreviousPage,
    canNextPage,
    pageOptions,
    pageCount,
    gotoPage,
    allColumns,
    nextPage,
    toggleGroupBy,
    previousPage,
    setPageSize,
    selectedFlatRows,
    preGlobalFilteredRows,
    setGlobalFilter,
    rows,
    state: { pageIndex, pageSize, groupBy, expanded, globalFilter }
  } = useTable(
    { columns, data, initialState: { pageSize: 20 }, updateMyData },
    ...plugins.filter((p) => p !== null)
  );

  useCallback(() => {
    onRowSelection && onRowSelection(selectedFlatRows);
  }, [selectedFlatRows && onRowSelection]);

  return (
    <Box>
      <HStack spacing={2} w="full" mb={4}>
        <GlobalFilter
          preGlobalFilteredRows={preGlobalFilteredRows}
          setGlobalFilter={setGlobalFilter}
          globalFilter={globalFilter}
        />
        <GroupBy
          allColumns={allColumns}
          groupBy={groupBy}
          toggleGroupBy={toggleGroupBy}
        />
      </HStack>
      <Table {...getTableProps()} borderColor="gray.200" size="sm" width="full">
        <Thead width="full">
          {headerGroups.map((headerGroup) => (
            <Tr {...headerGroup.getHeaderGroupProps()} bg="gray.50">
              {headerGroup.headers.map((column: any) => (
                <Th
                  {...column.getHeaderProps(
                    isSortable && column.getSortByToggleProps()
                  )}
                  fontSize="md"
                  textTransform="capitalize"
                  fontWeight="medium"
                  letterSpacing="-0.01rem"
                  isNumeric={column.isNumeric}
                >
                  <HStack>
                    <Text>{column.render("Header")}</Text>
                    {column.isSorted && (
                      <IconButton
                        aria-label="sort"
                        size="x-small"
                        letterSpacing="-5%"
                        fontSize="lg"
                        icon={
                          column.isSortedDesc ? (
                            <MdArrowDropDown />
                          ) : (
                            <MdArrowDropUp />
                          )
                        }
                      />
                    )}
                  </HStack>
                </Th>
              ))}
            </Tr>
          ))}
        </Thead>
        <Tbody {...getTableBodyProps()}>
          {(page || rows).map((row, i) => {
            prepareRow(row);
            return (
              <Tr
                {...row.getRowProps()}
                fontSize="sm"
                bg={row?.isGrouped ? "blue.50" : "white"}
              >
                {row.cells.map((cell: any) => (
                  <Td
                    {...cell.getCellProps()}
                    borderWidth={1}
                    isNumeric={cell.column.isNumeric}
                  >
                    {cell.isGrouped ? (
                      // If it's a grouped cell, add an expander and row count
                      <>
                        <Text {...row.getToggleRowExpandedProps()}>
                          {row.isExpanded ? (
                            <MdArrowForward />
                          ) : (
                            <MdArrowDropDown />
                          )}
                        </Text>{" "}
                        {cell.render("Cell")} ({row.subRows.length})
                      </>
                    ) : cell.isAggregated ? (
                      cell.render("Aggregated")
                    ) : cell.isPlaceholder ? null : ( // For cells with repeated values, render null
                      // Otherwise, just render the regular cell
                      cell.render("Cell")
                    )}
                  </Td>
                ))}
              </Tr>
            );
          })}
        </Tbody>
      </Table>

      {showPagination && (
        <PaginationControl
          canPreviousPage={canPreviousPage}
          canNextPage={canNextPage}
          pageOptions={pageOptions}
          pageCount={pageCount}
          gotoPage={gotoPage}
          nextPage={nextPage}
          previousPage={previousPage}
          setPageSize={setPageSize}
          pageIndex={pageIndex}
          pageSize={pageSize}
        />
      )}
    </Box>
  );
};

export default DataGrid;
