import React, { useCallback, useEffect, useMemo, useState } from 'react';
import {
  ChevronLeftIcon,
  ChevronRightIcon,
  DoubleArrowLeftIcon,
  DoubleArrowRightIcon,
} from '../icon';
import type { IconButtonProps } from './icon-button';
import { IconButton } from './icon-button';
import { Flex } from './flex';
import { Typo } from './typo';

export interface PaginationProps {
  /** 현재 선택된 페이지, 1부터 시작 */
  page?: number;
  /** 기본 선택 페이지, page보다 낮은 우선 순위를 갖는다 */
  defaultPage?: number;
  /** 선택한 페이지 변경 이벤트 cb */
  onChange?: (page: number) => void;
  /** 전체 페이지의 수 */
  count?: number;
  /** 표시할 페이지 버튼의 개수 */
  siblingCount?: number;
}

export function Pagination(props: PaginationProps): React.ReactNode {
  const { onChange, count = 0, siblingCount = 2 } = props;

  const [page, setPage] = useState(() => props.page || props.defaultPage || 1);

  const visibleItems = useMemo(() => {
    let start = Math.max(1, page - siblingCount);
    let end = Math.min(count, page + siblingCount);
    if (page - siblingCount <= 0 && end < count) {
      end = Math.min(count, end + Math.abs(page - siblingCount) + 1);
    } else if (page + siblingCount > count && start > 1) {
      start = Math.max(1, start - (page + siblingCount - count));
    }

    return Array.from({ length: end - start + 1 }, (_, i) => i + start);
  }, [count, page, siblingCount]);

  useEffect(() => {
    onChange?.(page);
  }, [onChange, page]);

  useEffect(() => {
    if (props.page) {
      setPage(props.page);
    }
  }, [props.page]);

  const prev = useMemo<number | undefined>(() => {
    const p = page - 1;
    return p < 1 ? undefined : p;
  }, [page]);

  const next = useMemo<number | undefined>(() => {
    const n = page + 1;
    return n > count ? undefined : n;
  }, [count, page]);

  const onClickPrev = useCallback(() => {
    prev && setPage(prev);
  }, [prev]);

  const onClickNext = useCallback(() => {
    next && setPage(next);
  }, [next]);

  const doublePrev = useMemo<number | undefined>(() => {
    if (!visibleItems.length) return;
    return Math.max(0, visibleItems[0] - 1);
  }, [visibleItems]);

  const onClickDoublePrev = useCallback(() => {
    doublePrev && setPage(doublePrev);
  }, [doublePrev]);

  const doubleNext = useMemo<number | undefined>(() => {
    if (!visibleItems.length) return;
    const n = visibleItems[visibleItems.length - 1] + 1;
    if (n > count) return;
    return Math.min(count, n);
  }, [count, visibleItems]);

  const onClickDoubleNext = useCallback(() => {
    doubleNext && setPage(doubleNext);
  }, [doubleNext]);

  const iconSize = {
    height: 24,
    width: 24,
  };

  const moveButtonProps: IconButtonProps = {
    variant: 'ghost',
    size: 'large',
    style: { borderRadius: '50%' },
  };

  return (
    <Flex align="center" className="tipp-pagination" gap="4">
      <IconButton
        disabled={!doublePrev}
        onClick={onClickDoublePrev}
        {...moveButtonProps}
      >
        <DoubleArrowLeftIcon {...iconSize} />
      </IconButton>
      <IconButton disabled={!prev} onClick={onClickPrev} {...moveButtonProps}>
        <ChevronLeftIcon {...iconSize} />
      </IconButton>
      <Flex gap="1">
        {visibleItems.map((item) => {
          return (
            <button
              className={`page-button ${item === page ? 'active' : ''}`}
              key={item}
              onClick={() => {
                setPage(item);
              }}
              type="button"
            >
              <Typo variant="body">{item}</Typo>
            </button>
          );
        })}
      </Flex>
      <IconButton disabled={!next} onClick={onClickNext} {...moveButtonProps}>
        <ChevronRightIcon {...iconSize} />
      </IconButton>
      <IconButton
        disabled={!doubleNext}
        onClick={onClickDoubleNext}
        {...moveButtonProps}
      >
        <DoubleArrowRightIcon {...iconSize} />
      </IconButton>
    </Flex>
  );
}
