import clsx from "clsx";
import { ReactNode } from "react";
import { createRange } from "#lib/range";
import { PAGINATION_LIMIT } from "#lib/pagination";
import { KemonoLink } from "#components/links";

interface IProps {
  count: number;
  true_count?: number;
  offset?: number;
  constructURL: (offset: number) => string;
}

interface IPaginatorButtonProps {
  href?: string;
  className?: string;
  children: ReactNode;
}

export function Paginator({
  count,
  true_count,
  offset = 0,
  constructURL,
}: IProps) {
  const limit = PAGINATION_LIMIT;
  const skip = offset;
  const currentCeilingOfRange = skip + limit < count ? skip + limit : count;
  const totalButtons = 5;
  const optionalButtons = totalButtons - 2;
  const mandatoryButtons = totalButtons - optionalButtons;
  const currentPageNumber = Math.ceil((skip + limit) / limit);
  const totalPages = Math.ceil(count / limit);
  const numberBeforeCurrentPage =
    totalPages < totalButtons || currentPageNumber < totalButtons
      ? currentPageNumber - 1
      : totalPages - currentPageNumber < totalButtons
      ? totalButtons - 1 + (totalButtons - (totalPages - currentPageNumber))
      : totalButtons - 1;
  const basePageNumber = Math.max(
    currentPageNumber - numberBeforeCurrentPage - 1,
    1
  );
  const showFirstPostsButton = basePageNumber > 1;
  const showLastPostsButton =
    currentPageNumber - basePageNumber <
    totalButtons +
      (currentPageNumber - basePageNumber < totalButtons
        ? totalButtons - (currentPageNumber + basePageNumber)
        : 0);
  const optionalBeforeButtons =
    currentPageNumber -
    mandatoryButtons -
    (totalPages - currentPageNumber < mandatoryButtons
      ? mandatoryButtons - (totalPages - currentPageNumber)
      : 0);
  const optionalAfterButtons =
    currentPageNumber +
    mandatoryButtons +
    (currentPageNumber - basePageNumber < mandatoryButtons
      ? mandatoryButtons - (currentPageNumber - basePageNumber)
      : 0);
  const range = createRange(0, totalButtons * 2 + 1);

  if (!(count > limit)) {
    return undefined;
  }

  return (
    <>
      <small>
        Showing {skip + 1} - {currentCeilingOfRange} of {true_count || count}
      </small>

      <menu>
        {!(
          showFirstPostsButton || showLastPostsButton
        ) ? undefined : showFirstPostsButton ? (
          <PaginatorButton href={constructURL(0)}>{"<<"}</PaginatorButton>
        ) : (
          <PaginatorButton
            className={clsx(
              "pagination-button-disabled",
              currentPageNumber - mandatoryButtons - 1 && "pagination-desktop"
            )}
          >
            {"<<"}
          </PaginatorButton>
        )}

        {showFirstPostsButton ? undefined : currentPageNumber -
          mandatoryButtons -
          1 ? (
          <PaginatorButton className="pagination-mobile" href={constructURL(0)}>
            {"<<"}
          </PaginatorButton>
        ) : totalPages - currentPageNumber > mandatoryButtons &&
          !showLastPostsButton ? (
          <PaginatorButton
            className={clsx("pagination-button-disabled", "pagination-mobile")}
          >
            {"<<"}
          </PaginatorButton>
        ) : undefined}

        {currentPageNumber > 1 ? (
          <PaginatorButton
            className="prev"
            href={constructURL((currentPageNumber - 2) * limit)}
          >
            {"<"}
          </PaginatorButton>
        ) : (
          <PaginatorButton className="pagination-button-disabled">
            {"<"}
          </PaginatorButton>
        )}

        {range.reduce<JSX.Element[]>((buttons, page, index) => {
          if (page + basePageNumber && page + basePageNumber <= totalPages) {
            const localOffset =
              page + basePageNumber !== 1
                ? (page + basePageNumber - 1) * limit
                : 0;
            const buttonClassName =
              page + basePageNumber < optionalBeforeButtons ||
              (page + basePageNumber > optionalAfterButtons &&
                page + basePageNumber != currentPageNumber)
                ? "pagination-button-optional"
                : page + basePageNumber == currentPageNumber
                ? clsx(
                    "pagination-button-disabled",
                    "pagination-button-current"
                  )
                : page + basePageNumber == currentPageNumber + 1
                ? "pagination-button-after-current"
                : undefined;
            const button = (
              <PaginatorButton
                key={index}
                href={
                  page + basePageNumber === currentPageNumber
                    ? undefined
                    : constructURL(localOffset)
                }
                className={clsx(buttonClassName)}
              >
                {page + basePageNumber}
              </PaginatorButton>
            );

            buttons.push(button);
          }

          return buttons;
        }, [])}

        {currentPageNumber < totalPages ? (
          <PaginatorButton
            className="next"
            href={constructURL(currentPageNumber * limit)}
          >
            {">"}
          </PaginatorButton>
        ) : (
          <PaginatorButton
            className={clsx(
              "pagination-button-disabled",
              totalPages && " pagination-button-after-current"
            )}
          >
            {">"}
          </PaginatorButton>
        )}

        {!(
          showFirstPostsButton || showLastPostsButton
        ) ? undefined : showLastPostsButton ? (
          <PaginatorButton href={constructURL((totalPages - 1) * limit)}>
            {">>"}
          </PaginatorButton>
        ) : (
          <PaginatorButton
            className={clsx(
              "pagination-button-disabled",
              totalPages - currentPageNumber > mandatoryButtons &&
                "pagination-desktop"
            )}
          >
            {">>"}
          </PaginatorButton>
        )}

        {showLastPostsButton ? undefined : totalPages - currentPageNumber >
          mandatoryButtons ? (
          <PaginatorButton
            href={constructURL((totalPages - 1) * limit)}
            className="pagination-mobile"
          >
            {">>"}
          </PaginatorButton>
        ) : currentPageNumber > optionalButtons && !showFirstPostsButton ? (
          <PaginatorButton
            className={clsx("pagination-button-disabled", "pagination-mobile")}
          >
            {">>"}
          </PaginatorButton>
        ) : undefined}
      </menu>
    </>
  );
}

function PaginatorButton({ href, className, children }: IPaginatorButtonProps) {
  return href ? (
    <KemonoLink url={href} className={className}>
      <b>{children}</b>
    </KemonoLink>
  ) : (
    <li className={className}>
      <b>{children}</b>
    </li>
  );
}
