/**
 * --------------------------------------------------------------------------
 * gallery.js
 * Provide an image gallery
 * --------------------------------------------------------------------------
 */

import Carousel from 'bootstrap/js/src/carousel.js'
import EventHandler from 'bootstrap/js/src/dom/event-handler.js'
import SelectorEngine from 'bootstrap/js/src/dom/selector-engine.js'
import { defineJQueryPlugin } from 'bootstrap/js/src/util/index.js'
import Manipulator from 'bootstrap/js/src/dom/manipulator.js'

/**
 * Constants
 */

const NAME = 'gallery'
// We are extending the Boostrap Carousel so, for events to work, we must
// use the same DATA_KEY
const DATA_KEY = 'bs.carousel'
const EVENT_KEY = `.${DATA_KEY}`
const DATA_API_KEY = '.data-api'

const CLASS_NAME_CAROUSEL = 'carousel'
const CLASS_NAME_GALLERY = 'gallery'

const SELECTOR_DATA_RIDE = '[data-bs-ride="gallery"]'
const SELECTOR_INDICATORS = '.gallery-indicators'
const SELECTOR_ACTIVE = '.active'

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

const EdGELVersion = '5.1.0-rc.1'

const Default = {
  interval: false,
  keyboard: true,
  slide: false,
  pause: 'hover',
  ride: false,
  wrap: true,
  touch: true
}

// Validation done in Carousel, so not required here.
// const DefaultType = {}

/**
 * Class definition
 */

class Gallery extends Carousel {
  constructor(element, config) {
    super(element, config)

    this._indicatorsElement = SelectorEngine.findOne(SELECTOR_INDICATORS, this._element)
    this._positionIndicators()
  }

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

  static get NAME() {
    return NAME
  }

  // Overriding DATA_KEY to match Carousel's so events continue to work.
  static get DATA_KEY() {
    return DATA_KEY
  }

  static get VERSION() {
    const bsVersion = super.VERSION
    return `${bsVersion}+edgel-${EdGELVersion}`
  }

  // Private
  _configAfterMerge(config) {
    // Enforce Gallery settings on Carousel
    const enforce = {
      interval: false,
      defaultInterval: false,
      ride: false,
      keyboard: true,
      touch: true
    }

    return {
      ...config,
      ...enforce
    }
  }

  _setActiveIndicatorElement(element) {
    super._setActiveIndicatorElement(element)

    this._positionIndicators()
  }

  _positionIndicators() {
    if (!this._indicatorsElement) {
      return
    }

    const activeIndicator = SelectorEngine.findOne(SELECTOR_ACTIVE, this._indicatorsElement)

    if (activeIndicator) {
      const newLeftOffset = (this._indicatorsElement.offsetWidth / 2) - activeIndicator.offsetLeft - (activeIndicator.offsetWidth / 2)
      this._indicatorsElement.style.transform = `translate3d(${newLeftOffset}px, 0px, 0)`
    }
  }

  // Public
  cycle() {
    // Do nothing - the Gallery is not to be used as a Carousel.
  }

  // Static
  static jQueryInterface(config) {
    return this.each(function () {
      const data = Gallery.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(document, EVENT_CLICK_DATA_API, SELECTOR_DATA_RIDE, function (event) {
  const target = SelectorEngine.getElementFromSelector(this)

  if (!target || !target.classList.contains(CLASS_NAME_GALLERY) || !target.classList.contains(CLASS_NAME_CAROUSEL)) {
    return
  }

  event.preventDefault()

  const gallery = Gallery.getOrCreateInstance(target)
  const slideIndex = this.getAttribute('data-bs-slide-to')

  if (slideIndex) {
    gallery.to(slideIndex)
    return
  }

  if (Manipulator.getDataAttribute(this, 'slide') === 'next') {
    gallery.next()
    return
  }

  gallery.prev()
})

EventHandler.on(window, EVENT_LOAD_DATA_API, () => {
  const galleries = SelectorEngine.find(SELECTOR_DATA_RIDE)

  for (const gallery of galleries) {
    Gallery.getOrCreateInstance(gallery)
  }
})

/**
 * ------------------------------------------------------------------------
 * jQuery
 * ------------------------------------------------------------------------
 * add .Gallery to jQuery only if jQuery is present
 */

defineJQueryPlugin(Gallery)

export default Gallery
