import { MouseEvent, useCallback, useEffect, useState } from 'react';
import { PaginationProps } from '@theme/components/types';
import { twMerge } from 'tailwind-merge';
import clsx from 'clsx';
import { Link, Button, LoaderSpinner } from '@theme/components';
import usePagination from '@akinon/next/hooks/use-pagination';
import { useLocalization } from '@akinon/next/hooks';
import { useRouter } from '@akinon/next/hooks';
import { useInView } from 'react-intersection-observer';

const parseSafeUrl = (url: string) => {
  try {
    return new URL(url, window.location.origin);
  } catch {
    return null;
  }
};

export const Pagination = (props: PaginationProps) => {
  const { t } = useLocalization();
  const router = useRouter();
  const {
    total,
    limit,
    currentPage,
    numberOfPages,
    containerClassName,
    prevClassName,
    pageClassName,
    nextClassName,
    moreButtonClassName,
    threshold = 1,
    type = 'list',
    onPageChange,
    direction,
    render,
    isLoading,
    customStyles
  } = props;

  const pagination = usePagination(total, limit, currentPage, numberOfPages);
  const {
    total: paginationTotal,
    limit: paginationLimit,
    page,
    pageList,
    prev,
    next,
    last,
    setTotal,
    setLimit
  } = pagination;

  const [paginationItems, setPaginationItems] = useState([]);
  const showNext = currentPage * paginationLimit < paginationTotal;
  const { ref, inView } = useInView({ threshold: 0.75 });
  const [prevPage, setPrevPage] = useState(page);
  const [nextPage, setNextPage] = useState(page);

  const createListItems = useCallback(() => {
    setPaginationItems([]);
    const delta = 2;
    const startPage = Math.max(Number(page) - delta, 1);
    const endPage = Math.min(Number(page) + delta, numberOfPages);

    setPaginationItems((prev) => [
      ...prev,
      {
        page: pageList[0].page,
        url: pageList[0].url
      }
    ]);

    if (delta < startPage) {
      setPaginationItems((prev) => [...prev, { page: '...', url: '#' }]);
    }

    for (let i = startPage; i <= endPage; i++) {
      if (i === 1) continue;

      setPaginationItems((prev) => [
        ...prev,
        {
          page: pageList[i - 1]?.page,
          url: pageList[i - 1]?.url
        }
      ]);
    }

    if (endPage < numberOfPages - threshold) {
      setPaginationItems((prev) => [...prev, { page: '...', url: '#' }]);
    }

    if (page < numberOfPages - delta) {
      setPaginationItems((prev) => [
        ...prev,
        {
          page: pageList[pageList.length - threshold].page,
          url: pageList[pageList.length - threshold].url
        }
      ]);
    }
  }, [numberOfPages, page, pageList, threshold]);

  const handleClick = (e: MouseEvent<HTMLAnchorElement>, url: string) => {
    e.preventDefault();

    const newUrl = parseSafeUrl(url);
    if (!newUrl) {
      return;
    }

    const page = newUrl.searchParams.get('page');

    if (page === '1') {
      newUrl.searchParams.delete('page');
    }

    router.push(newUrl.pathname + newUrl.search, undefined);
  };

  const handlePageChange = () => {
    let changingPage;

    if (direction === 'prev') {
      changingPage = Number(type !== 'list' ? prevPage : page) - 1;
      setPrevPage(changingPage);
    } else {
      changingPage = Number(type !== 'list' ? nextPage : page) + 1;
      setNextPage(changingPage);
    }

    // Navigate to new page using router if onPageChange is not provided
    if (onPageChange) {
      onPageChange(changingPage);
    } else {
      const currentUrl = parseSafeUrl(window.location.href);
      if (!currentUrl) {
        return;
      }

      currentUrl.searchParams.set('page', String(changingPage));
      if (changingPage === 1) {
        currentUrl.searchParams.delete('page');
      }
      router.push(currentUrl.pathname + currentUrl.search, undefined);
    }
  };

  useEffect(() => {
    if (type === 'infinite' && page === 1) {
      setPrevPage(1);
      setNextPage(1);
    }
    // eslint-disable-next-line react-hooks/exhaustive-deps
  }, [page]);

  useEffect(() => {
    if (inView) {
      handlePageChange();
    }
  }, [inView]); // eslint-disable-line react-hooks/exhaustive-deps

  useEffect(() => {
    if (type === 'list') {
      createListItems();
    }
  }, [page]); // eslint-disable-line react-hooks/exhaustive-deps

  useEffect(() => {
    if (total && total !== paginationTotal) {
      setTotal(total);
    }
  }, [total, paginationTotal, setTotal]);

  useEffect(() => {
    if (limit && limit !== paginationLimit) {
      setLimit(limit);
    }
  }, [limit, paginationLimit, setLimit]);

  if (render) {
    return <>{render(pagination)}</>;
  }

  // Custom styles for pagination container
  const containerStyles: React.CSSProperties = {
    marginTop: customStyles?.marginTop || '32px',
    marginBottom: customStyles?.marginBottom || '16px',
    gap: customStyles?.pageGap || '8px'
  };

  // Custom styles for page links (button-like)
  const pageStyles: React.CSSProperties = {
    fontSize: customStyles?.pageFontSize || '14px',
    color: customStyles?.pageColor || '#9ca3af',
    backgroundColor: customStyles?.pageBgColor || 'transparent',
    paddingLeft: customStyles?.pagePaddingX || '8px',
    paddingRight: customStyles?.pagePaddingX || '8px',
    paddingTop: customStyles?.pagePaddingY || '4px',
    paddingBottom: customStyles?.pagePaddingY || '4px',
    borderRadius: customStyles?.pageBorderRadius || '0px',
    borderWidth: customStyles?.pageBorderWidth || '0px',
    borderStyle: 'solid',
    borderColor: customStyles?.pageBorderColor || '#e5e7eb',
    display: 'flex',
    alignItems: 'center',
    justifyContent: 'center'
  };

  const activePageStyles: React.CSSProperties = {
    fontSize: customStyles?.pageFontSize || '14px',
    color: customStyles?.pageActiveColor || '#1a1a1a',
    fontWeight: customStyles?.pageActiveFontWeight || '600',
    backgroundColor: customStyles?.pageActiveBgColor || 'transparent',
    paddingLeft: customStyles?.pagePaddingX || '8px',
    paddingRight: customStyles?.pagePaddingX || '8px',
    paddingTop: customStyles?.pagePaddingY || '4px',
    paddingBottom: customStyles?.pagePaddingY || '4px',
    borderRadius: customStyles?.pageBorderRadius || '0px',
    borderWidth: customStyles?.pageBorderWidth || '0px',
    borderStyle: 'solid',
    borderColor: customStyles?.pageActiveBorderColor || '#1a1a1a',
    display: 'flex',
    alignItems: 'center',
    justifyContent: 'center'
  };

  const arrowStyles: React.CSSProperties = {
    color: customStyles?.arrowColor || '#1a1a1a'
  };

  // Custom styles for more button
  const buttonStyles: React.CSSProperties = {
    backgroundColor: customStyles?.buttonBgColor || '#000000',
    color: customStyles?.buttonTextColor || '#ffffff',
    borderRadius: customStyles?.buttonBorderRadius || '4px',
    paddingLeft: customStyles?.buttonPaddingX || '20px',
    paddingRight: customStyles?.buttonPaddingX || '20px',
    paddingTop: customStyles?.buttonPaddingY || '12px',
    paddingBottom: customStyles?.buttonPaddingY || '12px'
  };

  return direction === 'prev' && type !== 'list' ? (
    <>
      <div
        className="flex items-center justify-center"
        style={{
          marginTop: customStyles?.marginTop,
          marginBottom: customStyles?.marginBottom
        }}
        data-section-id="pagination-section"
      >
        <Button
          className={twMerge('px-5', moreButtonClassName)}
          style={buttonStyles}
          onClick={() => handlePageChange()}
        >
          {isLoading ? (
            <LoaderSpinner className="h-4 w-4" />
          ) : (
            t('category.pagination.load_previous_page')
          )}
        </Button>
      </div>
    </>
  ) : (
    <>
      {type === 'more' && (
        <div
          className="flex items-center justify-center"
          style={{
            marginTop: customStyles?.marginTop,
            marginBottom: customStyles?.marginBottom
          }}
          data-section-id="pagination-section"
        >
          <Button
            className={twMerge(
              Number(nextPage) === Number(last) ? 'pointer-events-none' : '',
              moreButtonClassName
            )}
            style={{
              ...buttonStyles,
              backgroundColor:
                Number(nextPage) === Number(last)
                  ? '#6b7280'
                  : customStyles?.buttonBgColor || '#000000'
            }}
            onClick={() => handlePageChange()}
            disabled={Number(nextPage) === Number(last)}
          >
            {isLoading ? (
              <LoaderSpinner className="h-4 w-4" />
            ) : (
              t('category.pagination.more')
            )}
          </Button>
        </div>
      )}

      {type === 'infinite' && Number(nextPage) !== last && (
        <div ref={ref}></div>
      )}

      {(type === 'infinite' || type === 'more') &&
        Number(nextPage) === last &&
        !isLoading && (
          <p className="mt-8 text-center">
            {t('category.pagination.shown_items')}
          </p>
        )}

      {type === 'list' && (
        <ul
          className={twMerge(
            'flex items-center justify-center',
            containerClassName
          )}
          style={containerStyles}
          data-section-id="pagination-section"
        >
          {prev && currentPage !== 1 && (
            <li>
              <Link
                onClick={(e) => handleClick(e, prev)}
                href={prev}
                className={twMerge(
                  'flex cursor-pointer px-2 items-center',
                  prevClassName
                )}
                style={arrowStyles}
              >
                <span>&lt;</span>
                <span className="ms-4 hidden lg:inline-block">
                  {t('category.pagination.previous')}
                </span>
              </Link>
            </li>
          )}

          {paginationItems.map((item, i) => (
            <li key={i}>
              {item?.url != '#' ? (
                <Link
                  onClick={(e) => handleClick(e, item.url)}
                  href={item.url}
                  className={twMerge(
                    clsx('cursor-pointer px-2 items-center', {
                      'pointer-events-none': item.url === null
                    }),
                    pageClassName
                  )}
                  style={
                    Number(page) === Number(item?.page)
                      ? activePageStyles
                      : pageStyles
                  }
                >
                  {item?.page}
                </Link>
              ) : (
                <span
                  className="flex cursor-default items-center justify-center"
                  style={pageStyles}
                >
                  {item?.page}
                </span>
              )}
            </li>
          ))}

          {showNext && (
            <li>
              <Link
                onClick={(e) => handleClick(e, next)}
                href={next}
                className={twMerge(
                  'flex cursor-pointer px-2 items-center',
                  nextClassName
                )}
                style={arrowStyles}
              >
                <span className="me-4 hidden lg:inline-block">
                  {t('category.pagination.next')}
                </span>
                <span>&gt;</span>
              </Link>
            </li>
          )}
        </ul>
      )}
    </>
  );
};
