/**
 * --------------------------------------------------------------------------
 * social.js
 * Provide social media buttons
 * --------------------------------------------------------------------------
 */

import {
  defineJQueryPlugin
} from 'bootstrap/js/src/util/index.js'
import SelectorEngine from 'bootstrap/js/src/dom/selector-engine.js'
import EventHandler from 'bootstrap/js/src/dom/event-handler.js'
import Data from 'bootstrap/js/src/dom/data.js'
import EdGELBaseComponent from './edgel-base-component.js'

/**
 * Constants
 */

const NAME = 'social'
const DATA_KEY = 'uoe.social'
const EVENT_KEY = `.${DATA_KEY}`
const DATA_API_KEY = '.data-api'
const EVENT_CLICK_DATA_API = `click${EVENT_KEY}${DATA_API_KEY}`
const EVENT_LOAD_DATA_API = `load${EVENT_KEY}${DATA_API_KEY}`

const CLASS_NAME_SOCIAL_BUTTONS = 'social'
const SELECTOR_SOCIAL = 'div[data-provide="uoe-social"]'
const SELECTOR_BUTTON = 'a.btn-social'
const SELECTOR_URL = 'meta[property="og:url"]'
const SELECTOR_TITLE = 'meta[property="og:title"]'

const SOCIAL_BUTTONS = {
  facebook: {
    name: 'Facebook',
    svg: '<svg width="46px" height="46px" viewBox="0 0 46 46"><rect class="social-bg-facebook" rx="4" ry="4" width="46" height="46"/><path class="social-fg-facebook" d="M31.3,46V27.8h5.9l0.9-6.9h-6.8v-4.4c0-2,0.6-3.3,3.4-3.3l3.6,0V7.1c-0.6-0.1-2.8-0.3-5.3-0.3c-5.2,0-8.8,3.2-8.8,9.1V21h-5.9v6.9h5.9V46H31.3z"/></svg>',
    url: 'https://www.facebook.com/sharer/sharer.php?u=~URL~',
    label: 'Share this content on Facebook.',
    popupWidth: 550,
    popupHeight: 285,
    sort: 1
  },
  twitter: {
    name: 'Twitter',
    svg: '<svg width="46px" height="46px" viewBox="0 0 46 46"><rect class="social-bg-twitter" rx="4" ry="4" width="46" height="46"/> <path class="social-fg-twitter" d="M40,13c-1.2,0.5-2.5,0.9-3.8,1.1c1.4-0.8,2.4-2.1,2.9-3.7c-1.3,0.8-2.7,1.3-4.3,1.6 c-1.2-1.3-3-2.1-4.9-2.1c-3.7,0-6.7,3-6.7,6.7c0,0.5,0.1,1,0.2,1.5c-5.6-0.3-10.5-2.9-13.8-7c-0.6,1-0.9,2.1-0.9,3.4c0,2.3,1.2,4.4,3,5.6c-1.1,0-2.1-0.3-3-0.8v0.1c0,3.2,2.3,6,5.4,6.6c-0.6,0.2-1.2,0.2-1.8,0.2c-0.4,0-0.9,0-1.3-0.1c0.9,2.7,3.3,4.6,6.3,4.7c-2.3,1.8-5.2,2.9-8.3,2.9c-0.5,0-1.1,0-1.6-0.1c3,1.9,6.5,3,10.3,3c12.3,0,19.1-10.2,19.1-19.1c0-0.3,0-0.6,0-0.9C38,15.5,39.1,14.3,40,13z"/></svg>',
    url: 'https://twitter.com/share?url=~URL~&text=~TITLE~',
    label: 'Share this content on Twitter.',
    popupWidth: 550,
    popupHeight: 269,
    sort: 2
  },
  linkedin: {
    name: 'LinkedIN',
    svg: '<svg width="46px" height="46px" viewBox="0 0 46 46"><rect class="social-bg-linkedin" rx="4" ry="4" width="46" height="46"/><path class="social-fg-linkedin" d="M6.9,17.4h6.9v22.2H6.9V17.4zM10.3,6.4c2.2,0,4,1.8,4,4c0,2.2-1.8,4-4,4c-2.2,0-4-1.8-4-4C6.3,8.2,8.1,6.4,10.3,6.4"/><path class="social-fg-linkedin" d="M18.1,17.4h6.6v3h0.1c0.9-1.7,3.2-3.6,6.5-3.6c7,0,8.3,4.6,8.3,10.6v12.2h-6.9V28.8c0-2.6-0.1-5.9-3.6-5.9c-3.6,0-4.1,2.8-4.1,5.7v11h-6.9V17.4z"/></svg>',
    url: 'http://www.linkedin.com/shareArticle?&mini=true&url=~URL~&title=~TITLE~',
    label: 'Share this content on LinkedIn.',
    popupWidth: 550,
    popupHeight: 269,
    sort: 3
  },
  email: {
    name: 'Email',
    svg: '<svg width="46px" height="46px" viewBox="0 0 46 46"><rect class="social-bg-email" rx="4" ry="4" width="46" height="46"/><path class="social-fg-email" d="M34.8,11.5H11.2c-2.2,0-3.9,1.8-3.9,3.9v15.7c0,2.2,1.8,3.9,3.9,3.9h23.6c2.2,0,3.9-1.8,3.9-3.9V15.1C38.7,13,37,11.2,34.8,11.2zM11.2,13.2h23.6c1.1,0,2,0.9,2,2v1.1l-13.8,9.2l-13.8-9.2v-1.1C9.2,14.1,10.1,13.2,11.2,13.2zM34.8,32.8H11.2c-1.1,0-2-0.9-2-2V17.4L23,26.5l13.8-9.2v13.5C36.8,31.9,35.9,32.8,34.8,32.8z"/></svg>',
    url: 'mailto:?subject=~TITLE~&body=~URL~',
    label: 'Email this content.',
    sort: 4
  }
}

const Default = {
  facebook: false,
  twitter: false,
  linkedin: false,
  email: false,
  heading: 'Share'
}

const DefaultType = {
  facebook: 'boolean',
  twitter: 'boolean',
  linkedin: 'boolean',
  email: 'boolean',
  heading: 'string'
}

/**
 * Class definition
 */

class Social extends EdGELBaseComponent {
  constructor(element, config) {
    super(element, config)

    if (this._element.tagName !== 'DIV') {
      // eslint-disable-next-line no-console
      console.error('Invalid EdGEL markup for social buttons.')
      return
    }

    // Get OGP values from the META tags.
    this._pageUrl = SelectorEngine.findOne(SELECTOR_URL, document.head).content.trim()
    this._pageTitle = SelectorEngine.findOne(SELECTOR_TITLE, document.head).content.trim()

    if (!this._pageUrl) {
      // eslint-disable-next-line no-console
      console.error('Missing og:url META tag')
      return
    }

    if (!this._pageTitle) {
      // eslint-disable-next-line no-console
      console.error('Missing og:title META tag')
      return
    }

    this._addButtons()
    this._addEventListeners()
  }

  // Getters
  static get Default() {
    return Default
  }

  static get DefaultType() {
    return DefaultType
  }

  static get NAME() {
    return NAME
  }

  // Private
  _configAfterMerge(config) {
    for (const [key, value] of Object.entries(DefaultType)) {
      if (value === 'boolean') {
        config[key] = Boolean(config[key]) // Coerce string values
      }
    }

    return config
  }

  _popupPosition(button) {
    const height = SOCIAL_BUTTONS[button].popupHeight
    const width = SOCIAL_BUTTONS[button].popupWidth
    const top = window.screenY + (window.innerHeight / 2) - (height / 2)
    const left = window.screenX + (window.innerWidth / 2) - (width / 2)

    return {
      height, width, top, left
    }
  }

  _addButtons() {
    const buttons = []
    for (const key of Object.getOwnPropertyNames(SOCIAL_BUTTONS)) {
      if (this._config[key]) {
        SOCIAL_BUTTONS[key].key = key
        buttons.push(SOCIAL_BUTTONS[key])
      }
    }

    if (!buttons.length) {
      return
    }

    buttons.sort((a, b) => a.sort - b.sort)

    const heading = document.createElement('h2')
    heading.textContent = this._config.heading
    this._element.innerHTML = ''
    this._element.append(heading)

    const ul = document.createElement('ul')
    ul.className = CLASS_NAME_SOCIAL_BUTTONS
    this._element.append(ul)

    for (const button of buttons) {
      const li = document.createElement('li')
      const a = document.createElement('a')
      const url = button.url
        .replace('~TITLE~', encodeURIComponent(this._pageTitle))
        .replace('~URL~', encodeURIComponent(this._pageUrl))

      a.className = 'btn btn-social'
      a.innerHTML = button.svg
      a.setAttribute('aria-label', button.label)
      a.setAttribute('href', url)

      if (button.popupWidth) {
        a.setAttribute('role', 'button')
      }

      if (button.url.startsWith('http')) {
        a.setAttribute('target', '_blank')
      }

      ul.append(li)
      li.append(a)

      Data.set(a, DATA_KEY, button.key)
    }
  }

  _addEventListeners() {
    for (const key of Object.getOwnPropertyNames(SOCIAL_BUTTONS)) {
      if ('popupWidth' in SOCIAL_BUTTONS[key]) {
        EventHandler.on(this._element, EVENT_CLICK_DATA_API, SELECTOR_BUTTON, event => {
          const key = Data.get(event.delegateTarget, DATA_KEY)
          const pos = this._popupPosition(key)
          if (!pos.height) {
            return
          }

          event.preventDefault()
          event.stopPropagation()

          const features = `width=${pos.width},height=${pos.height},resizable=yes,top=${pos.top},left=${pos.left}`
          window.open(event.delegateTarget.getAttribute('href'), SOCIAL_BUTTONS[key].name, features)
        })
      }
    }
  }

  // Static
  static jQueryInterface(config) {
    return this.each(function () {
      const data = Social.getOrCreateInstance(this, config)

      if (typeof config === 'number') {
        data.to(config)
        return
      }

      if (typeof config === 'string') {
        if (data[config] === undefined || config.startsWith('_') || config === 'constructor') {
          throw new TypeError(`No method named "${config}"`)
        }

        data[config]()
      }
    })
  }
}

/**
 * Data API implementation
 */
EventHandler.on(window, EVENT_LOAD_DATA_API, () => {
  const socials = SelectorEngine.find(SELECTOR_SOCIAL)

  for (const social of socials) {
    Social.getOrCreateInstance(social)
  }
})

/**
 * jQuery
 */

defineJQueryPlugin(Social)

export default Social
