import {
  ContentState,
  convertFromHTML,
  Editor,
  EditorState,
  getDefaultKeyBinding,
  RichUtils,
} from "draft-js";
import { stateToHTML } from "draft-js-export-html";
import React, { Component } from "react";
import InlineControls from "./InlineControls";
import style from "./style";

class RichEditor extends Component {
  constructor(props) {
    super(props);

    const blocksFromHTML = convertFromHTML(props.content);

    const state = ContentState.createFromBlockArray(
      blocksFromHTML.contentBlocks,
      blocksFromHTML.entityMap
    );

    this.state = {
      editorState: EditorState.createWithContent(state),
      editorContentHtml: props.content,
      index: "",
      isHighlighted: false,
    };

    this.focus = () => this.refs.editor.focus();
    this.blur = () => this.refs.editor.blur();
    this.onChange = this.onChange.bind(this);

    this.handleKeyCommand = this.handleKeyCommand.bind(this);
    this.mapKeyToEditorCommand = this.mapKeyToEditorCommand.bind(this);
    this.toggleInlineStyle = this.toggleInlineStyle.bind(this);
    this.onFocus = this.onFocus.bind(this);
    this.onBlur = this.onBlur.bind(this);
  }

  handleKeyCommand(command, editorState) {
    const newState = RichUtils.handleKeyCommand(editorState, command);
    if (newState) {
      this.onChange(newState);
      return true;
    }
    return false;
  }

  mapKeyToEditorCommand(e) {
    if (e.keyCode === 9 /* TAB */) {
      const newEditorState = RichUtils.onTab(
        e,
        this.state.editorState,
        4 /* maxDepth */
      );
      if (newEditorState !== this.state.editorState) {
        this.onChange(newEditorState);
      }
      return;
    }
    return getDefaultKeyBinding(e);
  }

  toggleInlineStyle(inlineStyle) {
    console.log(inlineStyle);

    this.onChange(
      RichUtils.toggleInlineStyle(this.state.editorState, inlineStyle),
      () => {
        clearTimeout(this.timer);
        this.focus();
      },
      inlineStyle
    );
  }

  onFocus(e) {
    this.props.setIsEditing(true);
    this.props.setCanDrag(false);
    this.props.changeState(this.props.settings.id, "active");
  }

  onBlur() {
    const { setIsEditing } = this.props;

    this.timer = setTimeout(() => {
      setIsEditing(false);
      this.props.setCanDrag(true);
      this.setState({ selectedText: false });
    }, 200);
  }

  onChange(editorState, callbackFn = () => false, inlineStyle) {
    const {
      index,
      editorChange,
      settings,
      updateComponentSettings,
    } = this.props;

    // Get Selected Text;
    const selectionState = editorState.getSelection();
    const anchorKey = selectionState.getAnchorKey();
    const currentContent = editorState.getCurrentContent();
    const currentContentBlock = currentContent.getBlockForKey(anchorKey);
    const start = selectionState.getStartOffset();
    const end = selectionState.getEndOffset();
    const selectedText = currentContentBlock.getText().slice(start, end);

    const editorContentHtml = stateToHTML(editorState.getCurrentContent());

    this.setState(
      {
        editorState,
        editorContentHtml,
        index: this.index,
        selectedText,
      },
      () => callbackFn()
    );

    const event = {
      target: {
        value: stateToHTML(editorState.getCurrentContent()),
      },
    };

    if (this.props.hasOwnProperty("editorChange"))
      editorChange(index, event, "html");
    this.props.changeState(this.props.settings.id, "active");

    // update database
    window.clearTimeout(this.doSave);
    this.doSave = window.setTimeout(() => {
      const updatedSettings = {
        ...settings,
        html: editorContentHtml,
      };

      updateComponentSettings(settings.id, updatedSettings, true, false);
    }, 500);
  }

  render() {
    const { pageContent, isEditing, position, buttonList } = this.props;
    const { editorState, selectedText } = this.state;

    // are we in the middle of a drag?  if so, make the editor read only
    const isDragging = pageContent.filter(
      (content) => content.type === "Cursor"
    ).length;

    return (
      <div
        style={{ position: "relative", zIndex: 2 }}
        onDoubleClick={(e) => e.stopPropagation()}
        onClick={(e) => {
          e.stopPropagation();
          this.props.changeState(this.props.settings.id, "active");
        }}
      >
        {selectedText && isEditing ? (
          <InlineStyleControls
            style={style.inlineStyleToolbar}
            editorState={editorState}
            onToggle={this.toggleInlineStyle}
            position={position || "top"}
            buttonList={buttonList}
          />
        ) : null}

        <Editor
          editorState={editorState}
          handleKeyCommand={this.handleKeyCommand}
          keyBindingFn={this.mapKeyToEditorCommand}
          onChange={this.onChange}
          onFocus={this.onFocus}
          onBlur={this.onBlur}
          onKeyUp={this.onKeyUp}
          ref="editor"
          spellCheck
          index={this.props.index}
          readOnly={isDragging || this.props.disabled}
        />
      </div>
    );
  }
}

const InlineStyleControls = (props) => {
  const { position, buttonList, editorState, onToggle } = props;
  const currentStyle = editorState.getCurrentInlineStyle();
  return (
    <InlineControls
      onToggle={onToggle}
      currentStyle={currentStyle}
      position={position}
      buttonList={buttonList}
    />
  );
};

export default React.memo(RichEditor);
