import React from "react";
import { ListOnScrollProps } from "react-window";
import { TableAddon, TableProps } from "../../TableProps";
import {
  ScrollableTable,
  ScrollableTableBody,
  ScrollableTableHead,
} from "./ScrollableTable";

export interface VirtualizedOptions<Record = any> {
  /**
   * 每行高度
   * @default 45
   */
  itemHeight?: number | ((record: Record, index: number) => number);

  /**
   * 表格高度
   * @default 同 `maxHeight`
   */
  height?: number | string;

  /**
   * 滚动至底部的回调
   * @since 2.3.5
   */
  onScrollBottom?: (props: ListOnScrollProps) => void;
}

/**
 * `scrollable` 插件用于支持表格滚动。
 *
 * **纵向滚动**：需要指定表格内容区域最大高度 `maxHeight`，内容超过最大高度时，出现纵向滚动条。
 *
 * **横向滚动**：需要指定表格最小宽度的 `minWidth`，表格超过其容器宽度时，出现横向滚动条。
 */
export interface ScrollableAddonOptions<Record = any> {
  /**
   * 设置 maxHeight 属性来开启表格内容区域的纵向滚动
   */
  maxHeight?: number | string;

  /**
   * 设置表格内容区域的最小高度
   */
  minHeight?: number | string;

  /**
   * 哪些内容改变之后，会导致滚动高度变化
   *
   * 默认不传会使用 `props => [props.records.length]`
   */
  scrollHeightFactor?: (props: TableProps) => any[];

  /**
   * Table Body 滚动至底部的回调
   */
  onScrollBottom?: (event: React.UIEvent) => void;

  /**
   * 设置 minWidth 属性来开启表格内容区域的横向滚动
   */
  minWidth?: number | string;

  /**
   * 当依赖项变化后是否滚动到表格顶部
   *
   * - `true` - 依赖项包括 `records`/`columns`/`topTip`
   *
   * @default false
   * @since 2.1.0
   */
  scrollToTopOnChange?: boolean | any[];

  /**
   * 纵向虚拟滚动配置
   *
   * - 优化包含大量数据的表格渲染
   *
   * @since 2.3.0
   */
  virtualizedOptions?: VirtualizedOptions<Record>;
}

/**
 * 支持表格内容区域滚动
 *
 * 如果遇到无法滚动情况，请尝试将该插件置于 Table 插件配置组最前
 *
```js
<Table
  records={records}
  columns={columns}
  addons={[scrollable({ maxHeight: 144 })]}
/>
```
 */
export function scrollable(options: ScrollableAddonOptions): TableAddon {
  const {
    minHeight,
    maxHeight,
    minWidth,
    scrollHeightFactor = (props: TableProps) => [props.records.length],
    onScrollBottom = () => null,
    scrollToTopOnChange,
    virtualizedOptions,
  } = options;

  if (virtualizedOptions && !virtualizedOptions.height) {
    virtualizedOptions.height = maxHeight;
  }

  const extraProps = {
    tableBoxStyle: { minWidth },
    virtualizedOptions: virtualizedOptions || undefined,
  };

  return {
    getInfo: () => ({ name: "scrollable" }),
    onInjectProps: props => {
      return Object.assign(extraProps, props);
    },

    /**
     * 对 div.tea-table 进行注入，提供滚动上下文
     */
    onInjectTable: render => props => {
      const table = render(props);

      return (
        <ScrollableTable
          scrollHeightFactor={scrollHeightFactor(props)}
          onScrollBottom={onScrollBottom}
          table={table}
        />
      );
    },

    /**
     * 对 div.tea-table__body 进行注入，提供 bodyRef 用于检测滚动状态变化
     */
    onInjectBody: render => (records, columns, topTip, ...args) => {
      const body = render(records, columns, topTip, ...args);

      return (
        <ScrollableTableBody
          body={body}
          bodyDeps={
            Array.isArray(scrollToTopOnChange)
              ? scrollToTopOnChange
              : [records, columns, topTip]
          }
          scrollToTopOnChange={!!scrollToTopOnChange}
          style={{ maxHeight, minHeight }}
        />
      );
    },

    /**
     * 对 div.tea-table__head 进行注入，根据滚动状态决定要不要使用 padding
     */
    onInjectHead: render => (...args) => {
      const head = render(...args);

      return <ScrollableTableHead head={head} />;
    },
  };
}
