import React, { useRef, useMemo, useCallback } from 'react';
import { bem } from 'utils/bem';
import { BgStyle } from 'common/styles/utils';
import { ITEMS_PER_PAGE } from 'common/constants';
import { SDropdownText } from 'common/s-components/table/s-dropdown-text';
import { SPagination } from 'common/s-components/table/s-pagination';
import { SArrow } from 'common/s-components/table/s-pagination-arrow';
import { SArrowWrapper } from 'common/s-components/table/s-pagination-arrow-wrapper';
import { SGoto } from 'common/s-components/table/s-goto';
import { Dropdown } from 'common/components/dropdown';
import { getPages } from './transducers';
import { Pagination } from './types';

interface Props {
  pagination: Pagination;
  onChange(pagination: Pagination): void;
  className?: string;
  widgetsBgStyle?: BgStyle;
}

const classes = bem('pagination');

export const CommonPagination = React.memo(({ pagination, onChange, className, widgetsBgStyle }: Props) => {
  const { total, pageSize, current } = pagination;
  const numberOfPages = Math.ceil(total / pageSize);

  const goToInput = useRef<HTMLInputElement>(null);

  const handlePageNumberChange = useCallback(
    (value: number) => {
      if (pageSize === value) return;

      onChange({
        ...pagination,
        current: 1,
        pageSize: value,
      });
    },
    [pageSize, pagination, onChange]
  );

  const handleChangePage = useCallback(
    (current: number) => {
      onChange({
        ...pagination,
        current,
      });
    },
    [pagination, onChange]
  );

  const pages = useMemo(() => getPages(numberOfPages, current), [numberOfPages, current]);

  const renderPrev = useCallback(() => {
    const disabled = current === 1;
    return (
      <SArrowWrapper
        className={classes('wrapper', {
          disabled,
        })}
        data-selector="previous-page"
        onClick={() => {
          if (!disabled) handleChangePage(current - 1);
        }}
      >
        <SArrow className={classes('arrow', { disabled, left: true })} />
      </SArrowWrapper>
    );
  }, [current, handleChangePage]);

  const renderNext = useCallback(() => {
    const disabled = current === numberOfPages;
    return (
      <SArrowWrapper
        className={classes('wrapper', {
          disabled,
        })}
        data-selector="next-page"
        onClick={() => {
          if (!disabled) handleChangePage(current + 1);
        }}
      >
        <SArrow
          className={classes('arrow', {
            disabled,
            right: true,
          })}
        />
      </SArrowWrapper>
    );
  }, [current, numberOfPages, handleChangePage]);

  const renderPagination = useCallback(
    () =>
      pages.map(page => (
        <div key={page}>
          {page >= 0 ? (
            <span
              className={classes('page', {
                active: current === page,
              })}
              data-selector={`page-${page}`}
              onClick={() => {
                if (current !== page) {
                  handleChangePage(page);
                }
              }}
            >
              {page}
            </span>
          ) : (
            <span className={classes('dots')}>...</span>
          )}
        </div>
      )),
    [pages, current, handleChangePage]
  );

  const handleGoTo = useCallback(() => {
    if (!goToInput.current) return;

    const pageString = goToInput.current.value?.replace(/[^0-9]+/g, '').trim();
    if (!pageString) return;

    goToInput.current.value = pageString;

    const page = parseInt(pageString, 10);
    if (page <= numberOfPages && page > 0 && page !== current) {
      handleChangePage(page);
    }
  }, [goToInput, numberOfPages, current, handleChangePage]);

  const renderGoTo = useCallback(() => {
    if (numberOfPages <= 1) return null;

    return (
      <SGoto className={classes('goto')} bgStyle={widgetsBgStyle}>
        <span className={classes('goto-text')}>Go to</span>
        <input data-selector="go-to-page" ref={goToInput} className={classes('goto-input')} onInput={handleGoTo} />
      </SGoto>
    );
  }, [numberOfPages, goToInput, handleGoTo, widgetsBgStyle]);

  const resultsFrom = `${(pageSize * (current - 1)) / 10}1`;
  const resultsTo = Math.min(pageSize * current, total);

  return (
    <SPagination className={className}>
      <ul className={classes('list', 'left')}>
        <li className={classes('item', 'left')}>
          <span className={classes('text')}>
            Showing{' '}
            <b>
              {resultsFrom} – {resultsTo}
            </b>{' '}
            of <b data-selector="perf-table-pagination">{total}</b> results
          </span>
        </li>
        <li className={classes('item', 'middle')}>
          {renderPrev()}
          {renderPagination()}
          {renderNext()}
        </li>
        <li className={classes('item', 'right')}>
          <Dropdown
            bgStyle={widgetsBgStyle}
            dataSelector="per-page-dropdown"
            className={classes('dropdown')}
            title={<span className={classes('dropdown-title')}>{pageSize} / page</span>}
          >
            {ITEMS_PER_PAGE.map(number => (
              <Dropdown.Option
                key={number.id}
                dataSelector={`per-page-${number.value}-option`}
                onClick={() => handlePageNumberChange(number.value)}
              >
                <SDropdownText
                  className={classes('items-per-page', {
                    active: number.value === pageSize,
                  })}
                >
                  {number.text}
                </SDropdownText>
              </Dropdown.Option>
            ))}
          </Dropdown>
          {renderGoTo()}
        </li>
      </ul>
    </SPagination>
  );
});
