/* global Element */
var yo = require('yo-yo')
var css = require('./styles/tooltip-styles')
var modal = require('./modal-dialog-custom')

/**
 * Open a tooltip
 * @param {string} tooltipText The text shown by the tooltip
 * @param {function} [action] Returns An HTMLElement to display for action
 */
module.exports = function addTooltip (tooltipText, action, opts) {
  action = action || function () { return yo`<div></div>` }
  const t = new Toaster()
  return t.render(tooltipText, action(t), opts)
}

class Toaster {
  hide () {
    if (this.id) clearTimeout(this.id)
    setTimeout(() => {
      // remove from body after the animation is finished
      if (this.tooltip.parentElement) this.tooltip.parentElement.removeChild(this.tooltip)
    }, 2000)
    animation(this.tooltip, css.animateTop.className)
  }

  /**
  * Force resolve the promise to close
  * the toaster ignoring timeout
  */
  forceResolve () {
    if (this.id) clearTimeout(this.id)
    if (this.resolveFn) this.resolveFn()
  }

  render (tooltipText, actionElement, opts) {
    opts = defaultOptions(opts)
    let canShorten = true
    if (tooltipText instanceof Element) {
      canShorten = false
    } else {
      if (typeof tooltipText === 'object') {
        if (tooltipText.message) {
          tooltipText = tooltipText.message
        } else {
          try {
            tooltipText = JSON.stringify(tooltipText)
          } catch (e) {
          }
        }
      }
    }

    return new Promise((resolve, reject) => {
      const shortTooltipText = (canShorten && tooltipText.length > 201) ? tooltipText.substring(0, 200) + '...' : tooltipText
      this.resolveFn = resolve

      function showFullMessage () {
        modal.alert(tooltipText)
      }

      function closeTheToaster (self) {
        self.hide()
        over()
        resolve()
      }
      const button = tooltipText.length > 201 ? yo`
      <button class="btn btn-secondary btn-sm mx-3" style="white-space: nowrap;" onclick=${() => showFullMessage()}>Show full message</button>
      ` : ''

      this.tooltip = yo`
        <div data-shared="tooltipPopup" class="${css.tooltip} alert alert-info p-2"  onmouseenter=${() => { over() }} onmouseleave=${() => { out() }}>
          <span class="px-2">
            ${shortTooltipText}
            ${button}
            ${actionElement}
          </span>
          <span style="align-self: baseline;">
            <button data-id="tooltipCloseButton" class="fas fa-times btn-info mx-1 p-0" onclick=${() => closeTheToaster(this)}></button>
          </span>
        </div>`
      const timeOut = () => {
        return setTimeout(() => {
          if (this.id) {
            this.hide()
            resolve()
          }
        }, opts.time)
      }
      const over = () => {
        if (this.id) {
          clearTimeout(this.id)
          this.id = null
        }
      }
      const out = () => {
        if (!this.id) this.id = timeOut()
      }
      this.id = timeOut()
      document.body.appendChild(this.tooltip)
      animation(this.tooltip, css.animateBottom.className)
    })
  }
}

const defaultOptions = (opts) => {
  opts = opts || {}
  return {
    time: opts.time || 7000
  }
}

const animation = (tooltip, anim) => {
  tooltip.classList.remove(css.animateTop.className)
  tooltip.classList.remove(css.animateBottom.className)
  // eslint-disable-next-line
  void tooltip.offsetWidth // trick for restarting the animation
  tooltip.classList.add(anim)
}
