import React from 'react';
import { findDOMNode } from 'react-dom';
import Sortable from 'sortablejs';
import cloneDeep from 'lodash/cloneDeep';
import { RendererProps } from '../../factory';
import Overlay from '../../components/Overlay';
import PopOver from '../../components/PopOver';
import Modal from '../../components/Modal';
import Button from '../../components/Button';
import Checkbox from '../../components/Checkbox';
import TooltipWrapper from '../../components/TooltipWrapper';
import type { TooltipObject } from '../../components/TooltipWrapper';
import { noop, autobind } from '../../utils/helper';
import { filter } from '../../utils/tpl';
import { Icon } from '../../components/icons';
import { RootClose } from '../../utils/RootClose';
import { IColumn } from '../../store/table';
// Jay

export interface ColumnTogglerProps extends RendererProps {
  /**
   * 按钮文字
   */
  label?: string | React.ReactNode;

  /**
   * 按钮提示文字，hover focus 时显示
   */
  tooltip?: string | TooltipObject;

  /**
   * 禁用状态下的提示
   */
  disabledTip?: string | TooltipObject;

  /**
   * 点击外部是否关闭
   */
  closeOnOutside?: boolean;

  /**
   * 点击内容是否关闭
   */
  closeOnClick?: boolean;

  /**
   * 下拉菜单对齐方式
   */
  align?: 'left' | 'right';

  /**
   *  ColumnToggler的CSS类名
   */
  className?: string;

  /**
   * 按钮的CSS类名
   */
  btnClassName?: string;

  /**
   * 按钮大小
   */
  size?: 'xs' | 'sm' | 'md' | 'lg';

  /**
   * 按钮级别，样式
   */
  level?: 'info' | 'success' | 'danger' | 'warning' | 'primary' | 'link';

  /**
   * 是否独占一行 `display: block`
   */
  block?: boolean;

  /**
   * 是否可通过拖拽排序
   */
  draggable?: boolean;

  /**
   * 默认是否展开
   */
  defaultIsOpened?: boolean;

  /**
   * 激活状态
   */
  isActived?: boolean;

  /**
   * ICON名称
   */
  icon?: string | React.ReactNode;

  /**
   * 是否只显示图标。
   */
  iconOnly?: boolean;

  /**
   * 是否隐藏展开的Icon
   */
  hideExpandIcon?: boolean;

  /**
   * 是否显示遮罩层
   */
  overlay?: boolean;

  /**
   * 列数据
   */
  columns: Array<IColumn>;
  // Jay
  getRawColumns?: () => Array<IColumn>; // 未进行显隐和排序处理的列数据
  onColumnToggle: (columns: Array<IColumn> | undefined, saveCols: Record<string, any>, canFetch: boolean) => void;
  modalContainer?: () => HTMLElement;
  filteredColumns?: Array<IColumn>;
}

export interface ColumnTogglerState {
  isOpened: boolean;
  enableSorting: boolean;
  tempColumns: any[];
}

export default class ColumnToggler extends React.Component<
  ColumnTogglerProps,
  ColumnTogglerState
> {
  state: ColumnTogglerState = {
    isOpened: false,
    enableSorting: false,
    tempColumns: cloneDeep(this.props.columns)
  };

  static defaultProps: Pick<
    ColumnTogglerProps,
    'placement' | 'tooltipTrigger' | 'tooltipRootClose' | 'draggable'
  > = {
      placement: 'top',
      tooltipTrigger: ['hover', 'focus'],
      tooltipRootClose: false,
      draggable: false
    };

  target: any;
  sortable?: Sortable;
  dragRefDOM: HTMLElement;

  constructor(props: ColumnTogglerProps) {
    super(props);

    this.open = this.open.bind(this);
    this.close = this.close.bind(this);
    this.toggle = this.toggle.bind(this);
    this.domRef = this.domRef.bind(this);
    this.dragRef = this.dragRef.bind(this);
    // Jay
    this.reset = this.reset.bind(this);
    this.canConfirmFetch = false
  }

  // Jay
  canConfirmFetch: boolean
  componentDidUpdate(prevProps: ColumnTogglerProps, preState: ColumnTogglerState) {
    if (prevProps.columns !== this.props.columns) {
      this.setState({ tempColumns: this.props.columns })
    }
  }

  componentDidMount() {
    if (this.props.defaultIsOpened) {
      this.setState({
        isOpened: true
      });
    }
  }

  componentWillUnmount() {
    this.destroyDragging();
  }

  domRef(ref: any) {
    this.target = ref;
  }

  toggle(e: React.MouseEvent<any>) {
    e.preventDefault();

    this.setState({
      isOpened: !this.state.isOpened
    });
  }

  open() {
    this.setState({
      isOpened: true
    });
  }

  close() {
    this.setState({
      isOpened: false,
      enableSorting: false,
      tempColumns: cloneDeep(this.props.columns)
    });
  }

  swapColumnPosition(oldIndex: number, newIndex: number) {
    const columns = this.state.tempColumns;
    // 有两种逻辑：插入和调换
    // 插入
    const old = columns.splice(oldIndex, 1)[0]
    // columns.splice(newIndex < oldIndex ? newIndex : newIndex + 1, 0, old)
    columns.splice(newIndex, 0, old)
    // 调换两个顺序
    // columns[oldIndex] = columns.splice(newIndex, 1, columns[oldIndex])[0];

    this.setState({ tempColumns: columns });
  }

  updateToggledColumn(
    column: IColumn,
    index: number,
    value: any,
    shift?: boolean
  ) {
    const tempColumns = this.state.tempColumns.concat();

    tempColumns.splice(index, 1, {
      ...column,
      // Jay
      pristine: { ...column.pristine, hidden: !value },
      toggled: value
    });
    this.canConfirmFetch = true
    this.setState({ tempColumns });
  }

  reset() {
    // Jay
    // const { enableSorting } = this.state
    // const tempColumns = this.state.tempColumns.concat();
    // if (!enableSorting) {
    //   // 显示列重置，全部设置为hidden为false
    //   tempColumns.forEach(column => {
    //     column.pristine = { ...column.pristine, hidden: column.pristine.canSet === false ? true : false };
    //     column.toggled = column.pristine.canSet === false ? false : true
    //   })

    //   this.setState({ tempColumns });
    // } else {
    //   const tempArr: any[] = []
    //   tempColumns.forEach(column => {
    //     tempArr[this.initIndexObj[column.name]] = column
    //   })
    //   this.setState({ tempColumns: tempArr });
    // }
    this.canConfirmFetch = false
    const { getRawColumns, onColumnToggle } = this.props
    if (getRawColumns) {
      this.setState({ tempColumns: getRawColumns() }, () => {
        onColumnToggle && onColumnToggle(undefined, {}, true);
      });
    }
  }

  @autobind
  dragRef(ref: any) {
    const { enableSorting } = this.state;
    const { draggable } = this.props;

    if (enableSorting && draggable && ref) {
      this.initDragging();
    }
  }

  initDragging() {
    const dom = findDOMNode(this) as HTMLElement;
    const ns = this.props.classPrefix;

    this.sortable = new Sortable(
      dom.querySelector(`.${ns}ColumnToggler-modal-content`) as HTMLElement,
      {
        group: `ColumnToggler-modal-content`,
        animation: 150,
        handle: `.${ns}ColumnToggler-menuItem-dragBar`,
        ghostClass: `${ns}ColumnToggler-menuItem--dragging`,
        onEnd: (e: any) => {
          if (e.newIndex === e.oldIndex) {
            return;
          }

          const parent = e.to as HTMLElement;
          if (e.oldIndex < parent.childNodes.length - 1) {
            parent.insertBefore(e.item, parent.childNodes[e.oldIndex]);
          } else {
            parent.appendChild(e.item);
          }
          this.canConfirmFetch = true
          this.swapColumnPosition(e.oldIndex, e.newIndex);
        }
      }
    );
  }

  destroyDragging() {
    this.sortable && this.sortable.destroy();
  }

  @autobind
  onConfirm() {
    const { tempColumns } = this.state;
    const { onColumnToggle } = this.props;
    const saveCols: Record<string, any> = {}
    // Jay
    tempColumns.forEach((col, index) => {
      if (col.type === 'operation') return
      saveCols[col.name] = {
        index,
        // 0:false , 1:true
        hidden: col.pristine.hidden ? 1 : col.toggled ? 0 : 1
      }
    })
    onColumnToggle && onColumnToggle([...tempColumns], saveCols, this.canConfirmFetch);
    this.setState({
      isOpened: false,
      enableSorting: false
    });
  }

  renderOuter() {
    const {
      popOverContainer,
      classnames: cx,
      classPrefix: ns,
      children,
      closeOnClick,
      closeOnOutside
    } = this.props;
    const body = (
      <RootClose
        disabled={!this.state.isOpened}
        onRootClose={closeOnOutside !== false ? this.close : noop}
      >
        {(ref: any) => {
          return (
            <ul
              className={cx('ColumnToggler-menu')}
              onClick={closeOnClick ? this.close : noop}
              ref={ref}
            >
              {children}
            </ul>
          );
        }}
      </RootClose>
    );

    if (popOverContainer) {
      return (
        <Overlay container={popOverContainer} target={() => this.target} show>
          <PopOver
            overlay
            onHide={this.close}
            classPrefix={ns}
            className={cx('ColumnToggler-popover')}
            style={{ minWidth: this.target?.offsetWidth }}
          >
            {body}
          </PopOver>
        </Overlay>
      );
    }

    return body;
  }

  renderModal() {
    const {
      render,
      classnames: cx,
      classPrefix: ns,
      modalContainer,
      draggable,
      overlay,
      translate: __
    } = this.props;

    const { enableSorting, tempColumns } = this.state;

    // Jay
    let controlShowColsCount = 0
    let canSortColsCount = 0
    Array.isArray(tempColumns) && tempColumns.forEach(col => {
      if (col.type === 'operation' ? false : col.pristine.canSet !== false) {
        controlShowColsCount++
      }
      if (!col.fixed && col.pristine.canSet !== false) {
        canSortColsCount++
      }
    })

    return (
      <>
        <Modal
          size="lg"
          closeOnEsc
          onHide={this.close}
          show={this.state.isOpened}
          contentClassName={cx('ColumnToggler-modal')}
          container={modalContainer || this.target}
          overlay={typeof overlay === 'boolean' ? overlay : false}
        >
          <header className={cx('ColumnToggler-modal-header')}>
            <span className={cx('ColumnToggler-modal-title')}>列设置</span>
            <a
              data-tooltip={__('Dialog.close')}
              data-position="left"
              className={cx('Modal-close')}
              onClick={this.close}
            >
              <Icon icon="close" className="icon" />
            </a>
          </header>

          <ul className={cx('ColumnToggler-modal-content')} ref={this.dragRef}>
            {/* Jay */}
            {controlShowColsCount === 0 ? <li style={{ marginLeft: 5, fontSize: 13 }}>当前没有可控制显隐的列</li> :
              Array.isArray(tempColumns)
                ? tempColumns.map((column, index) => column.type !== 'operation' ? (
                  <TooltipWrapper
                    tooltipClassName={cx('ColumnToggler-tooltip')}
                    placement="top"
                    tooltip={column.label || ''}
                    trigger={enableSorting ? [] : 'hover'}
                    key={column.index}
                  >
                    <li
                      className={cx('ColumnToggler-menuItem')}
                      key={column.index}
                      // Jay 固定列不允许排序，操作列不能控制显隐，canSet为false不能设置显隐和排序
                      style={{ display: ((enableSorting && draggable && column.fixed) || column.pristine.canSet === false) ? 'none' : 'block' }}
                    >
                      {enableSorting && draggable && tempColumns.length > 1 ? (
                        <>
                          <a className={cx('ColumnToggler-menuItem-dragBar')}>
                            <Icon icon="drag-bar" className={cx('icon')} />
                          </a>
                          <span>
                            {column.label ? render('tpl', column.label) : null}
                          </span>
                        </>
                      ) : (
                        <Checkbox
                          size="sm"
                          classPrefix={ns}
                          // checked={column.toggled}
                          checked={column.pristine.hidden !== undefined ? !column.pristine.hidden : true}
                          disabled={!column.toggable || enableSorting}
                          onChange={this.updateToggledColumn.bind(
                            this,
                            column,
                            index
                          )}
                        >
                          {/* Jay */}
                          {column.label ? render('tpl', column.label) : null}
                        </Checkbox>
                      )}
                    </li>
                  </TooltipWrapper>
                ) : null)
                : null
            }
          </ul>

          <footer className={cx('ColumnToggler-modal-footer')}>
            <div>
              <Button
                className={cx(`ColumnToggler-modeSelect`, {
                  'is-actived': !enableSorting
                })}
                onClick={() => this.setState({ enableSorting: false })}
                level="link"
              >
                {__('Table.toggleColumn')}
              </Button>
              <Button
                className={cx(`ColumnToggler-modeSelect`, {
                  'is-actived': enableSorting
                })}
                onClick={() =>
                  this.setState(
                    { enableSorting: true },
                    () =>
                      this.state.enableSorting &&
                      this.props.draggable &&
                      this.initDragging()
                  )
                }
                level="link"
                // Jay
                // disabled={tempColumns.length < 2}
                disabled={canSortColsCount < 2} //
              >
                {__('sort')}
              </Button>
            </div>
            <div style={{ display: 'flex' }}>
              <div>
                <Button size="sm" onClick={this.close}>
                  {__('cancel')}
                </Button>
              </div>
              <div style={{ margin: '0 10px' }}>
                <Button size="sm" onClick={this.reset}>
                  {__('resetSettings')}
                </Button>
              </div>
              <div>
                <Button level="primary" size="sm" onClick={this.onConfirm}>
                  {__('confirm')}
                </Button>
              </div>
            </div>
          </footer>
        </Modal>
      </>
    );
  }

  render() {
    const {
      tooltip,
      placement,
      tooltipContainer,
      tooltipTrigger,
      tooltipRootClose,
      disabledTip,
      block,
      disabled,
      btnDisabled,
      btnClassName,
      size,
      label,
      level,
      primary,
      className,
      classnames: cx,
      align,
      iconOnly,
      icon,
      isActived,
      data,
      draggable,
      hideExpandIcon
    } = this.props;

    const button = (
      <button
        onClick={this.toggle}
        disabled={disabled || btnDisabled}
        className={cx(
          'Button',
          btnClassName,
          typeof level === 'undefined'
            ? 'Button--default'
            : level
              ? `Button--${level}`
              : '',
          {
            'Button--block': block,
            'Button--primary': primary,
            'Button--iconOnly': iconOnly
          },
          size ? `Button--${size}` : ''
        )}
      >
        {icon ? (
          typeof icon === 'string' ? (
            <i className={cx(icon, 'm-r-xs')} />
          ) : (
            icon
          )
        ) : null}
        {typeof label === 'string' ? filter(label, data) : label}
        {hideExpandIcon || draggable ? null : (
          <span className={cx('ColumnToggler-caret')}>
            <Icon icon="caret" className="icon" />
          </span>
        )}
      </button>
    );

    return (
      <div
        className={cx(
          'ColumnToggler',
          {
            'ColumnToggler-block': block,
            'ColumnToggler--alignRight': align === 'right',
            'is-opened': this.state.isOpened,
            'is-actived': isActived
          },
          className
        )}
        ref={this.domRef}
      >
        {draggable ? (
          button
        ) : (
          <TooltipWrapper
            placement={placement}
            tooltip={disabled ? disabledTip : tooltip}
            container={tooltipContainer}
            trigger={tooltipTrigger}
            rootClose={tooltipRootClose}
          >
            {button}
          </TooltipWrapper>
        )}
        {this.state.isOpened
          ? draggable
            ? this.renderModal()
            : this.renderOuter()
          : null}
      </div>
    );
  }
}
