import React, { useEffect, useMemo, useState } from 'react'

import styles from './_pagination.module.scss'
import Button from '../Button/Button'
import Icon from '../Icons/Icon'
import { useIsMobileView } from '../../hooks/useIsMobileView/useIsMobileView'
import PaginationEllipsis from './PaginationEllipsis/PaginationEllipsis'
import { c } from '../../translations/LibraryTranslationService'

export type PaginationProps = {
  /** Total number of pages */
  totalPages: number
  /** Function to call when a new page is selected */
  callout: (page: number) => void
  /** The current page passed in by the parent */
  currentPage: number
  /** Optional prop to add a test id to the Pagination for QA testing */
  qaTestId?: string
}

const Pagination = ({
  totalPages,
  callout,
  currentPage,
  qaTestId = 'pagination',
}: PaginationProps): React.JSX.Element => {
  const [activePage, setActivePage] = useState(currentPage - 1)
  const lastPage = totalPages - 1

  const updatePage = (page: number) => {
    setActivePage(page)
    callout(page + 1)
  }
  const isMobileView = useIsMobileView()

  useEffect(() => {
    setActivePage(currentPage - 1)
  }, [currentPage])

  const options = useMemo(
    () =>
      Array.from({ length: totalPages }, (_, i) => ({
        name: (i + 1).toString(),
        label: (i + 1).toString(),
      })),
    [totalPages],
  )

  const renderPageButton = (page: number) => {
    // Digits counts the number of characters in the page number. This is used to help calculate how wide a button should be.
    const digits =
      (page + 1).toString().length <= 2 ? 1 : (page + 1).toString().length
    const width = {
      1: '32px',
      3: '40px',
      4: '48px',
      5: '56px',
      6: '64px',
    }[digits]

    return (
      <Button
        key={page}
        onClick={() => updatePage(page)}
        styleType='tertiary'
        style={{ width }}
        className={`${styles.button} ${
          activePage === page ? styles.active : ''
        }`}
        data-text={(page + 1).toLocaleString()}
      >
        <span className={styles.buttonContent}>{page + 1}</span>
      </Button>
    )
  }

  const renderPageButtons = () => {
    if (isMobileView) {
      return (
        <PaginationEllipsis
          activePage={activePage}
          position='end'
          lastPage={lastPage}
          updatePage={updatePage}
          pageOptions={options}
        />
      )
    }

    const buttons = []
    const maxNumOfPages = 7

    // Always show the first page
    buttons.push(renderPageButton(0))

    if (totalPages > maxNumOfPages) {
      const maxNumOfEllipsis = 2
      const showEllipsisAtStart = activePage > maxNumOfEllipsis + 1
      const showEllipsisAtEnd = lastPage - activePage > maxNumOfEllipsis + 1
      const paginationEllipsisProps = {
        updatePage,
        lastPage,
        activePage,
        pageOptions: options,
      }

      if (showEllipsisAtStart && showEllipsisAtEnd) {
        // Example: Ellipsis, 3, 4, 5, Ellipsis
        buttons.push(
          <PaginationEllipsis
            {...paginationEllipsisProps}
            key='start'
            position='start'
          />,
        )
        for (let i = activePage - 1; i <= activePage + 1; i++) {
          buttons.push(renderPageButton(i))
        }
        buttons.push(
          <PaginationEllipsis
            {...paginationEllipsisProps}
            key='end'
            position='end'
          />,
        )
      } else if (showEllipsisAtStart) {
        // Example: Ellipsis, 3, 4, 5, 6
        buttons.push(
          <PaginationEllipsis
            {...paginationEllipsisProps}
            key='start'
            position='start'
          />,
        )
        for (let i = lastPage - maxNumOfPages + 4; i <= lastPage; i++) {
          buttons.push(renderPageButton(i - 1))
        }
      } else if (showEllipsisAtEnd) {
        // Example: 2, 3, 4, 5, Ellipsis
        for (let i = 2; i <= maxNumOfPages - 2; i++) {
          buttons.push(renderPageButton(i - 1))
        }
        buttons.push(
          <PaginationEllipsis
            {...paginationEllipsisProps}
            key='end'
            position='end'
          />,
        )
      }
    } else {
      // Show all pages if total pages are less than or equal to maxNumOfPages
      for (let i = 2; i <= lastPage; i++) {
        buttons.push(renderPageButton(i - 1))
      }
    }

    // Always show the last page if there is more than one page
    totalPages > 1 && buttons.push(renderPageButton(lastPage))

    return buttons
  }

  if (currentPage <= 0) {
    throw new Error(c('errorPagination'))
  }
  return (
    <div className={styles.container} qa-test-id={qaTestId}>
      <Button
        styleType='tertiary'
        onClick={() => updatePage(activePage > 0 ? activePage - 1 : 0)}
        disabled={activePage === 0}
      >
        <Icon
          icon='popoverTriangle'
          iconSize='12px'
          className={`${styles.navIcon} ${styles.left} ${
            activePage === 0 ? styles.disabled : ''
          }`}
        />
      </Button>
      {renderPageButtons()}
      <Button
        styleType='tertiary'
        onClick={() =>
          updatePage(activePage < lastPage ? activePage + 1 : lastPage)
        }
        disabled={activePage === lastPage}
      >
        <Icon
          icon='popoverTriangle'
          iconSize='12px'
          className={`${styles.navIcon} ${styles.right} ${
            activePage === lastPage ? styles.disabled : ''
          }`}
        />
      </Button>
    </div>
  )
}

export default Pagination
