import React from "react";
import classNames from "classnames";
import { TableAddon } from "../../TableProps";
import { noop } from "../../../_util/noop";
import {
  RowsDraggableTable,
  RowsDraggableTableBody,
  DraggableTableRow,
} from "./RowsDraggableTable";
import { CheckTreeRelation } from "../../../checktree";
import { getRowKeyFromRecordKey } from "../../util/get-row-key-from-record-key";
import { injectPropsIfTargetNotExisted } from "../../util/inject-props-if-target-not-existed";
import { Icon } from "../../../icon";

/**
 * `RowsDraggable` 插件用于支持表格行拖拽排序操作。
 */
export interface RowsDraggableOptions<Record = any> {
  /**
   * 提供 `relations` 属性，结合 expandable 插件
   */
  relations?: CheckTreeRelation;

  /**
   * 用户进行展开/收起操作的时候，知会最新的键值，结合 expandable 插件
   */
  onExpandedKeysChange?: (
    value: string[],
    context?: {
      event: React.SyntheticEvent;
      operateType: "expand" | "collapse";
      operateKey: string;
      operateRecord: Record;
    }
  ) => void;

  /**
   * 展开行的键值，结合 expandable 插件
   */
  expandedKeys?: string[];

  /**
   * 子级相对父级缩进量，结合 expandable 插件
   * @default 20
   */
  indent?: number;

  /**
   * 拖拽完成回调
   */
  onDragEnd: (
    records: Record[],
    dragContext?: {
      dragKey?: string;
      dragRecordIndex?: number;
      dragRecord?: Record;
      dropKey?: string;
      dropDepth?: number;
    }
  ) => void;

  /**
   * 拖拽开始时回调
   */
  onDragStart?: (context: any) => void;

  /**
   * 拖拽类型，树拖拽排序或者仅行拖拽
   * @default "row"
   */
  dragType?: "tree" | "row";

  /**
   * 可拖拽的行, 默认所有行
   * @default "all"
   */
  draggableRowKeys?: string[] | "all";

  /**
   * 子树列表字段名，树形拖拽需传该参数
   */
  childrenColName?: string;

  /**
   * 隐藏拖拽手柄图标
   *
   * *默认值：*
   *
   * - *内置拖拽 `"unhover"`*
   * - *第三方库拖拽 `false`*
   */
  hideHandler?: boolean | "unhover";

  /**
   * 拖拽手柄列宽度，可以指定 CSS 属性或数字 (单位：px)
   * @default 46
   */
  width?: string | number;

  /**
   * 拖拽手柄图标
   *
   * *参考 Icon 组件[图标类型](/component/icon)*
   *
   * @default "drop"
   */
  icon?: string;

  /**
   * 提供一个列的 `key`，将icon插入到一个目标列
   *
   * 默认在最前新建一列插入
   */
  targetColumnKey?: string;
}
const fallbackColumnKey = "__row_draggable_addon__";
export function rowsDraggable({
  onDragEnd = noop,
  onDragStart = noop,
  draggableRowKeys = "all",
  childrenColName = "childrenList",
  dragType = "row",
  relations,
  onExpandedKeysChange,
  expandedKeys,
  indent = 20,
  hideHandler = "unhover",
  icon,
  width = 26,
  targetColumnKey,
  ...options
}: RowsDraggableOptions): TableAddon {
  const iconColumnWidth =
    (options as any).iconColumnWidth ||
    (typeof width === "number" ? width : 26);

  let getRowKey: ReturnType<typeof getRowKeyFromRecordKey>;
  let recordsData = [];
  return {
    getInfo: () => ({ name: "draggable" }),
    onInjectProps: props => {
      const { recordKey, records } = props;
      recordsData = records;
      getRowKey = getRowKeyFromRecordKey(recordKey);
      const columns =
        hideHandler !== true
          ? injectPropsIfTargetNotExisted(props.columns, targetColumnKey, {
              key: fallbackColumnKey,
              width: iconColumnWidth,
              header: null,
              render: () => null,
            })
          : props.columns;

      return {
        ...props,
        rowsDraggable: true,
        draggableRowKeys,
        columns,
      };
    },
    onInjectTable: render => props => {
      const table = render(props);
      return (
        <RowsDraggableTable
          table={table}
          onDragEnd={onDragEnd}
          onDragStart={onDragStart}
          relations={relations}
          onExpandedKeysChange={onExpandedKeysChange}
          expandedKeys={expandedKeys}
          indent={indent}
          recordsData={recordsData}
          getRowKey={getRowKey}
          childrenColName={childrenColName}
          dragType={dragType}
          iconColumnWidth={
            hideHandler !== true && !targetColumnKey ? iconColumnWidth : 0
          }
        />
      );
    },
    onInjectBody: render => (records, rows, topTip, bottomTip) => {
      const body = render(records, rows, topTip, bottomTip);
      return <RowsDraggableTableBody body={body} />;
    },
    onInjectRow: renderRow => (record, rowKey, recordIndex, columns) => {
      const key = getRowKey(record, recordIndex);
      const { prepends, row, appends } = renderRow(
        record,
        rowKey,
        recordIndex,
        columns
      );

      // 表头跳过
      if (recordIndex === -1) {
        return { prepends, row, appends };
      }

      return {
        prepends,
        row: (
          <DraggableTableRow
            {...row.props}
            row={row}
            dataKey={key}
            key={key}
            draggableRowKeys={draggableRowKeys}
          />
        ),
        appends,
      };
    },
    onInjectColumn: previous => (
      record,
      rowKey,
      recordIndex,
      column,
      columnIndex
    ) => {
      // 不是目标列
      if (column.key !== targetColumnKey && column.key !== fallbackColumnKey) {
        return previous(record, rowKey, recordIndex, column, columnIndex);
      }

      const { children, props, ...result } = previous(
        record,
        rowKey,
        recordIndex,
        column,
        columnIndex
      );

      let childrenWrap = children;
      // 非表头
      if (recordIndex !== -1 && hideHandler !== true) {
        childrenWrap = (
          <div
            className={classNames({ "hover-icon": hideHandler === "unhover" })}
          >
            <Icon type={icon} />
            {children}
          </div>
        );
      }
      return { ...result, props, children: childrenWrap };
    },
  };
}
