import { EditorView, NodeView } from 'prosemirror-view';
import { Node as ProsemirrorNode } from 'prosemirror-model';

import isFunction from 'tui-code-snippet/type/isFunction';
import css from 'tui-code-snippet/domUtil/css';

import { removeNode, setAttributes } from '@/utils/dom';
import { getCustomAttrs } from '@/wysiwyg/helper/node';

import { Emitter } from '@t/event';

type GetPos = (() => number) | boolean;

type InputPos = {
  top: number;
  right: number;
};

const WRAPPER_CLASS_NAME = 'toastui-editor-ww-code-block';
const CODE_BLOCK_LANG_CLASS_NAME = 'toastui-editor-ww-code-block-language';

export class CodeBlockView implements NodeView {
  dom: HTMLElement | null = null;

  contentDOM: HTMLElement | null = null;

  private node: ProsemirrorNode;

  private view: EditorView;

  private getPos: GetPos;

  private eventEmitter: Emitter;

  private input: HTMLElement | null = null;

  constructor(node: ProsemirrorNode, view: EditorView, getPos: GetPos, eventEmitter: Emitter) {
    this.node = node;
    this.view = view;
    this.getPos = getPos;
    this.eventEmitter = eventEmitter;

    this.createElement();
    this.bindDOMEvent();
    this.bindEvent();
  }

  private createElement() {
    const { language } = this.node.attrs;
    const wrapper = document.createElement('div');

    wrapper.setAttribute('data-language', language || 'text');
    wrapper.className = WRAPPER_CLASS_NAME;

    const pre = this.createCodeBlockElement();
    const code = pre.firstChild as HTMLElement;

    wrapper.appendChild(pre);

    this.dom = wrapper;
    this.contentDOM = code;
  }

  private createCodeBlockElement() {
    const pre = document.createElement('pre');
    const code = document.createElement('code');
    const { language } = this.node.attrs;
    const attrs = getCustomAttrs(this.node.attrs);

    if (language) {
      code.setAttribute('data-language', language);
    }
    setAttributes(attrs, pre);

    pre.appendChild(code);

    return pre;
  }

  private createLanguageEditor({ top, right }: InputPos) {
    const wrapper = document.createElement('span');

    wrapper.className = CODE_BLOCK_LANG_CLASS_NAME;

    const input = document.createElement('input');

    input.type = 'text';
    input.value = this.node.attrs.language;

    wrapper.appendChild(input);
    document.querySelector<HTMLElement>('.toastui-editor.ww-mode')!.appendChild(wrapper);
    const wrpperWidth = wrapper.clientWidth;

    css(wrapper, {
      top: `${top + 10}px`,
      left: `${right - wrpperWidth - 10}px`,
      width: `${wrpperWidth}px`,
    });

    this.input = input;
    this.input.addEventListener('blur', () => this.changeLanguage());
    this.input.addEventListener('keydown', this.handleKeydown);

    setTimeout(() => this.input!.focus());
  }

  private bindDOMEvent() {
    if (this.dom) {
      this.dom.addEventListener('click', this.handleMousedown);
    }
  }

  private bindEvent() {
    this.eventEmitter.listen('scroll', () => {
      if (this.input) 

    });
  }

  private handleMousedown = (ev: MouseEvent) => {
    const target = ev.target as HTMLElement;
    const style = getComputedStyle(target, ':after');

    // judge to click pseudo element with background image for IE11
    if (style.backgroundImage !== 'none' && isFunction(this.getPos)) {
      const { top, right } = this.view.coordsAtPos(this.getPos());

      this.createLanguageEditor({ top, right });
    }
  };

  private handleKeydown = (ev: KeyboardEvent) => {
    if (ev.key === 'Enter' && this.input) {
      ev.preventDefault();
      this.changeLanguage();
    }
  };

  private changeLanguage() {
    if (this.input && isFunction(this.getPos)) {
      const { value } = this.input as HTMLInputElement;

      this.reset();

      const pos = this.getPos();
      const { tr } = this.view.state;

      tr.setNodeMarkup(pos, null, { language: value });
      this.view.dispatch(tr);
    }
  }

  private reset() {
    if (this.input?.parentElement) {
      const parent = this.input.parentElement;

      this.input = null;
      removeNode(parent);
    }
  }

  stopEvent() {
    return true;
  }

  update(node: ProsemirrorNode) {
    if (!node.sameMarkup(this.node)) {
      return false;
    }

    this.node = node;

    return true;
  }

  destroy() {
    this.reset();

    if (this.dom) {
      this.dom.removeEventListener('click', this.handleMousedown);
    }
  }
}

{
        this.reset();
      }