/**
 * --------------------------------------------------------------------------
 * overlay.js
 * Provide overlays to iframes according to cookie policy.
 *
 * Use data-uoe-cookie-src attribute instead of src attribute to prevent
 * loading until permission granted.
 * --------------------------------------------------------------------------
 */

import * as Nunjucks from 'nunjucks'
import {
  onDOMContentLoaded,
  typeCheckConfig
} from 'bootstrap/js/src/util'
import BaseComponent from 'bootstrap/js/src/base-component'
import SelectorEngine from 'bootstrap/js/src/dom/selector-engine'
import Data from 'bootstrap/js/src/dom/data'
import EventHandler from 'bootstrap/js/src/dom/event-handler'
import Manipulator from 'bootstrap/js/src/dom/manipulator'

/**
 * ------------------------------------------------------------------------
 * Constants
 * ------------------------------------------------------------------------
 */

const NAME = 'overlay'
const DATA_KEY = 'uoe.overlay'
const EVENT_KEY = `.${DATA_KEY}`
const EVENT_CLICK = `click${EVENT_KEY}`

const SELECTOR_OVERLAY = 'iframe[data-bs-src]'
const SELECTOR_BUTTONS = 'button.cookie-btn-overlay'

const Default = {
  linkUrl: '',
  linkText: 'Further information'
}

const DefaultType = {
  linkUrl: 'string',
  linkText: 'string'
}

/**
 * ------------------------------------------------------------------------
 * Class Definition
 * ------------------------------------------------------------------------
 */

class Overlay extends BaseComponent {
  constructor(element) {
    super(element)

    this._config = this._getConfig()

    this._addOverlay()
  }

  // Getters

  static get Default() {
    return Default
  }

  static get DefaultType() {
    return DefaultType
  }

  static get DATA_KEY() {
    return DATA_KEY
  }

  // Private

  _getConfig(config) {
    config = {
      ...this.constructor.Default,
      ...Manipulator.getDataAttributes(this._element),
      ...config
    }

    typeCheckConfig(NAME, config, this.constructor.DefaultType)

    this._validateUrl(config.src)
    if (config.linkUrl) {
      this._validateUrl(config.linkUrl)
    }

    if (config.linkUrl && !config.linkText.trim()) {
      throw new TypeError('Empty custom link text')
    }

    return config
  }

  _validateUrl(testUrl) {
    // Validate URL
    let url
    try {
      url = new URL(testUrl)
    } catch {
      throw new TypeError(`Invalid URL provided in "${testUrl}"`)
    }

    if (url.protocol !== 'https:') {
      throw new TypeError(`Only https protocol accepted for "${testUrl}"`)
    }
  }

  _addOverlay() {
    const cookieOverlay = document.createElement('div')
    const style = window.getComputedStyle(this._element)
    let height = this._element.offsetHeight

    let borderWidth = style.getPropertyValue('border-top-width')
    height -= (borderWidth.includes('px') ? borderWidth.slice(0, -2) : 0)

    borderWidth = style.getPropertyValue('border-bottom-width')
    height -= (borderWidth.includes('px') ? borderWidth.slice(0, -2) : 0)

    const overlayData = {}
    if (this._config.linkUrl) {
      overlayData.link = {
        label: this._config.linkText,
        url: this._config.linkUrl
      }
    }

    cookieOverlay.innerHTML = Nunjucks.render('uoe-overlay.njk', overlayData)
    cookieOverlay.firstChild.setAttribute('style', 'width:' + this._element.offsetWidth.toString() + 'px;height:' + height.toString() + 'px' /* style.getPropertyValue('border-top-width') */)
    this._overlay = cookieOverlay.firstChild
    this._element.parentNode.insertBefore(this._overlay, this._element)
    this._element.style.display = 'none'

    EventHandler.on(this._overlay, EVENT_CLICK, SELECTOR_BUTTONS, event => {
      event.preventDefault()
      event.stopPropagation()

      this._element.setAttribute('src', this._config.src)
      this._overlay.style.display = 'none'
      this._element.style.display = ''
    })
  }

  // Static
  static overlayInterface(element, config) {
    let data = Data.getData(element, DATA_KEY)
    const _config = typeof config === 'object' ? config : null

    if (!data) {
      data = new Overlay(element, _config)
    }

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

      data[config]()
    }
  }

  static addOverlays() {
    for (const overlay of SelectorEngine.find(SELECTOR_OVERLAY)) {
      Overlay.overlayInterface(overlay)
    }
  }
}

onDOMContentLoaded(Overlay.addOverlays)

export default Overlay
