import { Plugin, PluginKey } from "prosemirror-state";

class Menu {
  constructor({ options, editorView }) {
    this.options = {
      ...{
        resizeObserver: true,
        element: null,
        onUpdate: () => false,
      },
      ...options,
    };
    this.preventHide = false;
    this.editorView = editorView;
    this.isActive = false;
    this.top = 0;

    // the mousedown event is fired before blur so we can prevent it
    this.mousedownHandler = this.handleClick.bind(this);
    this.options.element.addEventListener("mousedown", this.mousedownHandler, { capture: true });

    this.focusHandler = ({ view }) => {
      console.log('focusHandler ');
      this.update(view);
    };
    this.options.editor.on("focus", this.focusHandler);

    this.blurHandler = ({ event }) => {
      if (this.preventHide) {
        this.preventHide = false;
        return;
      }

      this.hide(event);
    };
    this.options.editor.on("blur", this.blurHandler);

    // sometimes we have to update the position
    // because of a loaded images for example
    if (this.options.resizeObserver && window.ResizeObserver) {
      this.resizeObserver = new ResizeObserver(() => {
        if (this.isActive) {
            console.log('resize')
          this.update(this.editorView);
        }
      });
      this.resizeObserver.observe(this.editorView.dom);
    }
  }

  handleClick() {
    this.preventHide = true;
  }

  update(view, lastState) {

    console.log("1");
    const { state } = view;

    // Don't do anything if the document/selection didn't change
    if (lastState && lastState.doc.eq(state.doc) && lastState.selection.eq(state.selection)) {
      console.log("1.1");
      return;
    }

    console.log('state.selection.empty', state.selection.empty)
    if (!state.selection.empty) {
      console.log("1.2");

      this.hide();
      return;
    }

    const currentDom = view.domAtPos(state.selection.anchor);
    console.log("1.3 inn", currentDom.node.innerHTML);
    console.log("1.3 dom", view.dom);

    const isActive = currentDom.node.innerHTML === "<br>"
      && currentDom.node.tagName === "P"
      && currentDom.node.parentNode === view.dom;

    if (!isActive) {
      console.log("1.4");
      this.hide();
      return;
    }

    const parent = this.options.element.offsetParent;

    console.log("1.5");
    if (!parent) {
      this.hide();
      return;
    }

    console.log("1.6");
    const editorBoundings = parent.getBoundingClientRect();
    const cursorBoundings = view.coordsAtPos(state.selection.anchor);
    const top = cursorBoundings.top - editorBoundings.top;

    this.isActive = true;
    this.top = top;

    console.log("2");
    this.sendUpdate();
  }

  sendUpdate() {
    console.log("3");
    console.log({
      isActive: this.isActive,
      top: this.top,
    });
    this.options.onUpdate({
      isActive: this.isActive,
      top: this.top,
    });
  }

  hide(event) {
    if (event
      && event.relatedTarget
      && this.options.element.parentNode
      && this.options.element.parentNode.contains(event.relatedTarget)
    ) {
      return;
    }

    this.isActive = false;
    this.sendUpdate();
  }

  destroy() {
    this.options.element.removeEventListener("mousedown", this.mousedownHandler);

    if (this.resizeObserver) {
      this.resizeObserver.unobserve(this.editorView.dom);
    }

    this.options.editor.off("focus", this.focusHandler);
    this.options.editor.off("blur", this.blurHandler);
  }
}

export default function (options) {
  return new Plugin({
    key: new PluginKey("floating_menu"),
    view(editorView) {
      return new Menu({ editorView, options });
    },
  });
}
