import React, { useCallback, useContext, useMemo, useState } from "react";
import { useQuery } from "@tanstack/react-query";
import { Book } from "../../types/Book";
import { Button, Form, Table } from "react-bootstrap";
import {
  createColumnHelper,
  flexRender,
  getCoreRowModel,
  getSortedRowModel,
  getFilteredRowModel,
  getPaginationRowModel,
  PaginationState,
  useReactTable,
  ColumnDef,
} from "@tanstack/react-table";
import { Actions } from "./components/Actions";
import { ImArrowDown, ImArrowUp } from "react-icons/im";
import { useLocation } from "react-router-dom";
import { format } from "date-fns";
import { useAuth } from "../../shared/utils/useAuthentication";
import { ModalSelector } from "../../shared/components/modals/Modals";
import { ModalContext } from "../../App";
import { Pagination } from "./components/Pagination";
import { modalTypes } from "../../shared/components/modals/types";

export const Library = (): React.JSX.Element => {
  const location = useLocation();
  const locationState = location.state;

  const params = useMemo(
    () => new URLSearchParams(location.search),
    [location]
  );

  const { authenticated } = useAuth();
  const modalContext = useContext(ModalContext);

  const [selectedBooks, setSelectedBooks] = useState<Book["uuid"][]>([]);

  const toggleBookSelection = useCallback(
    (uuid: Book["uuid"]) =>
      setSelectedBooks((prev) =>
        prev.includes(uuid)
          ? prev.filter((current) => current !== uuid)
          : [...prev, uuid]
      ),
    []
  );

  const { data: books, refetch } = useQuery<Book[]>({
    queryFn: async () => {
      if (
        locationState &&
        "found" in locationState &&
        !!locationState.found.length
      ) {
        return locationState.found;
      }
      const response = await fetch(`/api/books/list`);
      const data = await response.json();
      return data;
    },
    queryKey: ["books"],
  });

  const shelf = params.get("shelf");
  const year = params.get("year");

  const data = useMemo(
    () =>
      books?.filter(
        (b) =>
          (!shelf || b.shelf?.toLowerCase() === shelf?.toLowerCase()) &&
          (!year || b.published.toString() === year)
      ) ?? [],
    [books, year, shelf]
  );

  const columnHelper = createColumnHelper<Book>();
  const columns: ColumnDef<Book, any>[] = useMemo(
    () =>
      [
        authenticated
          ? columnHelper.display({
              id: "selection",
              header: () => (
                <Form.Check
                  type='checkbox'
                  checked={selectedBooks.length === data?.length}
                  id={`select-all-books`}
                  onChange={() =>
                    setSelectedBooks((prev) =>
                      prev.length || !data ? [] : data.map((b) => b.uuid)
                    )
                  }
                />
              ),
              cell: (props) => (
                <Form.Check
                  type='checkbox'
                  checked={selectedBooks.includes(props.row.original.uuid)}
                  id={`select-book-${props.row.original.uuid}`}
                  onChange={() => toggleBookSelection(props.row.original.uuid)}
                />
              ),
            })
          : undefined,
        columnHelper.accessor((book) => book.isbn, {
          id: "isbn",
          header: "ISBN",
          size: 50,
          cell: (props) => <div>{props.row.original.isbn}</div>,
        }),
        columnHelper.accessor((book) => book.title, {
          id: "title",
          header: "Title",
          size: 200,
          cell: (props) => <div>{props.row.original.title}</div>,
        }),
        columnHelper.accessor((book) => book.published, {
          id: "published",
          header: "Year published",
          size: 30,
          cell: (props) => <div>{props.row.original.published}</div>,
        }),
        columnHelper.accessor((book) => book.shelf, {
          id: "shelf",
          header: "Shelf",
          size: 50,
          cell: (props) => <div>{props.row.original.shelf}</div>,
        }),
        columnHelper.accessor(
          (book) => (!book.checkoutBy ? "" : book.checkoutBy),
          {
            id: "checkoutBy",
            size: 50,
            header: "Checked out by",
            cell: (props) => (
              <div>
                {!props.row.original.checkoutBy
                  ? ""
                  : props.row.original.checkoutBy}
              </div>
            ),
          }
        ),
        columnHelper.accessor((book) => book.lastCheckoutDate, {
          id: "lastCheckoutDate",
          header: "Last checkout",
          size: 50,
          cell: (props) => (
            <div>
              {!props.row.original.lastCheckoutDate
                ? ""
                : format(
                    Number(props.row.original.lastCheckoutDate),
                    "yyyy MM dd"
                  )}
            </div>
          ),
        }),
        authenticated
          ? columnHelper.accessor(
              (book) => (!book.contact ? "" : book.contact),
              {
                id: "contactInfo",
                header: "Contact info",
                size: 50,
                cell: (props) => (
                  <div>
                    {!props.row.original.contact
                      ? ""
                      : props.row.original.contact}
                  </div>
                ),
              }
            )
          : undefined,
        columnHelper.display({
          id: "actions",
          header: "Actions",
          size: 30,
          cell: (props) => (
            <Actions
              book={props.row.original}
              refetch={refetch}
              authenticated={authenticated}
              setActiveModal={modalContext.setActiveModal}
            />
          ),
        }),
      ].filter((c) => typeof c !== "undefined") as ColumnDef<Book, any>[],
    [
      authenticated,
      columnHelper,
      selectedBooks,
      data,
      toggleBookSelection,
      refetch,
      modalContext.setActiveModal,
    ]
  );

  const [pagination, setPagination] = React.useState<PaginationState>({
    pageIndex: 0,
    pageSize: 10,
  });

  const table = useReactTable({
    columns,
    data,
    getCoreRowModel: getCoreRowModel(),
    getSortedRowModel: getSortedRowModel(),
    getFilteredRowModel: getFilteredRowModel(),
    getPaginationRowModel: getPaginationRowModel(),
    onPaginationChange: setPagination,
    state: {
      pagination,
    },
  });

  const currentPage = useMemo(
    () => table.getState().pagination.pageIndex,
    // eslint-disable-next-line react-hooks/exhaustive-deps
    [table.getState().pagination.pageIndex]
  );

  return (
    <div className='m-auto p-2' style={{ width: "100%", maxHeight: "100vh" }}>
      <ModalSelector {...modalContext} />
      <h1>Library</h1>
      <div
        style={{
          maxWidth: "100%",
          maxHeight: "80vh",
          overflow: "auto",
          marginBottom: "5px",
        }}
      >
        <Table striped bordered hover>
          <thead>
            {table.getHeaderGroups().map((headerGroup) => {
              return (
                <tr key={headerGroup.id}>
                  {headerGroup.headers.map((header) => (
                    <th key={header.id} colSpan={header.colSpan}>
                      <div
                        style={{ cursor: "pointer" }}
                        {...{
                          onClick: header.column.getToggleSortingHandler(),
                        }}
                      >
                        {flexRender(
                          header.column.columnDef.header,
                          header.getContext()
                        )}
                        {!!header.column.getIsSorted() &&
                          ((header.column.getIsSorted() as string) === "asc" ? (
                            <ImArrowUp />
                          ) : (
                            <ImArrowDown />
                          ))}
                      </div>
                    </th>
                  ))}
                </tr>
              );
            })}
          </thead>
          <tbody>
            {table.getRowModel().rows.map((row) => (
              <tr key={row.id}>
                {row.getVisibleCells().map((cell) => (
                  <td key={cell.id}>
                    {flexRender(cell.column.columnDef.cell, cell.getContext())}
                  </td>
                ))}
              </tr>
            ))}
          </tbody>
        </Table>
      </div>
      {table.getPageCount() ? (
        <div className='d-flex w-100'>
          <Pagination
            currentPage={currentPage}
            setPageIndex={table.setPageIndex}
            getPageCount={table.getPageCount}
          />
          {authenticated && (
            <Button
              style={{
                marginLeft: "0px",
                marginRight: "auto",
              }}
              className='my-auto'
              onClick={() =>
                modalContext.setActiveModal({
                  type: modalTypes.moveShelf,
                  books: selectedBooks,
                  onClose: () => {
                    refetch();
                    modalContext.setActiveModal();
                  },
                })
              }
            >
              Move selection
            </Button>
          )}
        </div>
      ) : null}
    </div>
  );
};