import React from 'react';
import { ClassNamesFn } from '../../theme';
import { IColumn, IRow, ITableStore } from '../../store/table';
import { SchemaNode, Action } from '../../types';
import { TableRow } from './TableRow';
import { filter } from '../../utils/tpl';
import { observer } from 'mobx-react';
import { LocaleProps } from '../../locale';
import { ActionSchema } from '../Action';
import cloneDeep from 'lodash/cloneDeep';
import { ControlledContextMenu } from '../Lion/components/LionContextMenu';
import { copy } from '../Lion/utils/utils';
import msgsub from '../Lion/utils/msgsub';
import Modal from 'antd/lib/modal';
import Button from 'antd/lib/button';
import { calcFn, translateNumber } from '../../utils/utils';
import { isMobile, numberFormatter, standardValueText } from '../../utils/helper';
import { isNil } from 'lodash';
import { CountItem } from '../Table';
import { flatMap } from 'lodash';

export interface TableBodyProps extends LocaleProps {
  className?: string;
  rowsProps?: any;
  tableClassName?: string;
  classnames: ClassNamesFn;
  columns: Array<IColumn>;
  rows: Array<IRow>;
  render: (region: string, node: SchemaNode, props?: any) => JSX.Element;
  renderCell: (
    region: string,
    column: IColumn,
    item: IRow,
    props: any
  ) => React.ReactNode;
  onCheck: (item: IRow, value: boolean, shift?: boolean) => void;
  onQuickChange?: (
    item: IRow,
    values: object,
    saveImmediately?: boolean | any,
    savePristine?: boolean
  ) => void;
  footable?: boolean;
  ignoreFootableContent?: boolean;
  footableColumns: Array<IColumn>;
  checkOnItemClick?: boolean;
  buildItemProps?: (item: IRow, index: number) => any;
  onAction?: (e: React.UIEvent<any>, action: Action, ctx: object) => void;
  rowClassNameExpr?: string;
  rowClassName?: string;
  data?: any;
  prefixRow?: Array<any>;
  affixRow?: Array<CountItem>;
  itemAction?: ActionSchema;
  // Jay
  store: ITableStore;
  stickyWidths?: { [key: string]: number };
  position: [rowIndex: number, colName: string]
  primaryField: string
  contextMenuVisible: boolean
  onContextMenuVisibleChange: (visible: boolean) => void
  headCurrentRows?: (val: boolean) => void
  setBorder?: boolean
  rowItems: any[]
  tableName?: string
}
interface TableState {
  index?: any;
  current?: any;
  summaryVisible: boolean;
  clearFormat: boolean;
}
@observer
export class TableBody extends React.Component<TableBodyProps, TableState> {
  menuItems: { id: number, title: string, children?: any[] }[]
  constructor(props: TableBodyProps) {
    super(props);
    this.state = {
      index: props.itemAction ? 0 : null,
      current: null,
      summaryVisible: false,
      clearFormat: false
    }
    this.headCurrentRows = this.headCurrentRows.bind(this)
    this.headKeydown = this.headKeydown.bind(this)
    this.menuItems = [
      { id: 0, title: '复制单元格' },
      { id: 1, title: '复制单元格名称' },
      { id: 2, title: '复制行' },
      { id: 3, title: '复制行和表头' },
      { id: 4, title: '复制列', children: flatMap(props.columns ?? [], (column) => column.name == 'operation' || column.name == undefined ? [] : ({ id: column.name, title: column.label, groupName: column.groupName })) },
      { id: 5, title: '复制全部数据' }
    ].concat({
      id: 7, title: '复制时去除格式', isCheckbox: true
    } as any)
  }

  componentWillUnmount() {
    document.body.onkeydown = null

  }
  dom: any = React.createRef();
  headCurrentRows(index: number, val: any) {
    this.setState({
      index: index,
      current: index,
    },
      () => {
        document.body.onkeydown = (e) => {
          this.headKeydown(e, val);
        };
      })
  }
  headKeydown(e: any, val: any) {
    const { rows, itemAction, onAction } = this.props
    let { current } = this.state
    if (e.key === "ArrowUp" || e.key === "ArrowDown") {
      // tbody及高度
      const currentParent = this.dom.current.parentElement.parentElement
      // 表格头部thead及高度
      const previous = this.dom.current.previousElementSibling
      const previousHeight = previous.clientHeight
      //cxd-Table-content
      const content = currentParent.parentElement
      //可视区域，不包括头部
      const visual = content.clientHeight - previousHeight
      // 可视区域内容条数
      const contnumber = Math.floor(visual / val.current.clientHeight) - 2
      if (e.key === "ArrowUp") {
        if (current > 0) {
          --current;
          this.setState({ current: current }, () => {
            if (current >= contnumber) {
              content.scrollTop = (current - contnumber) * val.current.clientHeight
            }
          });
        }
      }
      if (e.key === "ArrowDown") {
        if (current < rows.length - 1) {
          ++current;
          this.setState({ current: current }, () => {
            if (current >= contnumber - 2) {
              content.scrollTop = (current - contnumber) * val.current.clientHeight
            }
          });
        }
      }
    }
    if (e.key === "Enter") {
      this.setState({ index: current })
      if (itemAction) {
        onAction && onAction(e, itemAction as any, rows[current]?.data);
      }
    }
  }

  renderRows(
    rows: Array<any>,
    columns = this.props.columns,
    rowProps: any = {}
  ): any {
    const {
      rowClassName,
      rowClassNameExpr,
      onAction,
      buildItemProps,
      checkOnItemClick,
      classnames: cx,
      render,
      renderCell,
      onCheck,
      onQuickChange,
      footable,
      ignoreFootableContent,
      footableColumns,
      itemAction,
      store,
    } = this.props;
    // Aug
    let allColumns: Array<IColumn> = cloneDeep(columns)
    if (store?.mobileUI && footable && footableColumns.length) {
      allColumns.splice(-1, 0, ...footableColumns)
    }

    return rows.map((item: IRow, rowIndex: number) => {
      const itemProps = buildItemProps ? buildItemProps(item, rowIndex) : null;
      const itemHighlight = (this.state.index == rowIndex)
      const currentHighlight = (this.state.current == rowIndex)
      const doms = [
        <TableRow
          {...itemProps}
          itemAction={itemAction}
          classnames={cx}
          checkOnItemClick={checkOnItemClick}
          key={item.id}
          itemIndex={rowIndex}
          item={item}
          headCurrentRows={this.headCurrentRows}
          itemHighlight={itemHighlight}
          currentHighlight={currentHighlight}
          itemClassName={cx(
            rowClassNameExpr
              ? filter(rowClassNameExpr, item.data)
              : rowClassName,
            {
              'is-last': item.depth > 1 && rowIndex === rows.length - 1
            }
          )}
          // columns={columns}
          // Aug 移动端且展开更多信息时加载所有列
          columns={store?.mobileUI && item.expanded ? allColumns : columns}
          renderCell={renderCell}
          render={render}
          onAction={onAction}
          onCheck={onCheck}
          // todo 先注释 quickEditEnabled={item.depth === 1}
          onQuickChange={onQuickChange}
          {...rowProps}
          // Jay
          store={this.props.store}
          stickyWidths={this.props.stickyWidths}
          setBorder={this.props.setBorder}
        />
      ];

      // Aug 加入mobile判断，移动端将列统一放在上面一个tablerow里
      if (!store?.mobileUI && footable && footableColumns.length) {
        if (item.depth === 1) {
          doms.push(
            <TableRow
              {...itemProps}
              itemAction={itemAction}
              classnames={cx}
              checkOnItemClick={checkOnItemClick}
              key={`foot-${item.id}`}
              itemIndex={rowIndex}
              item={item}
              itemClassName={cx(
                rowClassNameExpr
                  ? filter(rowClassNameExpr, item.data)
                  : rowClassName
              )}
              columns={footableColumns}
              renderCell={renderCell}
              render={render}
              onAction={onAction}
              onCheck={onCheck}
              footableMode
              footableColSpan={columns.length}
              onQuickChange={onQuickChange}
              ignoreFootableContent={ignoreFootableContent}
              {...rowProps}
              // Jay
              store={this.props.store}
              stickyWidths={this.props.stickyWidths}
              setBorder={this.props.setBorder}
            />
          );
        }
      } else if (item.children.length && item.expanded) {
        // 嵌套表格
        doms.push(
          ...this.renderRows(item.children, columns, {
            ...rowProps,
            parent: item
          })
        );
      }
      return doms;
    });
  }

  renderStatisticRow(countFields: CountItem[] = []) {
    const { columns, classnames: cx, rows, stickyWidths, store, rowClassName, tableName, translate: __ } = this.props;
    if (Array.isArray(countFields) && countFields.length > 0) {
      const items = rows.map(row => row.locals)
      return (
        <tr className={cx('Table-tr', 'is-summary', rowClassName)} key={`summary-${0}`} onClick={() => this.setState({ summaryVisible: true })}>
          {columns.map(column => {
            const rawName = column.pristine.rawName ?? column.name
            const field = countFields?.find(item => rawName === item.name)
            const leftFixedColumns = store.leftFixedColumns
            const lastLeftFixedIndex = leftFixedColumns[leftFixedColumns.length - 1]?.index
            const rightFixedColumns = store.rightFixedColumns
            const firstRightFixedIndex = rightFixedColumns[0]?.index
            const tdClassName = `${cx(column.pristine.className, this.props.setBorder ? 'td-border' : '',
              {
                'fixed-left-last': column.index === lastLeftFixedIndex,
                'fixed-right-first': column.index === firstRightFixedIndex
              }
            )}`
            const tdStyle = {
              position: 'sticky', bottom: 0, zIndex: column.fixed == 'left' || column.fixed == 'right' ? 4 : 1,
              left: column.fixed === 'left' && stickyWidths?.[`${column.index}`],
              right: column.fixed === 'right' && stickyWidths?.[`${column.index}`],
              maxWidth: column.pristine.width || "200px",
              width: column.pristine.width || 'unset',
              textAlign: column.align
            } as any
            if (field) {
              const formulaRule = field.formula?.toLocaleLowerCase()
              const showText = (field.rule ?? '') + '：'
              let value: any = calcFn(formulaRule, column.name ?? '', items)
              if (formulaRule === 'count') {
                value = showText + value
                return <td table-name={tableName} column-name={column.name} title={value} className={tdClassName} style={tdStyle} key={column.index}>{value}</td>
              }
              if (column.pristine?.showUppercase) {
                value = showText + translateNumber(value, column.pristine?.showUppercase)
                return <td table-name={tableName} column-name={column.name} title={value} className={tdClassName + ' ellipsis'} style={tdStyle} key={column.index}>{value}</td>
              }

              value = value.toFixed(column.pristine.precision ?? 2)
              if (column.pristine?.kilobitSeparator && column.pristine?.showUppercase === 0) {
                value = numberFormatter(value, column.pristine.precision ?? 2);
              }
              value = `${showText}${column.pristine.prefix ?? ''}${value}${column.type === 'progress' ? '%' : (column.pristine.suffix ?? '')}`
              return (
                <td table-name={tableName} column-name={column.name} title={value} className={tdClassName + ' ellipsis'} style={tdStyle} key={column.index}>{value}</td>
              )
            }
            return <td table-name={tableName} column-name={column.name} className={tdClassName} style={tdStyle} key={column.index}></td>
          })}
        </tr>
      )
    }
    return null
  }

  summaryContent = () => {
    const { affixRow, columns, render, translate: __ } = this.props;
    const list = affixRow?.filter(item => item.name);
    //对list进行排序，根据columns的顺序来展示
    const showList: CountItem[] = [];
    columns.forEach(item => {
      const targetField = list?.find(litem => litem.name === item.name);
      if (targetField) showList.push(targetField);
    })
    return showList.map(item => {
      let column = columns.find(col => col.name === item.name);
      if (!column) return null;
      const formulaRule = item.formula?.toLocaleLowerCase()
      const calc = calcFn(formulaRule, column?.name ?? '', this.props.rowItems)
      return (<div className='summary-row-box'>
        <div className='field-name'>{item.label ?? ''}</div>
        {formulaRule === 'count' ? <div className='field-value'>{calc}</div> :
          <div className='field-value'>{render('', { ...column?.pristine, type: 'number' }, { value: calc })}</div>}
      </div>)
    })
  }

  renderSummaryFooter = () => {
    return <div>
      <Button block ghost type='link' style={{ letterSpacing: '5px', fontSize: '16px' }} onClick={() => this.setState({ summaryVisible: false })}>确定</Button>
    </div>
  }

  renderSummaryRow(
    position: 'prefix' | 'affix',
    items?: Array<any>,
    rowIndex?: number
  ) {
    const { columns, render, classnames: cx, store, setBorder, stickyWidths } = this.props;
    if (!(Array.isArray(items) && items.length)) {
      return null;
    }
    let offset = 0;
    // 将列的隐藏对应的把总结行也隐藏起来
    const result: any[] = items.map((item, index) => {
      let colIdxs: number[] = [offset + index - (columns[columns.length - 1].type === 'operation' && isMobile() ? 1 : 0)];
      if (item.colSpan > 1) {
        for (let i = 1; i < item.colSpan; i++) {
          colIdxs.push(offset + index + i);
        }
        offset += item.colSpan - 1;
      }
      const matchedColumns = colIdxs
        .map(idx => columns.find(col => col.rawIndex === idx))
        .filter(item => item);
      return {
        ...item,
        colSpan: matchedColumns.length,
        firstColumn: matchedColumns[0],
        lastColumn: matchedColumns[matchedColumns.length - 1]
      };
    }).filter(item => item.colSpan);
    if (result.length == 0) return null;
    //  如果是勾选栏，展开栏，拖拽栏，序号栏让它和下一列合并。
    if (result[0] && typeof columns[0]?.type === 'string' && columns[0]?.type.substring(0, 2) === '__') {
      result[0].colSpan = (result[0].colSpan || 1) + 1;
    }
    if (result[1] && typeof columns[1]?.type === 'string' && columns[1]?.type.substring(0, 2) === '__') {
      result[0].colSpan = (result[0].colSpan || 1) + 1;
    }
    // 缺少的单元格补齐
    let appendLen = columns.length - result.reduce((p, c) => p + (c.colSpan || 1), 0);
    // 多了则干掉一些
    while (appendLen < 0) {
      const item = result.pop();
      if (!item) {
        break;
      }
      appendLen += item.colSpan || 1;
    }
    // 少了则补个空的
    if (appendLen) {
      const item = /*result.length
        ? result.pop()
        : */ {
        type: 'html',
        html: '&nbsp;'
      };
      const column = store.filteredColumns[store.filteredColumns.length - 1];
      result.push({
        ...item,
        colSpan: /*(item.colSpan || 1)*/ 1 + appendLen,
        firstColumn: column,
        lastColumn: column
      });
    }
    return (
      <tr
        className={cx('Table-tr', 'is-summary')}
        key={`summary-${position}-${rowIndex || 0}`}
        style={{ position: 'sticky', bottom: 0, zIndex: 1 }}
        onClick={() => isMobile() ? this.setState({ summaryVisible: true }) : null}
      >
        {result.map((item, index) => {
          const column = item.firstColumn;
          const tdStyle = {
            position: 'sticky', bottom: 0, zIndex: column.fixed == 'left' || column.fixed == 'right' ? 4 : 1,
            left: column.fixed === 'left' && stickyWidths?.[`${column.index}`],
            right: column.fixed === 'right' && stickyWidths?.[`${column.index}`],
            maxWidth: column.pristine.width || "200px",
            width: column.pristine.width,
            textAlign: column.align
          } as any
          const Com = item.isHead ? 'th' : 'td';
          if (item.tpl) {
            const str = item.tpl.split('pick:')[1];
            const fieldList = str.split('|');
            const fieldName = fieldList[0];
            let unitName = fieldList[1];
            if (unitName.includes('}')) unitName = unitName.split('}')[0];
            const targetCol = columns.find(col => col.name === fieldName);
            const prevStr = item.tpl.split('${')[0];
            const nextStr = item.tpl.split('}')[1];
            const calc = calcFn(unitName, targetCol?.name ?? '', this.props.rowItems)
            let newValue: any = calc;
            newValue = !isNil(newValue) ? standardValueText(newValue, { suffix: '', prefix: '', kilobitSeparator: targetCol?.pristine.kilobitSeparator, precision: targetCol?.pristine.precision, showUppercase: targetCol?.pristine.showUppercase }) : 0
            const finalValue = prevStr + (unitName === 'count' ? calc : newValue) + nextStr
            return (
              <Com
                key={index}
                colSpan={item.colSpan}
                className={cx({ 'td-border': setBorder }, item.cellClassName, 'ellipsis')}
                style={tdStyle}
                title={finalValue}
                table-name={this.props.tableName}
              >
                {finalValue}
              </Com>
            )
          }
          return (
            <Com
              key={index}
              colSpan={item.colSpan}
              className={cx({ 'td-border': setBorder }, item.cellClassName)}
              style={tdStyle}
              table-name={this.props.tableName}
            >
              {/* 这里计算方式和普通表格不一样，只需要将字段表格的数据传进去就行 */}
              {render(`summary-row/${index}`, item, {
                data: { items: this.props.rowItems }
              })}
            </Com>
          );
        })}
      </tr>
    );
  }

  renderSummary(position: 'prefix' | 'affix', items?: Array<any>) {
    return Array.isArray(items)
      ? items.some(i => Array.isArray(i))
        ? items.map((i, rowIndex) =>
          this.renderSummaryRow(
            position,
            Array.isArray(i) ? i : [i],
            rowIndex
          )
        )
        : this.renderSummaryRow(position, items)
      : null;
  }

  handleContextMenu(type: number | string, [rowIndex, colName]: [rowIndx: number, colName: string]) {
    const { store, onContextMenuVisibleChange } = this.props
    const { clearFormat } = this.state;
    onContextMenuVisibleChange(false)
    let value = ' '
    if (typeof type == 'number') {
      switch (type) {
        case 0:
          value = store?.getCopyCellValue(rowIndex, colName, clearFormat) ?? ''
          break
        case 1:
          value = colName
          break
        case 2:
        case 3:
          value = store?.getCopyRowValue(rowIndex, type === 3, clearFormat) ?? ''
          break
        case 4:
          value = store?.getCopyColumnValue(colName, clearFormat) ?? ''
          break
        case 5:
        case 6:
          value = store?.getCopyPageValue(type == 6, clearFormat) ?? ''
          break
        default:
          return
      }
    } else {
      value = store?.getCopyColumnValue(type.split(','), clearFormat) ?? ''
    }
    try {
      copy(value).then(() => {
        msgsub._success('复制成功')
      })
    } catch (error) {
      msgsub._error('复制失败')
    }
  }

  render() {
    const {
      className,
      rows,
      columns,
      rowsProps,
      prefixRow,
      translate: __,
      affixRow,
      data
    } = this.props;
    const { summaryVisible } = this.state;
    return (
      <>
        <ControlledContextMenu
          menuItems={this.menuItems}
          visible={this.props.contextMenuVisible}
          onItemClick={index => this.handleContextMenu(index, this.props.position)}
          onVisibleChange={this.props.onContextMenuVisibleChange}
          clearFormat={this.state.clearFormat}
          onCheckboxChange={(e: CheckboxChangeEvent) => this.setState({ clearFormat: e.target.checked })}
        >
          <tbody className={className} ref={this.dom} >
            {rows.length ? (
              <>
                {this.renderSummary('prefix', prefixRow)}
                {this.renderRows(rows, columns, rowsProps)}
                {this.renderStatisticRow(affixRow)}
              </>
            ) : null}
          </tbody>
        </ControlledContextMenu>
        {summaryVisible && <Modal maskStyle={{ zIndex: 1111 }} wrapClassName="summary-modal-wrap" className={`summary-modal`} width={300} closable={false} getContainer={() => document.getElementById('amis-modal-container') || document.body} footer={this.renderSummaryFooter()}
          okText="确定" title="数据小计" visible={summaryVisible}>
          {
            this.summaryContent()
          }
        </Modal>}
      </>
    );
  }
}
