import {
  createElement,
  forwardRef,
  useState,
  RefForwardingComponent
} from 'rax';
import { useStyles } from '@rax-ui/styles';
import View from 'rax-view';
import Text from "rax-text";
import { isWeex } from 'universal-env';
import ScrollView from 'rax-scrollview';
import StyleProvider from './style';
import TableHeader from "./TableHeader";
import TableCellRow from "./TableCellRow";
import { TableProps, ColumnProps, SortOrder, CompareFn } from "./interface";

const Table: RefForwardingComponent<any, TableProps> = (props, ref) => {
  const {
    locale = { emptyText: "暂无数据" },
    sortDirections = [
      "ascend",
      "descend",
      null
    ] as SortOrder[],
    onHeaderRow, 
    onRow,
    onChange,
    customStyles,
    descIconRender, 
    onClickDescIcon,
    sortIconRender,
    bordered,
    dataSource,
    columns = [],
    children,
    ...others
  } = props;

  const defaultStyles = useStyles(StyleProvider, others, (classNames) => {
    let styles = {
      table: classNames(['table']),
      fixedTable: classNames(['table--fixed']),
      tableBorder: classNames(['table__border']),
      noData: classNames(['table__nodata']),
      noDataText: classNames(['table__nodata__text']),
      header: classNames(['table__header']),
      headerTitle: classNames(['table__header__title']),
      headerCellPadding: classNames(['table__header__cell--padding']),
      headerDesc: classNames(['table__header__desc']),
      headerDescIcon: classNames(['table__header__desc__icon']),
      sort: classNames(['table__header__sort']),
      sortIcon: classNames(['table__header__sort__icon']),
      sortIconAsce: classNames(['table__header__sort__icon--asce']),
      sortIconDesc: classNames(['table__header__sort__icon--desc']),
      sortIconSelected: classNames(['table__header__sort__icon--selected']),
      row: classNames(['table__row']),
      rowBorder: classNames(['table__row__border']),
      columnBorder: classNames(['table__column__border']),
      cell: classNames(['table__row__cell']),
      headerMinHeight: classNames(['table__header__min--height']),
      headerGroup: classNames(['table__header--group']),
      cellPadding: classNames(['table__row__cell__padding']),
      cellTitle: classNames(['table__row__cell__title']),
    };
    if (bordered) {
      const { fixedTable, tableBorder } = styles;
      styles.fixedTable.left = (fixedTable.left as number) + (tableBorder.borderLeftWidth as number);
    }
    if (isWeex) {
      styles.fixedTable.left = 0;
    }
    return styles;
  });

  const [sortedDataSource, setSortedDataSource] = useState();
  const [currentSortColumn, setCurrentSortColumn] = useState();

  const getCurrentSortColumn = () => {
    let sortColumn = null;
    if (currentSortColumn) {
      sortColumn = currentSortColumn;
    }
    return sortColumn;
  }

  const onSort = (column: ColumnProps, useDefaultSortOrder?) => {
    const sortedDataSource = [...dataSource];
    const newColumn = { ...column };
    const sortColumn = getCurrentSortColumn();
    if (sortColumn && sortColumn.key === newColumn.key) {
      newColumn.sortOrder = sortColumn.sortOrder;
    }

    let { sortOrder } = newColumn;
    if (useDefaultSortOrder) {
      sortOrder = column.defaultSortOrder === "ascend" ? null : "ascend";
    }

    const columnSortDirections = column.sortDirections || sortDirections;
    if (!columnSortDirections) {
      return;
    }
    const sortIndex = columnSortDirections.indexOf(sortOrder);
    if (!sortOrder || sortIndex === columnSortDirections.length - 1) {
      const [sortDirection] = columnSortDirections;
      newColumn.sortOrder = sortDirection;
    } else {
      newColumn.sortOrder = columnSortDirections[sortIndex + 1];
    }

    const localSort = column.sorter && typeof column.sorter === "function";
    if (localSort) {
      if (newColumn.sortOrder === "ascend") {
        sortedDataSource.sort(column.sorter as CompareFn);
      }
      if (newColumn.sortOrder === "descend") {
        sortedDataSource.sort(column.sorter as CompareFn).reverse();
      }
    }

    setCurrentSortColumn(newColumn);
    setSortedDataSource(sortedDataSource);

    if (!useDefaultSortOrder && onChange) {
      onChange(newColumn);
    }
  }

  if (!sortedDataSource) {
    columns.forEach((column) => {
      if (column.defaultSortOrder) {
        onSort(column, true);
      }
    });
  }

  const getChildrenColumns = (column: ColumnProps) => {
    if (column.children && Array.isArray(column.children)) {
      let childrenColumns = [];
      column.children.forEach((subColumn) => {
        const newSubColumn = { ...subColumn };
        const children = getChildrenColumns(newSubColumn);
        if (children) {
          childrenColumns = childrenColumns.concat(children);
        } else {
          childrenColumns.push(newSubColumn);
        }
      });
      return childrenColumns;
    }
    return null;
  }

  // 左侧固定的表格
  const renderTable = (dataSource, childrenColumns, columns, style?) => {
    const tableCellRows = [];
    dataSource.forEach((item, index) => {
      tableCellRows.push(
        <TableCellRow
          bordered={bordered}
          key={item.key}
          rowIndex={index}
          dataSource={item}
          columns={childrenColumns}
          styles={styles}
          onRow={onRow}
        />
      );
    });
    return (
      <View style={style}>
        <TableHeader
          onSort={(column) => {
            onSort(column);
          }}
          bordered={bordered}
          columns={columns}
          defaultSortDirections={sortDirections}
          sortColumn={getCurrentSortColumn()}
          styles={styles}
          onHeaderRow={onHeaderRow}
          sortIconRender={sortIconRender}
          descIconRender={descIconRender}
          onClickDescIcon={onClickDescIcon}
        />
        {tableCellRows}
      </View>
    );
  }

  // 可滑动的表格
  const renderScrollableTable = (dataSource, childrenColumns, columns) => {
    return (
      <ScrollView horizontal>
        {renderTable(dataSource, childrenColumns, columns)}
      </ScrollView>
    );
  }

  let tableDataSource = dataSource;
  const defaultStylesDeepCopy = JSON.parse(JSON.stringify(defaultStyles));
  const styles = typeof customStyles === "function" ? customStyles(defaultStylesDeepCopy) : defaultStyles;
  if (sortedDataSource) {
    tableDataSource = sortedDataSource;
  }  
  if (!tableDataSource || !columns) {
    return null;
  }
  if (!tableDataSource.length && columns.length) {
    // 有列配置，没行数据，显示暂无数据
    const { emptyText } = locale;
    return (
      <View style={{...styles.table, ...styles.noData}}>
        <Text style={styles.noDataText}>{emptyText}</Text>
      </View>
    );
  }

  // 尺寸计算
  let fixedWidth = 0;
  const scrollableColumns = [];
  const fixedColumns = [];
  let childrenColumns = [];
  columns.forEach((column) => {
    const children = getChildrenColumns(column);
    if (children) {
      childrenColumns = childrenColumns.concat(children);
    } else {
      childrenColumns.push(column);
    }
  });
  const sortColumn = getCurrentSortColumn();
  childrenColumns.forEach((column) => {
    const newColumn = { ...column };
    if (sortColumn) {
      if (newColumn.key === sortColumn.key) {
        newColumn.sortOrder = sortColumn.sortOrder;
      }
    }
    const scrollableColumn = { ...newColumn };
    const fixedColumn = { ...newColumn };
    if (newColumn.fixed) {
      fixedWidth += newColumn.width;
      scrollableColumn.hidden = true;
    } else {
      fixedColumn.hidden = true;
    }
    fixedColumns.push(fixedColumn);
    scrollableColumns.push(scrollableColumn);
  });

  const scrollableTable = renderScrollableTable(
    tableDataSource,
    scrollableColumns,
    columns
  );
  const fixedTable = fixedWidth > 0 ? renderTable(tableDataSource, fixedColumns, columns, {
    ...styles.fixedTable,
    width: fixedWidth
  }) : null;
  let tableStyle;
  if (bordered) {
    tableStyle = { ...styles.table, ...styles.tableBorder };
  } else {
    tableStyle = styles.table;
  }
  return (
    <View style={tableStyle}>
      {scrollableTable}
      {fixedTable}
    </View>
  );
}

export default forwardRef<any, TableProps>(Table);
