import React, { Dispatch, SetStateAction, useCallback, useMemo } from 'react';
import { usePaginationContext } from './pagination-context';
import { PaginationEllipsis } from './pagination-ellipsis';
import { PaginationItem } from './pagination-item';

type Props = {
  limit: number;
  count: number;
  current: number;
  setPage: Dispatch<SetStateAction<number>>;
};

export const PaginationPages: React.FC<Props> = ({ limit, count, current, setPage }) => {
  const { resolveUrl } = usePaginationContext();

  const showPages = useMemo(() => {
    const oddLimit = limit % 2 === 0 ? limit - 1 : limit;
    return oddLimit - 2;
  }, [limit]);

  const middleNumber = (showPages + 1) / 2;

  const [showBeforeEllipsis, showAfterEllipsis] = useMemo((): [boolean, boolean] => {
    const showEllipsis = count > limit;
    return [
      showEllipsis && current > middleNumber + 1,
      showEllipsis && current < count - middleNumber,
    ];
  }, [current, middleNumber, count, limit]);

  const pagesArray = useMemo(() => [...new Array(showPages)], [showPages]);

  const renderItem = useCallback((value: number, active: number) => (
    <PaginationItem
      key={`pagination-item-${value}`}
      aria-label={`page ${value}`}
      active={value === active}
      onClick={() => setPage(value)}
      href={resolveUrl(value)}
    >
      {value}
    </PaginationItem>
  ), [setPage]);

  const renderStartItems = pagesArray.map((_, index) => {
    const value = index + 2;
    return renderItem(value, current);
  });

  const renderMiddleItems = pagesArray.map((_, index) => {
    const middleIndexNumber = middleNumber - (index + 1);
    const value = current - middleIndexNumber;
    return (
      <PaginationItem
        key={`pagination-middle-${index}`}
        aria-label={`page ${value}`}
        active={index + 1 === middleNumber}
        onClick={() => setPage(value)}
        href={resolveUrl(value)}
      >
        {value}
      </PaginationItem>
    );
  });

  const renderEndItems = pagesArray.map((_, index) => {
    const value = count - (showPages - index);
    return renderItem(value, current);
  });

  if (count <= limit) {
    /* eslint-disable react/jsx-no-useless-fragment */
    return (
      <>
        {[...new Array(count)].map((_, index) => {
          const value = index + 1;
          return (
            <PaginationItem
              key={`pagination-item-${value}`}
              aria-label={`page ${value}`}
              active={value === current}
              onClick={() => setPage(value)}
              href={resolveUrl(value)}
            >
              {value}
            </PaginationItem>
          );
        })}
      </>
    );
    /* eslint-enable */
  }
  return (
    <>
      {renderItem(1, current)}
      {showBeforeEllipsis && (
        <PaginationEllipsis
          key="pagination-ellipsis-before"
          aria-label="previous pages"
          isBefore
          onClick={() => setPage(last => (last - 5 >= 1 ? last - 5 : 1))}
        />
      )}
      {showBeforeEllipsis && showAfterEllipsis ? renderMiddleItems :
        (showBeforeEllipsis ? renderEndItems : renderStartItems)
      }
      {showAfterEllipsis && (
        <PaginationEllipsis
          key="pagination-ellipsis-after"
          aria-label="next pages"
          onClick={() => setPage(last => (last + 5 <= count ? last + 5 : count))}
        />
      )}
      {renderItem(count, current)}
    </>
  );
};

PaginationPages.displayName = 'PaginationPages';
