/**
 * --------------------------------------------------------------------------
 * overlay.js
 * Provide overlays to iframes according to cookie policy.
 *
 * Use data-bs-src attribute instead of src attribute to prevent iframe
 * loading until permission granted.
 *   data-bs-src="https://player.vimeo.com/video/48643799"
 * Configure the link with the data-bs-link-url and data-bs-link-text
 * attributes
 *   data-bs-link-url="https://www.ed.ac.uk/"
 *   data-bs-link-text="Custom link"
 * --------------------------------------------------------------------------
 */

import SelectorEngine from 'bootstrap/js/src/dom/selector-engine.js'
import EventHandler from 'bootstrap/js/src/dom/event-handler.js'
import TemplateFactory from 'bootstrap/js/src/util/template-factory.js'
import EdGELBaseComponent from './edgel-base-component.js'
import { escapeHtml } from './helpers.js'

import template from './templates/uoe-overlay.js'

/**
 * Constants
 */

const NAME = 'overlay'
const DATA_KEY = 'uoe.overlay'
const EVENT_KEY = `.${DATA_KEY}`
const DATA_API_KEY = '.data-api'

const EVENT_LOAD_DATA_API = `load${EVENT_KEY}${DATA_API_KEY}`
const EVENT_CLICK = `click${EVENT_KEY}`

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

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

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

/**
 * Class definition
 */

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

    this._templateFactory = null
    this._templateConfig = {
      sanitize: false,
      html: true,
      template,
      content: {
        [TPL_SELECTOR_LINK]: this._renderLink
      }
    }

    this._addOverlay()
  }

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

  static get DefaultType() {
    return DefaultType
  }

  static get NAME() {
    return NAME
  }

  static get DATA_KEY() {
    return DATA_KEY
  }

  // Private
  _configAfterMerge(config) {
    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) {
    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}"`)
    }
  }

  _getTemplateFactory(newContent) {
    if (this._templateFactory) {
      this._templateFactory.changeContent(newContent)
    } else {
      const content = {
        ...newContent,
        ...this._templateConfig.content
      }
      this._templateFactory = new TemplateFactory({
        ...this._templateConfig,
        content
      })
    }

    return this._templateFactory
  }

  _renderLink(context) {
    const { linkUrl, linkText } = context._config.content

    if (linkUrl) {
      return `<a class="cookie-link" href="${encodeURI(linkUrl)}">${escapeHtml(linkText)}</a>`
    }
  }

  _addOverlay() {
    const cookieOverlay = document.createElement('div')
    cookieOverlay.append(this._getTemplateFactory(this._config).toHtml())

    // If this isn't wrapped in a ratio div, we will explicitly set the height and width.
    const parentClasses = this._element.parentElement.classList
    if (!parentClasses.contains('ratio') && !parentClasses.contains('ratio-text')) {
      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)

      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 = ''
    })
  }
}

/**
 * Data API implementation
 */

EventHandler.on(window, EVENT_LOAD_DATA_API, () => {
  const overlays = SelectorEngine.find(SELECTOR_OVERLAY)

  for (const overlay of overlays) {
    Overlay.getOrCreateInstance(overlay)
  }
})

export default Overlay
