/*
                   _             _   _
                  (_)           | | (_)
 _ __   __ _  __ _ _ _ __   __ _| |_ _  ___  _ __
| '_ \ / _` |/ _` | | '_ \ / _` | __| |/ _ \| '_ \
| |_) | (_| | (_| | | | | | (_| | |_| | (_) | | | |
| .__/ \__,_|\__, |_|_| |_|\__,_|\__|_|\___/|_| |_|
| |           __/ |
|_|          |___/

TODOs
  - add styling for disabled (unavailable) and current+disabled
    - apply `aria-current`, `.current`, `aria-disabled`, `.disabled`, `disabled`, and `tabindex="-1"` to manage current and disabled states
  - abstract the page URL generation pattern, since it is platform specific
  - ellipsis logic should maintain the length of the button-group at all times
    - use the truncation function to manage number of links
    - apply ellipses where necessary

*/

import { faChevronLeft } from '@fortawesome/pro-solid-svg-icons/faChevronLeft';
import { faChevronRight } from '@fortawesome/pro-solid-svg-icons/faChevronRight';
import { faEllipsisH } from '@fortawesome/pro-solid-svg-icons/faEllipsisH';
import { useRouter } from 'next/router';
import cn from 'clsx';
import React from 'react';

import { useApp } from '../../app';
import { FaIcon } from '../../elements/icon';
import { Chain, Stack, Div } from '../../system';
import { pageLink, prevNextBtn } from './pagination.module.scss';

function truncatePages(pageNums, currPage = 1, maxPages = 7) {
  // assert hard minimum number of links
  maxPages = Math.max(maxPages, 5);
  const numsLength = pageNums.length;
  // return pageNums as is, if under max length
  if (numsLength <= maxPages) return pageNums;
  // if within first N pages...
  if (currPage <= Math.ceil(maxPages / 2))
    return [...pageNums.slice(0, maxPages - 2), '_', ...pageNums.slice(-1)];
  // if within last N pages...
  if (currPage >= numsLength - Math.floor(maxPages / 2))
    return [...pageNums.slice(0, 1), '_', ...pageNums.slice(0 - maxPages + 2)];
  // if in the middle range...
  const offset = Math.ceil((maxPages - 4) / 2);
  return [
    ...pageNums.slice(0, 1),
    '_',
    ...pageNums.slice(currPage - offset, currPage + offset - 1),
    '_',
    ...pageNums.slice(-1),
  ];
}

/**
 * NOTE: this assumes Next.js router props and the `/page/[n]` pagination routing pattern
 * TODO: make this framework-agnostic
 * @param {number} n page number
 * @param {object} query params from router
 * @param {string} route route with params in square brackets
 * @returns string
 */
function paginationHref(n, query, route) {
  // set `query.n` to new `n`
  Object.assign(query, { n });
  // strip pagination from route if present
  route = route.replace(/\/page\/\[.+\]$/, '');
  // reduce the query to a new href string
  return Object.keys(query)
    .reduce((str, key) => {
      const RE = new RegExp(`\\[${key}\\]`);
      return str.replace(RE, query[key]);
    }, route + (n == 1 ? '/' : '/page/[n]'))
    .replace(/\/\//g, '/');
}

export function Pagination({ currPage, pageSize, itemCount, ...rest }) {
  const { Link, Head } = useApp();
  const { route, query } = useRouter();
  currPage = Number(currPage);
  const pageCount = Math.ceil(itemCount / pageSize);
  const pageNumbers = Array(pageCount)
    .fill()
    .map((_, n) => n + 1);
  const pageItemRanges = [];
  for (let index = 0; index < pageCount; index++) {
    pageItemRanges.push([Math.max(0, index * pageSize + 1), Math.min(itemCount, (index + 1) * pageSize)]);
  }
  const itemRange = pageItemRanges[currPage - 1] || [];
  const pageHref = (n) => paginationHref(n, query, route);
  const isFirst = currPage == 1;
  const isLast = currPage == pageCount;
  return (
    <>
      <Head>
        {!isFirst && <link rel="prev" href={`/blog${pageHref(currPage - 1)}`} key="prev" />}
        {!isLast && <link rel="next" href={`/blog${pageHref(currPage + 1)}`} key="next" />}
      </Head>
      <Stack
        // nav
        as="nav"
        role="navigation"
        aria-label="pagination"
        // stack
        gapY={16}
        maxW="max-content"
        className="pagination ta-center mx-auto ui-action"
        {...rest}
      >
        <Div fz={14} className="trim fg-tone-10 fw-normal">
          <span>
            Posts {itemRange[0]} – {itemRange[1]} of {itemCount}
          </span>
        </Div>
        <Chain fz={{ _: 14, m: 16 }} as="ol" role="list" gap={5} className="jc-center">
          <li>
            {isFirst ? (
              <span className={cn(pageLink, prevNextBtn, 'btn page-link page-prev')} aria-disabled>
                <FaIcon icon={faChevronLeft} label="previous page" />
              </span>
            ) : (
              <Link
                scroll={false}
                className={cn(pageLink, prevNextBtn, 'btn page-link page-prev')}
                href={pageHref(currPage - 1)}
                aria-label={`Go To Page ${currPage - 1}`}
              >
                <FaIcon icon={faChevronLeft} label="previous page" />
              </Link>
            )}
          </li>
          {truncatePages(pageNumbers, currPage, 5).map((pageNumber, i) => {
            if (pageNumber == '_')
              return (
                <li key={`page-ellipsis-${i}`}>
                  <span className={cn(pageLink, 'btn page-link')}>
                    <FaIcon icon={faEllipsisH} label="previous page" />
                  </span>
                </li>
              );
            const isCurr = pageNumber == currPage;
            return (
              <li key={`page-${pageNumber}`}>
                <Link
                  scroll={false}
                  className={cn(pageLink, 'btn page-link')}
                  href={pageHref(pageNumber)}
                  aria-label={isCurr ? `Current Page, Page ${pageNumber}` : undefined}
                  aria-disabled={isCurr ? true : undefined}
                  aria-current={isCurr ? 'page' : undefined}
                >
                  {pageNumber}
                  <span className="v-hide">
                    page {pageNumber} of {pageCount}
                  </span>
                </Link>
              </li>
            );
          })}
          <li>
            {isLast ? (
              <span className={cn(pageLink, prevNextBtn, 'btn page-link page-next')} aria-disabled>
                <FaIcon icon={faChevronRight} label="next page" />
              </span>
            ) : (
              <Link
                scroll={false}
                className={cn(pageLink, prevNextBtn, 'btn page-link page-next')}
                href={pageHref(currPage + 1)}
                aria-label={`Go To Page ${1}`}
              >
                <FaIcon icon={faChevronRight} label="next page" />
              </Link>
            )}
          </li>
        </Chain>
      </Stack>
    </>
  );
}
