import * as React from 'react';
import { IStoreState, ID, IColDimensions, IRowDimensions } from '../index.data';
import { connect } from 'unistore/react';
import {
  getCellType,
  getCell,
  getCellDimensions,
  getPresentCell,
  getActivedCell,
} from '../store/selectors';
import { getEditor } from '../cellTypes';
import styles from './index.less';
import { IEditor } from '../cellTypes/index.data';
import classnames from 'classnames';
import { FSM_IGNORE } from '../constants';
import { Store } from 'unistore';
import { FormulaEditor } from '../cellTypes';
import * as R from 'rambda';
import RuntimeContext from '../RuntimeContext';
import equals from 'fast-deep-equal';
import FakeEditor from '../cellTypes/base/FakeEditor';
import { fsmPred } from '../StateMachine/helper';

interface Props {
  id: ID;
  loadableRowFlags: boolean[];
  loadableColumnFlags: boolean[];
  isActiving: boolean;
  colDimensions: IColDimensions;
  rowDimensions: IRowDimensions;
  // 指示当前正在滚动, 只有滚动完成后, 重算colDimensions/rowDimensions后, 才能显示Editor
  readyDimensions: boolean;
}

class PresentCell extends React.Component<Props> {
  ref = React.createRef<HTMLDivElement>();

  static contextType = RuntimeContext;
  context!: React.ContextType<typeof RuntimeContext>;

  forceShowFormulaEditor: boolean = false;

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

    this.handleSubmit = this.handleSubmit.bind(this);
    this.handleChange = this.handleChange.bind(this);
    this.openFormulaEditor = this.openFormulaEditor.bind(this);
  }

  setCellValue(id: ID, value: any) {
    this.context!.commands.setCellData({ id, value });
  }

  setCellData(id: ID, data: any) {
    this.context!.commands.setCellData({ id, ...data });
  }

  handleChange(v: any) {}

  handleSubmit(v: any) {
    if ((this.getEditor() as any) === FormulaEditor) {
      // 全部改用 SetCellData
      this.setCellData(this.props.id, v);
    } else {
      this.setCellData(this.props.id, { value: v, error: null });
    }

    if (getActivedCell(this.context!.store.getState()) === this.props.id) {
      // 如果当前还在编辑状态, 则退出 ( 此条件不可忽略, 否则会导致死循环 )
      this.handleExitEditing();
    }
  }

  getEditor() {
    const state = this.context!.store.getState();
    const cellType = getCellType(state, this.props.id);
    const cell = getCell(state, this.props.id)!;
    return state.usage === 'editor' && !cell.locked
      ? this.forceShowFormulaEditor
        ? FormulaEditor
        : !R.isNil(cell.formula) && !cell.formulaDisabled
        ? FormulaEditor
        : getEditor(cellType)!
      : FakeEditor;
  }

  openFormulaEditor() {
    this.forceShowFormulaEditor = true;
    if (fsmPred.isEditing(this.context!.store.getState().mode)) {
      // 若已在editing横式下按下=号, 则如果直接发送editing事件, state不会有变化, 公式编辑器不会显示出来
      this.forceUpdate();
      // this.context!.patchState({ isActiving: true }); // bug: 未同步状态机
    } else {
      this.context!.fsmService.send({ type: 'EDITING' }); // ok
    }
  }

  handleExitEditing = () => {
    this.forceShowFormulaEditor = false;
    this.context!.fsmService.send({ type: 'SELECT.CELL', selectedCell: this.props.id });
  };

  shouldComponentUpdate(nextProps: any, nextState: any) {
    return !equals(this.props, nextProps) || !equals(this.state, nextState);
  }

  render() {
    const { id, isActiving, readyDimensions } = this.props;

    const getState = this.context!.store.getState;
    const state = getState();

    const cell = getCell(state, id)!;
    // 在undo时, 有时会不同步
    if (!cell) return null;

    const Editor: any = this.getEditor();
    const dim = getCellDimensions(state, id);

    const newStyle = {
      ...cell.style,
      left: dim.offsetLeft,
      top: dim.offsetTop,
      width: dim.offsetWidth + 1,
      height: dim.offsetHeight + 1,
      opacity: isActiving && !readyDimensions ? 1 : 0,
      pointerEvents: isActiving ? 'all' : ('none' as any),
    };

    // 如果已经被折叠或被滚走, 则不显示
    if (newStyle.width <= 1 || newStyle.height <= 1) {
      newStyle.top = -100000;
    }

    return Editor ? (
      <div className={classnames(styles['container'], FSM_IGNORE)} style={newStyle} ref={this.ref}>
        <Editor
          isActiving={isActiving}
          getState={getState}
          formula={cell.formula}
          value={cell.value}
          onChange={this.handleChange}
          onSubmit={this.handleSubmit}
          onExitEditing={this.handleExitEditing}
          openFormulaEditor={this.openFormulaEditor}
          style={newStyle}
        />
      </div>
    ) : null;
  }
}

export default PresentCell;
