import {
  DefaultDOMElement,
  FontAwesomeIcon as Icon,
  Tool
} from 'substance'

class CommentBubble extends Tool {
  render ($$) {
    if (!this.canCreateComment()) return $$('div')

    const title = 'Create a new comment'

    const iconPlus = $$(Icon, { icon: 'fa-plus' })
        .addClass('sc-comment-icon-plus')

    const iconBubble = $$(Icon, { icon: 'fa-comment-o' })
        .addClass('sc-comment-icon-bubble')

    const bubble = $$('div')
      .attr('title', title)
      .addClass('sc-overlay-bubble')
      .addClass('sc-overlay-bubble-hidden')
      .on('click', this.createComment)
      .append(iconBubble)
      .append(iconPlus)

    return bubble
  }

  // reset bubble position on window resize
  // only works on the horizontal level, as the vertical position gets
  // calculated relative to the overlay container, which gets positioned
  // wrong on resize (substance bug -- TODO)
  didMount () {
    this.context.editorSession.onUpdate('', this.position, this)
    this.position()
    DefaultDOMElement.getBrowserWindow().on('resize', this.didUpdate, this)
  }

  didUpdate () {
    this.position()
  }

  dispose () {
    DefaultDOMElement.getBrowserWindow().off(this)
  }

  position () {
    if (this.el.getChildCount() === 0) return
    this.setBubblePosition()
  }

  setBubblePosition () {
    // without this check, the editor will break on first load
    const surface = this.getSurface()
    if (!surface) return

    setTimeout(() => { // read comment below
      let documentElement = document.querySelector('.se-content')
      let overlayContainer = document.querySelector('.sc-overlay')
      let fix = 15
      if (parseInt(overlayContainer.offsetLeft) === 0) {
        const minEditorContentPanelChildren = document.getElementById('notes-editor-content-panel').children
        const temp = minEditorContentPanelChildren[0].children
        documentElement = temp[0]
        const children = temp[0].children
        overlayContainer = children[1]
      }

      const documentElementWidth = documentElement.offsetWidth / 1.85
      const overlayContainerLeft = overlayContainer.offsetLeft
      const left = documentElementWidth - overlayContainerLeft - fix

      // unhide it first, as the bubble has no height otherwise
      this.el.removeClass('sc-overlay-bubble-hidden')

      let wsel = window.getSelection()
      let wrange = wsel.getRangeAt(0)
      const hints = wrange.getBoundingClientRect()
      const selectionHeight = hints.height
      const bubbleHeight = this.el.getHeight()
      const cheat = 3
      const moveUp = (selectionHeight / 2) + (bubbleHeight / 2) + cheat
      const top = '-' + moveUp + 'px'

      this.el.css('left', left)
      this.el.css('top', top)
    })

    /*
      There is a race condition with overlayContainer's position.
      If it gets rendered fast enough, this is fine.
      Otherwise, the overlayContainerLeft variable won't have been updated by
      substance for us to get the correct value.
      There is no event letting us know that this has been updated,
      and it's probably not worth creating a listener.
    */
  }

  getCommentState () {
    const { commandManager } = this.context
    const commandStates = commandManager.getCommandStates()
    return commandStates.comment
  }

  getEditorSession () {
    return this.context.editorSession
  }

  getMode () {
    const commentState = this.getCommentState()
    return commentState.mode
  }

  getProvider () {
    return this.context.commentsProvider
  }

  getSelection () {
    const editorSession = this.getEditorSession()
    return editorSession.getSelection()
  }

  // TODO -- get from provider
  getSurface () {
    const surfaceManager = this.context.surfaceManager
    return surfaceManager.getFocusedSurface()
  }

  isSelectionLargerThanComments () {
    const provider = this.getProvider()
    return provider.isSelectionLargerThanComments()
  }

  canCreateComment () {
    const mode = this.getMode()

    if (mode === 'create') return true
    if (!this.isSelectionLargerThanComments()) return false

    return true
  }

  // TODO -- move to provider
  createComment () {
    if (!this.canCreateComment()) return

    const provider = this.getProvider()
    const selection = this.getSelection()
    const surface = this.getSurface()

    const newNode = {
      selection: selection,
      type: 'comment',
      path: selection.path,
      start: selection.start,
      end: selection.end
    }

    surface.editorSession.transaction((tx, args) => {
      const annotation = tx.create(newNode)
      provider.focusTextArea(annotation.id)
    })
  }
}

export default CommentBubble