import React, { useMemo, ReactElement, useState, useEffect } from "react";
import PropTypes from "prop-types";
import { useNavigate } from "react-router-dom";
import { isEmpty, isNil, isUndefined } from "lodash";
import MetadataPanel from "../shared/MetadataPanel";
import T2Table from "../shared/T2Table";
import SearchBar from "../Library/SearchBar";
import ellipsize from "ellipsize";
import {
  useQuery,
  keepPreviousData,
  useQueryClient,
} from "@tanstack/react-query";
import axios from "axios";
import { format, fromUnixTime, parseISO } from "date-fns";

/**
 * Component that tabulates the contents of the user's ThreeTwo Library.
 *
 * @component
 * @example
 * <Library />
 */
export const Library = (): ReactElement => {
  // Default page state
  // offset: 0
  const [offset, setOffset] = useState(0);
  const [searchQuery, setSearchQuery] = useState({
    query: {},
    pagination: {
      size: 25,
      from: offset,
    },
    type: "all",
    trigger: "libraryPage",
  });
  const queryClient = useQueryClient();

  /**
   * Method that queries the Elasticsearch index "comics" for issues specified by the query
   * @param searchQuery - A searchQuery object that contains the search term, type, and pagination params.
   */
  const fetchIssues = async (searchQuery) => {
    const { pagination, query, type } = searchQuery;
    return await axios({
      method: "POST",
      url: "http://localhost:3000/api/search/searchIssue",
      data: {
        query,
        pagination,
        type,
      },
    });
  };

  const searchIssues = (e) => {
    queryClient.invalidateQueries({ queryKey: ["comics"] });
    setSearchQuery({
      query: {
        volumeName: e.search,
      },
      pagination: {
        size: 15,
        from: 0,
      },
      type: "volumeName",
      trigger: "libraryPage",
    });
  };

  const { data, isLoading, isError, isPlaceholderData } = useQuery({
    queryKey: ["comics", offset, searchQuery],
    queryFn: () => fetchIssues(searchQuery),
    placeholderData: keepPreviousData,
  });

  const searchResults = data?.data;
  // Programmatically navigate to comic detail
  const navigate = useNavigate();
  const navigateToComicDetail = (row) => {
    navigate(`/comic/details/${row.original._id}`);
  };

  const ComicInfoXML = (value) => {
    return value.data ? (
      <dl className="flex flex-col text-md p-3 ml-4 my-3 rounded-lg dark:bg-yellow-500 bg-yellow-300 w-max">
        {/* Series Name */}
        <span className="inline-flex items-center w-fit bg-slate-50 text-slate-800 text-xs font-medium px-2 rounded-md dark:text-slate-900 dark:bg-slate-400">
          <span className="pr-1 pt-1">
            <i className="icon-[solar--bookmark-square-minimalistic-bold-duotone] w-5 h-5"></i>
          </span>
          <span className="text-md text-slate-900 dark:text-slate-900">
            {ellipsize(value.data.series[0], 45)}
          </span>
        </span>
        <div className="flex flex-row mt-2 gap-2">
          {/* Pages */}
          <span className="inline-flex items-center bg-slate-50 text-slate-800 text-xs px-2 rounded-md dark:text-slate-900 dark:bg-slate-400">
            <span className="pr-1 pt-1">
              <i className="icon-[solar--notebook-minimalistic-bold-duotone] w-5 h-5"></i>
            </span>
            <span className="text-md text-slate-900 dark:text-slate-900">
              Pages: {value.data.pagecount[0]}
            </span>
          </span>
          {/* Issue number */}
          <span className="inline-flex items-center bg-slate-50 text-slate-800 text-xs px-2 rounded-md dark:text-slate-900 dark:bg-slate-400">
            <span className="pr-1 pt-1">
              <i className="icon-[solar--hashtag-outline] w-3.5 h-3.5"></i>
            </span>
            <span className="text-slate-900 dark:text-slate-900">
              {!isNil(value.data.number) && (
                <span>{parseInt(value.data.number[0], 10)}</span>
              )}
            </span>
          </span>
        </div>
      </dl>
    ) : null;
  };

  const columns = useMemo(
    () => [
      {
        header: "Comic Metadata",
        footer: 1,
        columns: [
          {
            header: "File Details",
            id: "fileDetails",
            minWidth: 400,
            accessorKey: "_source",
            cell: (info) => {
              return <MetadataPanel data={info.getValue()} />;
            },
          },
          {
            header: "ComicInfo.xml",
            accessorKey: "_source.sourcedMetadata.comicInfo",
            cell: (info) =>
              !isEmpty(info.getValue()) ? (
                <ComicInfoXML data={info.getValue()} />
              ) : null,
          },
        ],
      },
      {
        header: "Additional Metadata",
        columns: [
          {
            header: "Date of Import",
            accessorKey: "_source.createdAt",
            cell: (info) => {
              return !isNil(info.getValue()) ? (
                <div className="text-sm w-max ml-3 my-3 text-slate-600 dark:text-slate-900">
                  <p>{format(parseISO(info.getValue()), "dd MMMM, yyyy")} </p>
                  {format(parseISO(info.getValue()), "h aaaa")}
                </div>
              ) : null;
            },
          },
          {
            header: "Downloads",
            accessorKey: "_source.acquisition",
            cell: (info) => (
              <div className="flex flex-col gap-2 ml-3 my-3">
                <span className="inline-flex items-center w-fit bg-slate-50 text-slate-800 text-xs px-2 rounded-md dark:text-slate-900 dark:bg-slate-400">
                  <span className="pr-1 pt-1">
                    <i className="icon-[solar--folder-path-connect-bold-duotone] w-5 h-5"></i>
                  </span>
                  <span className="text-md text-slate-900 dark:text-slate-900">
                    DC++: {info.getValue().directconnect.downloads.length}
                  </span>
                </span>

                <span className="inline-flex w-fit items-center bg-slate-50 text-slate-800 text-xs px-2 rounded-md dark:text-slate-900 dark:bg-slate-400">
                  <span className="pr-1 pt-1">
                    <i className="icon-[solar--magnet-bold-duotone] w-5 h-5"></i>
                  </span>
                  <span className="text-md text-slate-900 dark:text-slate-900">
                    Torrent: {info.getValue().torrent.downloads.length}
                  </span>
                </span>
              </div>
            ),
          },
        ],
      },
    ],
    [],
  );

  /**
   * Pagination control that fetches the next x (pageSize) items
   * based on the y (pageIndex) offset from the ThreeTwo Elasticsearch index
   * @param {number} pageIndex
   * @param {number} pageSize
   * @returns void
   *
   **/
  const nextPage = (pageIndex: number, pageSize: number) => {
    if (!isPlaceholderData) {
      queryClient.invalidateQueries({ queryKey: ["comics"] });
      setSearchQuery({
        query: {},
        pagination: {
          size: 15,
          from: pageSize * pageIndex + 1,
        },
        type: "all",
        trigger: "libraryPage",
      });
      // setOffset(pageSize * pageIndex + 1);
    }
  };

  /**
   * Pagination control that fetches the previous x (pageSize) items
   * based on the y (pageIndex) offset from the ThreeTwo Elasticsearch index
   * @param {number} pageIndex
   * @param {number} pageSize
   * @returns void
   **/
  const previousPage = (pageIndex: number, pageSize: number) => {
    let from = 0;
    if (pageIndex === 2) {
      from = (pageIndex - 1) * pageSize + 2 - (pageSize + 2);
    } else {
      from = (pageIndex - 1) * pageSize + 2 - (pageSize + 1);
    }
    queryClient.invalidateQueries({ queryKey: ["comics"] });
    setSearchQuery({
      query: {},
      pagination: {
        size: 15,
        from,
      },
      type: "all",
      trigger: "libraryPage",
    });
    // setOffset(from);
  };

  // ImportStatus.propTypes = {
  //   value: PropTypes.bool.isRequired,
  // };
  return (
    <div>
      <section>
        <header className="bg-slate-200 dark:bg-slate-500">
          <div className="mx-auto max-w-screen-xl px-2 py-2 sm:px-6 sm:py-8 lg:px-8 lg:py-4">
            <div className="sm:flex sm:items-center sm:justify-between">
              <div className="text-center sm:text-left">
                <h1 className="text-2xl font-bold text-gray-900 dark:text-white sm:text-3xl">
                  Library
                </h1>

                <p className="mt-1.5 text-sm text-gray-500 dark:text-white">
                  Browse your comic book collection.
                </p>
              </div>
            </div>
          </div>
        </header>
        {!isUndefined(searchResults?.hits) ? (
          <div>
            <div>
              <T2Table
                totalPages={searchResults.hits.total.value}
                columns={columns}
                sourceData={searchResults?.hits.hits}
                rowClickHandler={navigateToComicDetail}
                paginationHandlers={{
                  nextPage,
                  previousPage,
                }}
              >
                <SearchBar searchHandler={(e) => searchIssues(e)} />
              </T2Table>
            </div>
          </div>
        ) : (
          <div className="mx-auto max-w-screen-xl mt-5">
            <article
              role="alert"
              className="rounded-lg max-w-screen-md border-s-4 border-yellow-500 bg-yellow-50 p-4 dark:border-s-4 dark:border-yellow-600 dark:bg-yellow-300 dark:text-slate-600"
            >
              <div>
                <p>
                  No comics were found in the library, Elasticsearch reports no
                  indices. Try importing a few comics into the library and come
                  back.
                </p>
              </div>
            </article>
            <div className="block max-w-md p-6 bg-white border border-gray-200 my-3 rounded-lg shadow dark:bg-slate-400 dark:border-gray-700">
              <pre className="text-sm font-hasklig text-slate-700 dark:text-slate-700">
                {!isUndefined(searchResults?.data?.meta?.body) ? (
                  <p>
                    {JSON.stringify(
                      searchResults?.data.meta.body.error.root_cause,
                      null,
                      4,
                    )}
                  </p>
                ) : null}
              </pre>
            </div>
          </div>
        )}
      </section>
    </div>
  );
};

export default Library;
