import { useCallback, useMemo } from '@wordpress/element';
import clsx from 'clsx';

export interface PaginationProps {
  total: number;
  page: number;
  pageSize?: number;
  onPageChange: (page: number) => void;
}

interface PaginationNumIconProps {
  page: number;
  number: number;
  onClick: (page: number) => void;
}

const PREFIX = 'lks-pagination';
const SHOW_MIDDLE_PAGE_NUM = 5;
const SHOW_MORE_ICON_NUM = SHOW_MIDDLE_PAGE_NUM - 2;

export const PaginationNumIcon = ({
  number,
  page,
  onClick,
}: PaginationNumIconProps) => (
  <li
    onClick={() => onClick(number)}
    className={clsx(
      `${PREFIX}__btn`,
      `${PREFIX}__btn--number`,
      `${PREFIX}__btn--${number}`,
      {
        [`${PREFIX}__btn--active`]: page === number,
      },
    )}
  >
    {number}
  </li>
);

export const Pagination = ({
  total,
  page,
  pageSize = 10,
  onPageChange,
}: PaginationProps) => {
  const pageTotal = useMemo(
    () => Math.ceil(total / pageSize),
    [total, pageSize],
  );
  const pageNumberList = useMemo<number[]>(
    () => new Array(pageTotal).fill(1).map((num, index) => num + index),
    [pageTotal],
  );
  const previousDisabled = useMemo(() => page <= 1, [page]);
  const nextDisabled = useMemo(
    () => !pageTotal || page >= pageTotal,
    [page, pageTotal],
  );
  const showMorePreviousIcon = useMemo(
    () => !!page && page - SHOW_MORE_ICON_NUM > 1,
    [page],
  );
  const showMoreNextIcon = useMemo(
    () => !!pageTotal && pageTotal - SHOW_MORE_ICON_NUM > page,
    [page, pageTotal],
  );
  const shownPageNumberList = useMemo(() => {
    const numberList = [...pageNumberList];
    const startNum = numberList.shift() || 1;
    const endNum = numberList.pop();

    const middleAverage = Math.floor(SHOW_MIDDLE_PAGE_NUM / 2);
    const middleRangeStartIndex = Math.min(
      Math.max(page - SHOW_MIDDLE_PAGE_NUM + 1, 0),
      pageTotal - SHOW_MIDDLE_PAGE_NUM - 1,
    );
    const middleRangeEndIndex = Math.max(
      Math.min(page + middleAverage - 1, numberList.length),
      SHOW_MIDDLE_PAGE_NUM - 1,
    );
    const middleNumberList = numberList.slice(
      middleRangeStartIndex,
      middleRangeEndIndex,
    );

    return {
      startNum,
      endNum,
      middleNumberList,
    };
  }, [page, pageTotal, pageNumberList]);

  const handleChangePage = useCallback(
    (pageValue: number) => {
      const nextPage = Math.max(1, Math.min(pageValue, pageTotal));
      onPageChange?.(nextPage);
    },
    [pageTotal, onPageChange],
  );

  return (
    <ul className={PREFIX}>
      <li
        onClick={() => handleChangePage(page - 1)}
        className={clsx(`${PREFIX}__btn`, `${PREFIX}__btn__left`, {
          [`${PREFIX}__btn--disabled`]: previousDisabled,
        })}
      >
        {'<'}
      </li>
      <PaginationNumIcon
        page={page}
        number={shownPageNumberList.startNum}
        onClick={handleChangePage}
      />
      {showMorePreviousIcon && (
        <li
          onClick={() => handleChangePage(page - SHOW_MIDDLE_PAGE_NUM)}
          className={clsx(`${PREFIX}__btn`, `${PREFIX}__btn__more-previous`)}
        >
          {'<<'}
        </li>
      )}
      {shownPageNumberList.middleNumberList.map(number => (
        <PaginationNumIcon
          key={number}
          page={page}
          number={number}
          onClick={handleChangePage}
        />
      ))}
      {showMoreNextIcon && (
        <li
          onClick={() => handleChangePage(page + SHOW_MIDDLE_PAGE_NUM)}
          className={clsx(`${PREFIX}__btn`, `${PREFIX}__btn__more-next`)}
        >
          {'>>'}
        </li>
      )}
      {shownPageNumberList.endNum && (
        <PaginationNumIcon
          page={page}
          number={shownPageNumberList.endNum}
          onClick={handleChangePage}
        />
      )}
      <li
        onClick={() => handleChangePage(page + 1)}
        className={clsx(`${PREFIX}__btn`, `${PREFIX}__btn__left`, {
          [`${PREFIX}__btn--disabled`]: nextDisabled,
        })}
      >
        {'>'}
      </li>
    </ul>
  );
};
