import React, { useState, useEffect } from "react";
import classNames from "classnames";
import { StyledProps } from "../_type";
import { Icon } from "../icon";
import { Tooltip } from "../tooltip";
import { useTranslation } from "../i18n";
import { Select } from "../select";
import { useConfig } from "../_util/config-context";
import { noop } from "../_util/noop";
import { KeyMap } from "../_util/key-map";

/**
 * 表示分页信息
 */
export interface PagingQuery {
  /**
   * 页码：从 1 开始索引
   */
  pageIndex?: number;

  /**
   * 页长：表示每页记录数
   */
  pageSize?: number;
}

export interface PaginationProps extends Partial<PagingQuery>, StyledProps {
  /**
   * 必传，数据总个数，用于计算页数
   */
  recordCount: number;

  /**
   * 切换分页回调函数
   */
  onPagingChange?: (query: PagingQuery) => void;

  /**
   * 切换页长时，是否自动把页码重设为 1
   * @default true
   */
  isPagingReset?: boolean;

  /**
   * 页组件显示的说明信息，不传将渲染数据个数信息
   */
  stateText?: React.ReactNode;

  /**
   * 支持的页长设置
   * @default [10, 20, 30, 50, 100, 200]
   */
  pageSizeOptions?: number[];

  /**
   * 是否显示状态文案
   * @default true
   */
  stateTextVisible?: boolean;

  /**
   * 是否显示页长选择
   * @default true
   */
  pageSizeVisible?: boolean;

  /**
   * 是否显示页码输入
   * @default true
   */
  pageIndexVisible?: boolean;

  /**
   * 是否显示切页按钮（上一页/下一页）
   * @default true
   */
  jumpVisible?: boolean;

  /**
   * 是否显示第一页和最后一页按钮
   * @default true
   */
  endJumpVisible?: boolean;

  /**
   * 当前页码大于总页数时的自动重置行为
   *
   * 重置类型：不处理 / 回到首页 / 回到可用的末页
   *
   * @default "unset"
   * @since 2.6.3
   */
  pageCountChangingResetType?: "unset" | "first" | "last";
}

export const defaultPageSizeOptions = [10, 20, 30, 50, 100, 200];

export const Pagination = React.forwardRef(function Pagination(
  {
    pageIndex,
    pageSize,
    pageSizeOptions,
    recordCount,
    onPagingChange = noop,
    isPagingReset = true,
    stateText,
    stateTextVisible,
    pageSizeVisible,
    pageIndexVisible,
    jumpVisible,
    endJumpVisible,
    className,
    pageCountChangingResetType = "unset",
    ...props
  }: PaginationProps,
  ref: React.Ref<HTMLDivElement>
) {
  const { classPrefix } = useConfig();
  const t = useTranslation();

  if (!Array.isArray(pageSizeOptions) || pageSizeOptions.length === 0) {
    pageSizeOptions = defaultPageSizeOptions; // eslint-disable-line no-param-reassign
  }

  // 为非受控组件提供状态管理
  const [internalPaging, setInternalPaging] = useState<PagingQuery>({
    pageIndex: 1,
    pageSize: pageSizeOptions[0],
  });

  // 非受控组件，使用内部状态
  if (typeof pageIndex === "undefined") {
    // eslint-disable-next-line prefer-destructuring,no-param-reassign
    pageIndex = internalPaging.pageIndex;
  }
  if (typeof pageSize === "undefined") {
    // eslint-disable-next-line prefer-destructuring,no-param-reassign
    pageSize = internalPaging.pageSize;
  }

  // 状态改变同时更新内部状态和通知外部
  // eslint-disable-next-line no-param-reassign
  onPagingChange = (onPagingChange => (query: PagingQuery) => {
    setInternalPaging(query);
    onPagingChange(query);
  })(onPagingChange);

  // 总页数
  const pageCount = Math.max(1, Math.ceil(recordCount / pageSize));

  // 改变页长
  const changePageSize = (pageSize: number) => {
    onPagingChange({
      pageIndex: isPagingReset ? 1 : pageIndex,
      pageSize,
    });
  };

  // 改变页码
  const changePageIndex = (pageIndex: number) =>
    onPagingChange({
      pageIndex,
      pageSize,
    });

  // 渲染分页状态信息
  const stateElement = (() => {
    if (stateTextVisible === false) {
      return null;
    }
    return (
      <div className={`${classPrefix}-pagination__state`}>
        <span className={`${classPrefix}-pagination__text`}>
          {typeof stateText === "undefined"
            ? t.paginationRecordCount(recordCount)
            : stateText}
        </span>
      </div>
    );
  })();

  // 当前页码大于总页，可选重置
  useEffect(
    () => {
      if (
        pageCountChangingResetType !== "unset" &&
        recordCount > 0 &&
        pageIndex > pageCount
      ) {
        onPagingChange({
          pageIndex: pageCountChangingResetType === "first" ? 1 : pageCount,
          pageSize,
        });
      }
    },
    // eslint-disable-next-line react-hooks/exhaustive-deps
    [pageIndex, pageCount, recordCount]
  );

  // 操作区元素
  let operationElements: JSX.Element[] = [];

  // 页码输入
  if (pageIndexVisible !== false) {
    operationElements = [
      <PageIndexInput
        key="page-index-input"
        pageIndex={pageIndex}
        pageCount={pageCount}
        onChange={changePageIndex}
        classPrefix={classPrefix}
      />,
    ];
  }

  // 页码跳转
  if (jumpVisible !== false) {
    operationElements = [
      <PaginationButton
        key="jump-prev"
        type="pre"
        icon="arrowleft"
        disabled={pageIndex <= 1}
        title={pageIndex > 1 ? t.paginationPrevPage : t.paginationAtFirst}
        onClick={() => changePageIndex(pageIndex - 1)}
        classPrefix={classPrefix}
      />,
      ...operationElements,
      <PaginationButton
        key="jump-next"
        type="next"
        icon="arrowright"
        disabled={pageIndex >= pageCount}
        title={
          pageIndex < pageCount ? t.paginationNextPage : t.paginationAtLast
        }
        onClick={() => changePageIndex(pageIndex + 1)}
        classPrefix={classPrefix}
      />,
    ];
  }

  // 页头页尾跳转
  if (endJumpVisible !== false) {
    operationElements = [
      <PaginationButton
        key="jump-first"
        type="first"
        icon="firstpage"
        disabled={pageIndex <= 1}
        title={pageIndex > 1 ? t.paginationToFirstPage : t.paginationAtFirst}
        onClick={() => changePageIndex(1)}
        classPrefix={classPrefix}
      />,
      ...operationElements,
      <PaginationButton
        key="jump-last"
        type="last"
        icon="lastpage"
        disabled={pageIndex >= pageCount}
        title={
          pageIndex < pageCount ? t.paginationToLastPage : t.paginationAtLast
        }
        onClick={() => changePageIndex(pageCount)}
        classPrefix={classPrefix}
      />,
    ];
  }

  // 页长选择
  if (pageSizeVisible !== false) {
    operationElements = [
      <Select
        key="page-size-select"
        type="simulate"
        options={pageSizeOptions.map(page => ({
          value: String(page),
          text: page,
        }))}
        value={String(pageSize)}
        onChange={pageSize => changePageSize(Number(pageSize))}
        placement="top"
        boxClassName="size-auto-width"
      />,
      <span key="page-size-text" className={`${classPrefix}-pagination__text`}>
        {t.paginationRecordPerPage}
      </span>,
      ...operationElements,
    ];
  }

  return (
    <div
      ref={ref}
      className={classNames(`${classPrefix}-pagination`, className)}
      {...props}
    >
      {stateElement}
      <div className={`${classPrefix}-pagination__operate`}>
        {operationElements}
      </div>
    </div>
  );
});

Pagination.displayName = "Pagination";

export interface PaginationButtonProps {
  type: "pre" | "next" | "first" | "last" | "cur";
  icon: string;
  disabled?: boolean;
  title?: string;
  onClick?: React.MouseEventHandler;
  classPrefix: string;
}
export function PaginationButton({
  type,
  disabled,
  icon,
  title,
  onClick,
  classPrefix,
}: PaginationButtonProps) {
  const buttonClassName = classNames({
    [`${classPrefix}-pagination__turnbtn`]: true,
    [`${classPrefix}-pagination__${type}btn`]: type,
    "is-disabled": disabled,
  });

  const button = (
    <a
      className={buttonClassName}
      onClick={disabled ? null : onClick}
      onDoubleClick={evt => evt.preventDefault()}
      style={{ userSelect: "none" }}
    >
      <Icon type={icon} />
    </a>
  );

  if (title) {
    return <Tooltip title={title}>{button}</Tooltip>;
  }

  return button;
}

PaginationButton.displayName = "PaginationButton";

interface PageIndexInputProps {
  pageIndex: number;
  pageCount: number;
  onChange: (pageIndex: number) => void;
  classPrefix: string;
}

function PageIndexInput({
  pageIndex,
  pageCount,
  onChange,
  classPrefix,
}: PageIndexInputProps) {
  const [inputValue, setInputValue] = useState(null);
  const t = useTranslation();

  return (
    <div className={`${classPrefix}-pagination__manualinput`}>
      <input
        type="text"
        className={`${classPrefix}-input ${classPrefix}-pagination__inputpagenum`}
        value={inputValue === null ? String(pageIndex) : inputValue}
        onChange={evt => setInputValue(evt.target.value)}
        onBlur={() => {
          const parsedPageIndex = parseInt(inputValue, 10);
          if (
            parsedPageIndex !== pageIndex &&
            parsedPageIndex >= 1 &&
            parsedPageIndex <= pageCount
          ) {
            onChange(parsedPageIndex);
          }
          setInputValue(null);
        }}
        onKeyDown={evt => {
          // enter to confirm
          if (evt.key === KeyMap.Enter) {
            evt.preventDefault();
            const parsedPageIndex = parseInt(inputValue, 10);
            if (
              parsedPageIndex !== pageIndex &&
              parsedPageIndex >= 1 &&
              parsedPageIndex <= pageCount
            ) {
              onChange(parsedPageIndex);
            }
            setInputValue(null);
          }
          // up/down key
          else if (evt.key === KeyMap.Up || evt.key === KeyMap.Down) {
            let nextPageValue = parseInt(inputValue, 10);
            if (Number.isNaN(nextPageValue)) {
              nextPageValue = pageIndex;
            }
            if (evt.key === KeyMap.Up) {
              nextPageValue = Math.max(1, nextPageValue + 1);
            } else if (evt.key === KeyMap.Down) {
              nextPageValue = Math.min(pageCount, nextPageValue - 1);
            }
            setInputValue(String(nextPageValue));
          }
        }}
      />
      <span className={`${classPrefix}-pagination__totalpage`}>
        {t.paginationPageCount(pageCount)}
      </span>
    </div>
  );
}

PageIndexInput.displayName = "PageIndexInput";
