import * as React from 'react';
import {
  IStoreState,
  ID,
  EditorUsage,
  ISelectionType,
  IRow,
  ICell,
  IColumn,
  IRowDimensions,
  IColDimensions,
} from '../index.data';
import DataSheet from '../DataSheet';
import { connect } from 'unistore/react';
import styles from './index.less';
import Selected from '../Selected';
import { fsmPred } from '../StateMachine/helper';
import HighlightedCells from '../HighlightedCells';
import RuntimeContext from '../RuntimeContext';
import equals from 'fast-deep-equal';
import { getPresentCell } from '../store/selectors';
import PresentCell from '../PresentCell';
import VScrollBar from '../scroll/VScrollBar';
import classnames from 'classnames';
import * as R from 'rambda';
import { pickPatch } from '../utils';
import { Store } from 'unistore';
import { getAllLoadableRowFlags } from '../scroll/VScrollBar/helper';
import HScrollBar from '../scroll/HScrollBar';
import { getAllLoadableColumnFlags } from '../scroll/HScrollBar/helper';

interface Props {}

interface MappedProps {
  usage: EditorUsage;
  mode: any;
  highlightedCells: IStoreState['highlightedCells'];
  presentCell: ID | null;
  isActiving: boolean;

  colDimensions: IColDimensions;
  rowDimensions: IRowDimensions;
  // for DataSheet
  selectionType: ISelectionType | null;
  selectionCellRange: [ID, ID];
  // for selected
  selectionRowRange: [ID, ID];
  selectionColumnRange: [ID, ID];
  // for DataSheet.RowGroup
  rows: IRow[];
  columns: IColumn[];
  loadableRowFlags: boolean[];
  loadableColumnFlags: boolean[];
  cells: Record<ID, ICell>;
  // for auto scroll to selected
  scrollX: number;
  scrollY: number;
  readyDimensions: boolean;
  freezeAt: IStoreState['freezeAt'];
}

interface MappedActions {
  setScrollXY(xy: { dx: number; dy: number }): { scrollX: number; scrollY: number };
}

// 整个Sheet的外部容器
class SpreadSheet extends React.Component<Props & MappedProps & MappedActions> {
  static contextType = RuntimeContext;
  context!: React.ContextType<typeof RuntimeContext>;

  constructor(props: Props & MappedProps & MappedActions) {
    super(props);

    this.handleWheel = this.handleWheel.bind(this);
  }

  shouldComponentUpdate(nextProps: Props & MappedProps) {
    return !equals(nextProps, this.props);
  }

  handleWheel(e: React.WheelEvent) {
    if (this.props.freezeAt.i >= 0) {
      this.props.setScrollXY({ dx: e.deltaX, dy: e.deltaY });
      // 当滚动后, 对于滚出来的新行, 可能存在重算的需求
      setTimeout(() => {
        this.context!.setSheetDimensions();
      }, 0);
    }
  }

  render() {
    console.log('spreadSheet render');
    const {
      usage,
      mode,
      isActiving,
      highlightedCells,
      presentCell,
      selectionType,
      selectionCellRange,
      rows,
      columns,
      cells,
      loadableRowFlags,
      loadableColumnFlags,
      rowDimensions,
      colDimensions,
      scrollX,
      scrollY,
      readyDimensions,
      freezeAt,
    } = this.props;
    const showPresentCell = usage === 'editor' && presentCell;
    const showSelected = fsmPred.isSelecting(mode);
    const presentCellKey = '' + presentCell!;
    console.log('scrollYYY', scrollY);

    return (
      <div className={classnames(styles['spread-sheet'], 'spread-sheet')}>
        <div
          className={classnames(styles['data-sheet-wrapper'], 'data-sheet-wrapper')}
          onWheel={this.handleWheel}
        >
          <DataSheet
            mode={mode}
            selectionType={selectionType}
            selectionCellRange={selectionCellRange}
            rows={rows}
            columns={columns}
            cells={cells}
            loadableRowFlags={loadableRowFlags}
            loadableColumnFlags={loadableColumnFlags}
          />
          {showPresentCell && (
            <PresentCell
              key={presentCellKey}
              id={presentCell!}
              isActiving={isActiving}
              loadableRowFlags={loadableRowFlags}
              loadableColumnFlags={loadableColumnFlags}
              rowDimensions={rowDimensions}
              colDimensions={colDimensions}
              readyDimensions={readyDimensions}
            />
          )}
          {showSelected && <Selected />}
          {highlightedCells.length > 0 && (
            <HighlightedCells
              highlightedCells={highlightedCells}
              loadableRowFlags={loadableRowFlags}
              loadableColumnFlags={loadableColumnFlags}
              rowDimensions={rowDimensions}
              colDimensions={colDimensions}
            />
          )}
        </div>
        {freezeAt.i >= 0 && (
          <VScrollBar
            rowDimensions={rowDimensions}
            loadableRowFlags={loadableRowFlags}
            scroll={scrollY}
          />
        )}
        {freezeAt.j >= 0 && (
          <HScrollBar
            colDimensions={colDimensions}
            loadableColumnFlags={loadableColumnFlags}
            scroll={scrollX}
          />
        )}
      </div>
    );
  }
}

const mapState = (state: IStoreState, props: Props): MappedProps => {
  return {
    usage: state.usage,
    mode: state.mode,
    highlightedCells: state.highlightedCells,
    presentCell: getPresentCell(state),
    isActiving: !!state.isActiving,
    // for DataSheet
    selectionType: state.selectionType,
    selectionCellRange: state.selectedCellRange,
    // for selected, 必须有, 否则不会 re_render
    selectionRowRange: state.selectedRowRange,
    selectionColumnRange: state.selectedColumnRange,
    // for DataSheet.RowGroup
    rows: state.rows,
    columns: state.columns,
    loadableRowFlags: getAllLoadableRowFlags(state),
    loadableColumnFlags: getAllLoadableColumnFlags(state),
    cells: state.cells,
    colDimensions: state.colDimensions,
    rowDimensions: state.rowDimensions,
    scrollX: state.scrollX,
    scrollY: state.scrollY,
    readyDimensions: !!state.readyDimensions,
    freezeAt: state.freezeAt,
  };
};

const actions = (store: Store<IStoreState>) => ({
  setScrollXY: (state: IStoreState, { dx, dy }: { dx: number; dy: number }) => {
    let scrollX = Math.max(state.scrollX + dx, 0);
    let scrollY = Math.max(state.scrollY + dy, 0);

    const result = pickPatch(store.getState(), {
      scrollX,
      scrollY,
    });
    //   return R.isEmpty(result) ? null : { ...result, readyDimensions: true };
    // 这里无论如何都应该返回readyDimensions:false
    // 原因: 有时滚动发生了, 但未满1格, 所以rowDimensions并未变化, 然后滚动完成后, ReadyDimensions 仍为true
    //      这将导致selected / presentcell 不会显示
    return { ...result, readyDimensions: false };
  },
});

export default connect<Props, any, IStoreState, any>(
  mapState,
  actions,
)(SpreadSheet);
