import React from 'react';
import { findDOMNode } from 'react-dom';
import { Renderer, RendererProps } from '../factory';
import { SchemaNode, Action, Schema } from '../types';
import Button from '../components/Button';
import Checkbox from '../components/Checkbox';
import { ListStore, IListStore, IItem } from '../store/list';
import {
  anyChanged,
  getScrollParent,
  difference,
  ucFirst,
  isMobile
} from '../utils/helper';
import {
  isPureVariable,
  resolveVariableAndFilter
} from '../utils/tpl-builtin';
import Sortable from 'sortablejs';
import { filter } from '../utils/tpl';
import { Icon } from '../components/icons';
import {
  BaseSchema,
  SchemaClassName,
  SchemaCollection,
  SchemaExpression,
  SchemaTpl,
  SchemaTokenizeableString,
  SchemaObject
} from '../Schema';
import { CardSchema } from './Card';
import InfinteSroll from './Lion/components/InfinteSroll';
import offset from '../utils/offset';
import { getStyleNumber } from '../utils/dom';
import { ContextMenu } from './Lion/components/LionContextMenu';
import { Popover } from 'antd';
import { FileSyncOutlined } from '@ant-design/icons';
import { isEqual } from 'lodash';
/**
 * Cards 卡片集合渲染器。
 * 文档：https://baidu.gitee.io/amis/docs/components/card
 */
export interface CardsSchema extends BaseSchema {
  /**
   * 指定为 cards 类型
   */
  type: 'cards';

  card?: Omit<CardSchema, 'type'>;

  /**
   * 头部 CSS 类名
   */
  headerClassName?: SchemaClassName;

  /**
   * 底部 CSS 类名
   */
  footerClassName?: SchemaClassName;

  /**
   * 卡片 CSS 类名
   *
   * @default Grid-col--sm6 Grid-col--md4 Grid-col--lg3
   */
  itemClassName?: SchemaClassName;

  /**
   * 无数据提示
   *
   * @default 暂无数据
   */
  placeholder?: SchemaTpl;

  /**
   * 是否显示底部
   */
  showFooter?: boolean;

  /**
   * 是否显示头部
   */
  showHeader?: boolean;

  /**
   * 数据源: 绑定当前环境变量
   *
   * @default ${items}
   */
  source?: SchemaTokenizeableString;

  /**
   * 标题
   */
  title?: SchemaTpl;

  /**
   * 是否隐藏勾选框
   */
  hideCheckToggler?: boolean;

  /**
   * 是否固顶
   */
  affixHeader?: boolean;

  /**
   * 顶部区域
   */
  header?: SchemaCollection;

  /**
   * 底部区域
   */
  footer?: SchemaCollection;
  /**
   * 配置某项是否可以点选
   */
  itemCheckableOn?: SchemaExpression;

  /**
   * 配置某项是否可拖拽排序，前提是要开启拖拽功能
   */
  itemDraggableOn?: SchemaExpression;

  /**
   * 点击卡片的时候是否勾选卡片。
   */
  checkOnItemClick?: boolean;

  /**
   * 是否为瀑布流布局？
   */
  masonryLayout?: boolean;

  /**
   * 可以用来作为值的字段
   */
  valueField?: string;
}

export interface Column {
  type: string;
  [propName: string]: any;
}

export interface GridProps
  extends RendererProps,
  Omit<CardsSchema, 'className' | 'itemClassName'> {
  store: IListStore;
  selectable?: boolean;
  selected?: Array<any>;
  multiple?: boolean;
  valueField?: string;
  draggable?: boolean;
  onSelect: (
    selectedItems: Array<object>,
    unSelectedItems: Array<object>
  ) => void;
  onSave?: (
    items: Array<object> | object,
    diff: Array<object> | object,
    rowIndexes: Array<number> | number,
    unModifiedItems?: Array<object>,
    rowOrigins?: Array<object> | object,
    resetOnFailed?: boolean
  ) => void;
  onSaveOrder?: (moved: Array<object>, items: Array<object>) => void;
  onQuery: (values: object) => void;
  renderAggregate?: () => JSX.Element
}
interface GridState {
  toolbarShow: boolean,
  exhibition: number
}

export default class Cards extends React.Component<GridProps, object & GridState> {
  static propsList: Array<string> = [
    'header',
    'headerToolbarRender',
    'footer',
    'footerToolbarRender',
    'placeholder',
    'source',
    'selectable',
    'headerClassName',
    'footerClassName',
    'fixAlignment',
    'hideQuickSaveBtn',
    'hideCheckToggler',
    'itemCheckableOn',
    'itemDraggableOn',
    'masonryLayout',
    'items',
    'valueField'
  ];
  static defaultProps: Partial<GridProps> = {
    className: '',
    placeholder: 'placeholder.noData',
    source: '$items',
    selectable: false,
    headerClassName: '',
    footerClassName: '',
    itemClassName: 'Grid-col--sm6 Grid-col--md4 Grid-col--lg3',
    // fixAlignment: false,
    // hideCheckToggler: false,
    hideCheckToggler: isMobile(),//Aug
    masonryLayout: false,
    affixHeader: true,
    itemsClassName: ''
  };

  dragTip?: HTMLElement;
  sortable?: Sortable;
  parentNode?: any;
  body?: any;
  cardsBody?: any
  // fixAlignmentLazy: Function;
  unSensor: Function;
  renderedToolbars: Array<string>;
  updateAutoFillHeightTimes = 0;
  contetnHighUpdateTimer: any
  constructor(props: GridProps) {
    super(props);

    this.handleAction = this.handleAction.bind(this);
    this.handleCheck = this.handleCheck.bind(this);
    this.handleCheckAll = this.handleCheckAll.bind(this);
    this.handleQuickChange = this.handleQuickChange.bind(this);
    this.handleSave = this.handleSave.bind(this);
    this.handleSaveOrder = this.handleSaveOrder.bind(this);
    this.reset = this.reset.bind(this);
    this.dragTipRef = this.dragTipRef.bind(this);
    this.bodyRef = this.bodyRef.bind(this);
    this.affixDetect = this.affixDetect.bind(this);
    this.updateAutoFillHeight = this.updateAutoFillHeight.bind(this);
    this.itemsRef = this.itemsRef.bind(this);
    this.renderToolbar = this.renderToolbar.bind(this);
    // this.fixAlignmentLazy = debounce(this.fixAlignment.bind(this), 250, {
    //     trailing: true,
    //     leading: false
    // })

    const {
      store,
      selectable,
      draggable,
      orderBy,
      orderDir,
      multiple,
      hideCheckToggler,
      itemCheckableOn,
      itemDraggableOn
    } = props;

    store.update({
      selectable,
      draggable,
      orderBy,
      orderDir,
      multiple,
      hideCheckToggler,
      itemCheckableOn,
      itemDraggableOn
    });

    this.state = {
      toolbarShow: false,
      exhibition: 0,
    }

    Cards.syncItems(store, this.props) && this.syncSelected();
  }

  static syncItems(store: IListStore, props: GridProps, prevProps?: GridProps) {
    const source = props.source;
    const value = props.value || props.items;
    let items: Array<object> = [];
    let updateItems = false;

    if (
      Array.isArray(value) &&
      (!prevProps || (prevProps.value || prevProps.items) !== value)
    ) {
      items = value;
      updateItems = true;
    } else if (typeof source === 'string') {
      const resolved = resolveVariableAndFilter(source, props.data, '| raw');
      const prev = prevProps
        ? resolveVariableAndFilter(source, prevProps.data, '| raw')
        : null;

      if (prev && prev === resolved) {
        updateItems = false;
      } else if (Array.isArray(resolved)) {
        items = resolved;
        updateItems = true;
      }
    }

    updateItems && store.initItems(items);
    typeof props.selected !== 'undefined' &&
      store.updateSelected(props.selected, props.valueField);
    return updateItems;
  }

  componentDidMount() {
    let parent: HTMLElement | Window | null = getScrollParent(
      findDOMNode(this) as HTMLElement
    );
    if (!parent || parent === document.body) {
      parent = window;
    }

    this.parentNode = parent;
    this.affixDetect();
    parent.addEventListener('scroll', this.affixDetect);
    window.addEventListener('resize', this.affixDetect);
    this.updateAutoFillHeight();
    window.addEventListener('resize', this.updateAutoFillHeight);
  }

  componentDidUpdate(prevProps: GridProps) {
    const props = this.props;
    const store = props.store;

    if (
      anyChanged(
        [
          'selectable',
          'draggable',
          'orderBy',
          'orderDir',
          'multiple',
          'hideCheckToggler',
          'itemCheckableOn',
          'itemDraggableOn'
        ],
        prevProps,
        props
      )
    ) {
      store.update({
        selectable: props.selectable,
        draggable: props.draggable,
        orderBy: props.orderBy,
        orderDir: props.orderDir,
        multiple: props.multiple,
        hideCheckToggler: props.hideCheckToggler,
        itemCheckableOn: props.itemCheckableOn,
        itemDraggableOn: props.itemDraggableOn
      });
    }

    if (
      anyChanged(['source', 'value', 'items'], prevProps, props) ||
      (!props.value &&
        !props.items &&
        (props.data !== prevProps.data ||
          (typeof props.source === 'string' && isPureVariable(props.source))))
    ) {
      Cards.syncItems(store, props, prevProps) && this.syncSelected();
    } else if (prevProps.selected !== props.selected) {
      store.updateSelected(props.selected || [], props.valueField);
    }
    if (props.tabsdefer !== prevProps.tabsdefe && isMobile()) {
      this.updateAutoFillHeight()
    }
    if (!isEqual(prevProps.data, props.data)) {
      this.updateAutoExhibition()
    }
  }

  componentWillUnmount() {
    const parent = this.parentNode;
    parent && parent.removeEventListener('scroll', this.affixDetect);
    window.removeEventListener('resize', this.affixDetect);
    window.removeEventListener('resize', this.updateAutoFillHeight);
  }

  bodyRef(ref: HTMLDivElement) {
    this.body = ref;
  }

  itemsRef(ref: HTMLDivElement) {
    if (ref) {
      this.cardsBody = ref
      this.updateAutoExhibition()
      if (!isMobile() && ResizeObserver) {
        const observer = new ResizeObserver(entries => {
          for (let entry of entries) {
            // 在这里执行你希望在宽度变化时进行的操作
            clearTimeout(this.contetnHighUpdateTimer)
            this.contetnHighUpdateTimer = setTimeout(() => {
              this.updateAutoExhibition()
            }, 10)
          }
        });
        observer.observe(this.cardsBody);
      }
    } else {
      this.unSensor && this.unSensor();

      // @ts-ignore;
      delete this.unSensor;
    }
  }
  updateAutoExhibition = () => {
    if (this.cardsBody) {
      // this.unSensor = resizeSensor(ref.parentNode as HTMLElement, this.fixAlignmentLazy);
      const { data: { perPage, total, page } } = this.props
      const parentWidth = this.cardsBody.clientWidth
      const childWidth = (this.cardsBody.childNodes[0] as HTMLElement).clientWidth
      const node = Math.floor(parentWidth / childWidth);

      if (total <= perPage * page) {
        const exhibition = node - (total % node)
        this.setState({ exhibition: !(total % node) ? 0 : exhibition })
      } else {
        const exhibition = node - (perPage % node)
        this.setState({ exhibition: !(perPage % node) ? 0 : exhibition })
      }
    }
  }
  affixDetect() {
    if (!this.props.affixHeader || !this.body) {
      return;
    }

    const ns = this.props.classPrefix;
    const dom = findDOMNode(this) as HTMLElement;
    const clip = (this.body as HTMLElement).getBoundingClientRect();
    const offsetY =
      this.props.affixOffsetTop ?? this.props.env.affixOffsetTop ?? 0;
    const affixed =
      clip.top - 10 < offsetY && clip.top + clip.height - 40 > offsetY;
    const afixedDom = dom.querySelector(`.${ns}Cards-fixedTop`) as HTMLElement;

    this.body.offsetWidth &&
      (afixedDom.style.cssText = `top: ${offsetY}px;width: ${this.body.offsetWidth}px;`);
    affixed ? afixedDom.classList.add('in') : afixedDom.classList.remove('in');
    // store.markHeaderAffix(clip.top < offsetY && (clip.top + clip.height - 40) > offsetY);
  }

  updateAutoFillHeight() {
    const { classPrefix: ns, autoFillHeight } = this.props;
    if (!this.body) return;

    const dom = findDOMNode(this) as HTMLElement;
    const drawerFooter = dom.closest(`.${ns}Drawer-content`)?.querySelector(`.${ns}Drawer-footer`);
    // 循环计算父级节点的 pddding，这里不考虑父级节点还可能会有其它兄弟节点的情况了
    let allParentPaddingButtom = 0;
    let parentNode = dom;
    while (parentNode) {
      const paddingButtom = getStyleNumber(parentNode, 'padding-bottom');
      const borderBottom = getStyleNumber(parentNode, 'border-bottom-width');
      allParentPaddingButtom =
        allParentPaddingButtom + paddingButtom + borderBottom;
      parentNode = parentNode.parentElement as HTMLElement;
    }

    let tableHeight =
      document.body.clientHeight -
      offset(dom).top -
      (drawerFooter ? drawerFooter.clientHeight + 1 : 0) -
      allParentPaddingButtom;
    // tab情况下，后面的table由于display：none，所以offset(table).top为0，所以继承最小的那个

    if (offset(dom).top === 0) {
      const tabsContent = dom.closest(`.${ns}Tabs-content`) as HTMLDivElement;
      tableHeight =
        document.body.clientHeight -
        offset(tabsContent).top -
        (drawerFooter ? drawerFooter.clientHeight + 1 : 0) -
        allParentPaddingButtom - 24;//多出来的24是tabs-pane的padding
    }
    if (autoFillHeight && tableHeight >= 400) {
      //当表格可展示高度大于350的占满剩余空间
      dom.style.height = tableHeight + 'px';
      dom.style.maxHeight = 'unset';
    } else {
      dom.style.maxHeight = document.body.clientHeight - 38 + 'px';
    }

  }

  handleAction(e: React.UIEvent<any>, action: Action, ctx: object) {
    const { onAction } = this.props;

    // 需要支持特殊事件吗？
    onAction(e, action, ctx);
  }

  handleCheck(item: IItem) {
    item.toggle();
    this.syncSelected();
  }

  handleCheckAll(index?: number) {
    const { store } = this.props;
    switch (index) {
      case 0:
        store.toggleAll();
        break;
      case 1:
        store.checkReverse();
        break;
      case 2:
        store.clear();
        break;
      case 3:
        store.toggleAll();
        break;
      default:
        store.toggleAll();
        return;
    }
    this.syncSelected();
  }

  syncSelected() {
    const { store, onSelect } = this.props;

    onSelect &&
      onSelect(
        store.selectedItems.map(item => item.data),
        store.unSelectedItems.map(item => item.data)
      );
  }

  handleQuickChange(
    item: IItem,
    values: object,
    saveImmediately?: boolean | any,
    saveSilent?: boolean,
    resetOnFailed?: boolean
  ) {
    item.change(values, saveSilent);

    if (!saveImmediately || saveSilent) {
      return;
    }

    if (saveImmediately && saveImmediately.api) {
      this.props.onAction(
        null,
        {
          actionType: 'ajax',
          api: saveImmediately.api
        },
        values
      );
      return;
    }

    const { onSave, primaryField } = this.props;

    if (!onSave) {
      return;
    }

    onSave(
      item.data,
      difference(item.data, item.pristine, ['id', primaryField]),
      item.index,
      undefined,
      item.pristine,
      resetOnFailed
    );
  }

  handleSave() {
    const { store, onSave, primaryField } = this.props;

    if (!onSave || !store.modifiedItems.length) {
      return;
    }

    const items = store.modifiedItems.map(item => item.data);
    const itemIndexes = store.modifiedItems.map(item => item.index);
    const diff = store.modifiedItems.map(item =>
      difference(item.data, item.pristine, ['id', primaryField])
    );
    const unModifiedItems = store.items
      .filter(item => !item.modified)
      .map(item => item.data);
    onSave(
      items,
      diff,
      itemIndexes,
      unModifiedItems,
      store.modifiedItems.map(item => item.pristine)
    );
  }

  handleSaveOrder() {
    const { store, onSaveOrder } = this.props;

    if (!onSaveOrder || !store.movedItems.length) {
      return;
    }

    onSaveOrder(
      store.movedItems.map(item => item.data),
      store.items.map(item => item.data)
    );
  }

  reset() {
    const { store } = this.props;

    store.reset();
  }

  bulkUpdate(value: object, items: Array<object>) {
    const { store } = this.props;

    const items2 = store.items.filter(item => ~items.indexOf(item.pristine));
    items2.forEach(item => item.change(value));
  }

  getSelected() {
    const { store } = this.props;

    return store.selectedItems.map(item => item.data);
  }

  dragTipRef(ref: any) {
    if (!this.dragTip && ref) {
      this.initDragging();
    } else if (this.dragTip && !ref) {
      this.destroyDragging();
    }

    this.dragTip = ref;
  }

  initDragging() {
    const store = this.props.store;
    const dom = findDOMNode(this) as HTMLElement;
    const ns = this.props.classPrefix;
    this.sortable = new Sortable(
      dom.querySelector(`.${ns}Cards-body`) as HTMLElement,
      {
        group: 'table',
        animation: 150,
        handle: `.${ns}Card-dragBtn`,
        ghostClass: `is-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);
          }

          store.exchange(e.oldIndex, e.newIndex);
        }
      }
    );
  }

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

  renderActions(region: string) {
    let {
      actions,
      render,
      store,
      classnames: cx,
      classPrefix: ns,
      headerBulkActions,
      footerBulkActions,
      headerActions
    } = this.props;
    let btn;
    actions = Array.isArray(actions) ? actions.concat() : [];
    const bulkActions = (headerBulkActions?.length ?? 0) + (footerBulkActions?.length ?? 0)
    if(region === 'header') {
      actions = actions.concat(headerActions || [], (headerBulkActions || []).map((item: any) => ({...item, isBulk: true})))
    }

    if (
      !~this.renderedToolbars.indexOf('check-all') &&
      !store.hideCheckToggler && //Aug
      region === 'footer' && bulkActions > 0 &&
      (btn = this.renderCheckAll())
    ) {
      actions.unshift({
        type: 'button',
        children: btn
      });
    }

    if (
      region === 'header' &&
      !~this.renderedToolbars.indexOf('drag-toggler') &&
      (btn = this.renderDragToggler())
    ) {
      actions.unshift({
        type: 'button',
        children: btn
      });
    }

    return Array.isArray(actions) && actions.length ? (
      <div className={cx('Cards-actions')}>
        {actions.map((action, key) =>
          action.isBulk ? this.props.bulkActionRender?.(action, key) : render(
            `action/${key}`,
            {
              type: 'button',
              ...action
            },
            {
              onAction: this.handleAction,
              key,
              btnDisabled: store.dragging
            }
          )
        )}
      </div>
    ) : null;
  }

  renderHeading() {
    let { title, store, hideQuickSaveBtn, classnames: cx, data } = this.props;

    if (title || (store.modified && !hideQuickSaveBtn) || store.moved) {
      return (
        <div className={cx('Cards-heading')}>
          {store.modified && !hideQuickSaveBtn ? (
            <span>
              {`当前有 ${store.modified} 条记录修改了内容, 但并没有提交。请选择:`}
              <button
                type="button"
                className={cx('Button Button--xs Button--success m-l-sm')}
                onClick={this.handleSave}
              >
                <Icon icon="check" className="icon m-r-xs" />
                提交
              </button>
              <button
                type="button"
                className={cx('Button Button--xs Button--danger m-l-sm')}
                onClick={this.reset}
              >
                <Icon icon="close" className="icon m-r-xs" />
                放弃
              </button>
            </span>
          ) : store.moved ? (
            <span>
              {`当前有 ${store.moved} 条记录修改了顺序, 但并没有提交。请选择:`}
              <button
                type="button"
                className={cx('Button Button--xs Button--success m-l-sm')}
                onClick={this.handleSaveOrder}
              >
                <Icon icon="check" className="icon m-r-xs" />
                提交
              </button>
              <button
                type="button"
                className={cx('Button Button--xs Button--danger m-l-sm')}
                onClick={this.reset}
              >
                <Icon icon="close" className="icon m-r-xs" />
                放弃
              </button>
            </span>
          ) : title ? (
            filter(title, data)
          ) : (
            ''
          )}
        </div>
      );
    }

    return null;
  }

  // Aug
  getMobileUI() {
    return isMobile() && this.props.useMobileUI
  }

  renderTools = () => {
    const {
      header,
      headerClassName,
      headerToolbar,
      headerToolbarRender,
      crudRenderToolbarFunc,
      showHeader,
      render,
      store,
      env,
      classnames: cx,
      translate: __,
      filterRender,//Aug
      data
    } = this.props;
    if (!headerToolbar?.length) return null;
    /** 折叠在工具里的tools */
    const foldedHeaderTools = [];
    /** 在筛选/多选右侧的tools */
    const unfoldedHeaderTools = [];

    headerToolbar.forEach((item) => {
      const { type, isToolBar, foldable } = item;
      /** 是否是移动端的工具 */
      if (isToolBar) {
        /** foldable: 是否归到折叠菜单中 */
        /** 配置非折叠的工具 */
        if (!foldable) {
          unfoldedHeaderTools.push(item);
        } else {
          foldedHeaderTools.push(item);
        }

      }
    });
    {/* 搜索 */ }
    const isFilter = !!Object.keys(data.filterParam || {}).length
    const filterNode = filterRender && filterRender(isFilter)
    {/* 批量 */ }
    const checkAll = (this.props.headerBulkActions?.length || this.props.footerBulkActions?.length) ?
      <span
        className={cx('Mobile-batch-manage', { 'is-active': !store.hideCheckToggler })}
        onClick={e => {
          e.preventDefault()
          store.toggableHideCheck()
        }} >
        {store.hideCheckToggler ? (
          <>
            <Icon icon="#icon-tooltool_list" className="batch-manage-icon" />
            <span className="batch-text">{__('CRUD.select')}</span>
          </>
        ) : (
          __('Wizard.finish')
        )}
      </span> : null;

    // const tools = []
    // if (!headerToolbar.some((item: any) => item.type == 'type-conversion')) {
    //   return
    // }
    // tools.push({
    //   label: '表格模式',
    //   type: 'switch-layout', icon: <FileSyncOutlined />
    // });

    return (<>
      {foldedHeaderTools?.length ? (<Popover showArrow={false} placement="bottom" getPopupContainer={env.getModalContainer}
        trigger="click" overlayClassName="table-toolbar-pop" autoAdjustOverflow visible={this.state.toolbarShow}
        onOpenChange={(open) => this.setState({ toolbarShow: open })}
        content={
          <div className='toolbar-container' onClick={() => this.setState({ toolbarShow: false })}>
            {
              foldedHeaderTools.map((item: any, index: number) => {
                return this.renderToolbar(item) ?? crudRenderToolbarFunc(item);
              })
            }
          </div>}>
        <div className={cx('Mobile-batch-manage')} onClick={() => this.setState({ toolbarShow: true })}>
          {/* <i className="fa fa-cog" aria-hidden="true"></i> */}
          <Icon icon='#icon-toolbox' className="icon" />
          <span className='batch-text'>{__('Table.tools')}</span>
        </div>
      </Popover>) : null}
      {/* 前端维护的固定的刷新/筛选 */}
      {filterNode}
      {checkAll}

      {/* 手动配置的 展示在右侧的按钮 */}
      {
        unfoldedHeaderTools.map((item) => {
          return (
            <div className={cx('Mobile-batch-manage')}>
              {this.renderToolbar(item) ?? crudRenderToolbarFunc(item)}
            </div>
          )
        })
      }
    </>)
  }

  renderHeader() {
    const {
      header,
      headerClassName,
      headerToolbar,
      headerToolbarRender,
      showHeader,
      render,
      store,
      classnames: cx,
      translate: __,
      filterRender,//Aug
      data
    } = this.props;

    if (showHeader === false) {
      return null;
    }

    // Aug
    if (this.getMobileUI()) {
      return (
        <div className={cx('Mobile-header-toolbar-wrapper')}>
          <div className='filter-conditions'>
            {typeof data.total == 'number' ? __('CRUD.total', { total: data.total }) : null}
            {data.selectedItems?.length ? <span style={{ marginLeft: 10 }}>{__('CRUD.checked', { count: data.selectedItems.length })}</span> : null}
          </div>
          <div className='header-btns'>
            {this.renderTools()}
            {/* {filterNode}
            {checkAll} */}
          </div>
        </div>
      )
    }

    const child = headerToolbarRender
      ? headerToolbarRender(
        {
          ...this.props,
          selectedItems: store.selectedItems.map(item => item.data),
          items: store.items.map(item => item.data),
          unSelectedItems: store.unSelectedItems.map(item => item.data)
        },
        this.renderToolbar,
        isMobile() ? null : this.renderPageNation
      )
      : null;
    const actions = this.renderActions('header');
    const toolbarNode =
      actions || child || store.dragging ? (
        <div className={cx('Cards-toolbar')} key="header-toolbar">
          {actions}
          {child}
          {store.dragging ? (
            <div className={cx('Cards-dragTip')} ref={this.dragTipRef}>
              {__('Card.dragTip')}
            </div>
          ) : null}
        </div>
      ) : null;
    const headerNode = header ? (
      <div className={cx('Cards-header', headerClassName)} key="header">
        {render('header', header)}
      </div>
    ) : null;
    return headerNode && toolbarNode
      ? [headerNode, toolbarNode]
      : headerNode || toolbarNode || null;
  }

  renderPageNation = () => {
    const {
      footerToolbar,
      footerToolbarRender,
      store,
      classnames: cx
    } = this.props;
    let _footer = footerToolbar || []
    const child = footerToolbarRender
    ? footerToolbarRender(
      {
        ...this.props,
        selectedItems: store.selectedItems.map(item => item.data),
        items: store.items.map(item => item.data),
        unSelectedItems: store.unSelectedItems.map(item => item.data)
      },
      this.renderToolbar,
      _footer
    )
    : null;
    const actions = this.renderActions('footer');
    const toolbarNode = (actions || child )? (
      <div className={cx('Cards-toolbar', 'Cards-toolbar-page')} key="footer-toolbar">
        {actions}
        {child}
      </div>
    ) : null;
    return toolbarNode;
  }

  renderFooter() {
    const {
      footer,
      footerClassName,
      headerToolbar, //Aug
      footerToolbar,
      footerToolbarRender,
      render,
      showFooter,
      store,
      headerActions,
      classnames: cx
    } = this.props;
    if (showFooter === false) {
      return null;
    }
    let _footer = footerToolbar || []
    if (this.getMobileUI()) {
      // 勾选批量状态时
      if (!store.hideCheckToggler) {
        _footer = ['headerBulkActions', 'footerBulkActions']
      } else {
        if (headerToolbar) {
          // 移动端将所有操作统一放在在底部
          _footer = _footer.concat(headerActions || [], headerToolbar)
        }
        // 非勾选状态不渲染批量操作
        _footer = _footer.filter((item: any) => {
          const type = (item as Schema).type || item
          return !['bulk-actions',
            'headerBulkActions',
            'footerBulkActions',
            'bulkActions',
            'pagination',
            'statistics',
            'switch-per-page',].includes(type)
        })
      }
    const child = footerToolbarRender
      ? footerToolbarRender(
        {
          ...this.props,
          selectedItems: store.selectedItems.map(item => item.data),
          items: store.items.map(item => item.data),
          unSelectedItems: store.unSelectedItems.map(item => item.data)
        },
        this.renderToolbar,
        _footer
      )
      : null;
    const actions = this.renderActions('footer');
    const toolbarNode =
      actions || child ? (
        <div className={cx('Cards-toolbar')} key="footer-toolbar">
          {actions}
          {child}
        </div>
      ) : null;
    const footerNode = footer ? (
      <div className={cx('Cards-footer', footerClassName)} key="footer">
        {render('footer', footer)}
      </div>
    ) : null;
    return footerNode && toolbarNode ? [toolbarNode, footerNode] : footerNode || toolbarNode || null;
    }
    return null;
  }

  renderCheckAll() {
    const { store, multiple, selectable, classnames: cx, classPrefix: ns, translate: __ } = this.props;

    if (
      !store.selectable ||
      !multiple ||
      !selectable ||
      store.dragging ||
      !store.items.length
    ) {
      return null;
    }

    // return (
    //   <Button
    //     key="checkall"
    //     tooltip="切换全选"
    //     onClick={this.handleCheckAll}
    //     size="sm"
    //     level={store.allChecked ? 'info' : 'default'}
    //   >
    //     全选
    //   </Button>
    // );
    // Aug
    return (
      this.getMobileUI() ? <div key="checkall" className={cx('Mobile-checkall')} >
        <Checkbox
          classPrefix={ns}
          type={multiple ? 'checkbox' : 'radio'}
          checked={store.allChecked}
          onChange={this.handleCheckAll}
          inline
        />
        <span>{__('Select.checkAll')}</span>
      </div> :
        <div className={cx('Context-checkall')}>
          <ContextMenu
            menuItems={[
              { id: 0, title: '全选' },
              { id: 1, title: '反选' },
              { id: 2, title: '不选' }
            ]}
            onItemClick={index => this.handleCheckAll(index)}
            key={Date()}
          >
            <th onClick={() => { this.handleCheckAll(3) }}>
              <Checkbox
                classPrefix={ns}
                partial={!store.allChecked}
                checked={store.someChecked}
                disabled={store.disabledHeadCheckbox}
              // onChange={this.handleCheckAll}
              />
            </th>
          </ContextMenu>
        </div>


    );
  }

  renderDragToggler() {
    const { store, multiple, selectable, env, translate: __ } = this.props;

    if (!store.draggable || store.items.length < 2) {
      return null;
    }

    return (
      <Button
        iconOnly
        key="dragging-toggle"
        tooltip={__('Card.toggleDrag')}
        tooltipContainer={
          env?.getTopModalContainer || undefined
        }
        size="sm"
        active={store.dragging}
        onClick={(e: React.MouseEvent<any>) => {
          e.preventDefault();
          store.toggleDragging();
          store.dragging && store.clear();
        }}
      >
        <Icon icon="exchange" className="icon r90" />
      </Button>
    );
  }

  renderToolbar(toolbar: SchemaNode, index: number) {
    const type = (toolbar as Schema).type || (toolbar as string);

    if (type === 'drag-toggler') {
      this.renderedToolbars.push(type);
      return this.renderDragToggler();
    } else if (type === 'check-all') {
      this.renderedToolbars.push(type);
      return this.renderCheckAll();
    } else if (type === 'columns-toggler') {
      return null
    }

    return void 0;
  }

  render() {
    const {
      className,
      store,
      columnsCount,
      itemClassName,
      placeholder,
      render,
      affixHeader,
      card,
      onAction,
      multiple,
      hideCheckToggler,
      checkOnItemClick,
      masonryLayout,
      itemsClassName,
      classnames: cx,
      classPrefix: ns,
      data,
      translate: __,
      autoFillHeight,
      infinteLoad,
      onLoadMore,
      loadHasMore,
      loadDataOnce,
      loadmoreLoading,
      headerBulkActions,
      footerBulkActions,
      columns,
      renderAggregate
    } = this.props;

    const inCombination = Boolean(this.body?.closest(`.${ns}Panel-Combination`))
    const bulkActions = (headerBulkActions?.length ?? 0) + (footerBulkActions?.length ?? 0)
    const { exhibition } = this.state

    this.renderedToolbars = []; // 用来记录哪些 toolbar 已经渲染了，已经渲染了就不重复渲染了。
    let itemFinalClassName: string = columnsCount
      ? `Grid-col--sm${Math.round(12 / columnsCount)}`
      : itemClassName || '';
    const header = isMobile() && inCombination ? null : this.renderHeader();
    const heading = this.renderHeading();
    const footer = this.renderFooter();
    let masonryClassName = '';

    if (masonryLayout) {
      masonryClassName =
        'Cards--masonry ' +
        itemFinalClassName
          .split(/\s/)
          .map(item => {
            if (/^Grid-col--(xs|sm|md|lg)(\d+)/.test(item)) {
              return `Cards--masonry${ucFirst(RegExp.$1)}${RegExp.$2}`;
            }

            return item;
          })
          .join(' ');
    }

    return (
      <div
        ref={this.bodyRef}
        className={cx('Cards', className, {
          'Cards--unsaved': !!store.modified || !!store.moved,
          // Aug
          'is-mobile': this.getMobileUI()
        })}
      >
        {affixHeader ? (
          <div className={cx('Cards-fixedTop')}>
            {header}
            {heading}
          </div>
        ) : null}
        {header}
        {heading}
        {renderAggregate?.()}
        {/* Aug */}
        <div className={cx('Cards-content', {
          'hasHeader': header,
          'hasFooter': footer,
        })}>
          {store.items.length ? (
            <div
              ref={this.itemsRef}
              className={cx('Cards-body Grid Cards-items', itemsClassName, masonryClassName)}
            >
              {store.items.map((item, index) => {
                return (
                  <div key={item.index} className={cx(itemFinalClassName)}>
                    {render(
                      `${index}`,
                      {
                        // @ts-ignore
                        type: 'card',
                        ...card
                      },
                      {
                        className: cx((card && card.className) || '', {
                          'is-checked': item.checked,
                          'is-modified': item.modified,
                          'is-moved': item.moved
                        }),
                        item,
                        intemIndex: item.index,
                        multiple,
                        hideCheckToggler: store.hideCheckToggler,
                        selectable: store.selectable,
                        checkable: item.checkable,
                        draggable: item.draggable,
                        selected: item.checked,
                        onSelect: item.toggle,
                        dragging: store.dragging,
                        data: item.locals,
                        checkOnItemClick,
                        onAction,
                        dataColumns: columns,
                        onCheck: this.handleCheck,
                        bulkActions,
                        onQuickChange: store.dragging
                          ? null
                          : this.handleQuickChange
                      }
                    )}
                  </div>
                );
              })}
              {
                exhibition > 0 && Array.from({ length: exhibition }, (_, index) => index + 1).map(() => {
                  return <div className={cx(itemFinalClassName)}>
                  </div>
                })
              }
            </div>
          ) :
            (
              <div className={cx('Cards-placeholder')}>
                {render('placeholder', __(placeholder))}
              </div>
            )
          }
          {/* Aug */}
          {(!inCombination && infinteLoad) && <InfinteSroll loadMore={onLoadMore} hasMore={loadHasMore} hasData={!!data?.items?.length} loadDataOnce={loadDataOnce} loadmoreLoading={loadmoreLoading} />}


        </div>
        {footer}
      </div>
    );
  }
}

@Renderer({
  test: /(^|\/)(?:crud\/body\/grid|cards)$/,
  name: 'cards',
  storeType: ListStore.name,
  weight: -100 // 默认的 grid 不是这样，这个只识别 crud 下面的 grid
})
export class CardsRenderer extends Cards {
  dragging: boolean;
  selectable: boolean;
  selected: boolean;
  onSelect: boolean;
  title?: string;
  subTitle?: string;
  desc?: string;
  avatar?: string;
  avatarClassName?: string;
  body?: SchemaNode;
  actions?: Array<Action>;
}
