import Vue from 'vue'

/**
 * Returns the prop.
 *
 * If the parent element is defined, that means the defaultTemplate has been extended, in that case
 * return the parent elements prop, if not return the current elements prop
 *
 * @param self
 * @param prop
 * @returns {*}
 */
const getComponentProp = function(self, prop) {
  return (self.$parent && self.$parent.$props && self.$parent[prop]) || self.$props[prop]
}

/**
 *
 */
class MobilePage {
  /**
   * Add the header to the div
   *
   * @param el
   * @param vnode
   * @param callback
   * @param content
   * @param closeButton
   */
  addMobileHeader(el, vnode, callback = null, content = null, closeButton = false) {
    // assign template if provided
    let baseTemplate = this.options.headerTemplate || this.mobilePageHeaderTemplate

    // extend the template to override props
    let template = Vue.extend(baseTemplate)

    template = new template({
      props: this.mobilePageHeaderTemplate.props,
      propsData: {
        closeButton: closeButton,
        title:
          (vnode.data && vnode.data.attrs && vnode.data.attrs['mobile-page-title']) ||
          this.mobilePageHeaderTemplate.props.title.default,
      },
    })

    template.$mount()

    template.$el.dataset.mobilePageHeader = true

    template.$el.classList.add('mobile-page-header')

    if (callback) {
      template.$el.addEventListener('click', callback)
    }

    template.$el.addEventListener('click', () => this.mobileClasses(el, false))

    // append
    let prevHeader = el.querySelector('[data-mobile-page-header]')

    if (prevHeader) {
      prevHeader.remove()
    }

    el.prepend(template.$el)
  }

  addMobileFooter(el, vnode, callback = null) {
    // assign template if provided
    let baseTemplate = this.options.footerTemplate || this.mobilePageFooterTemplate

    // extend the template to override props
    let template = Vue.extend(baseTemplate)

    template = new template({
      props: this.mobilePageFooterTemplate.props,
      propsData: {
        title:
          (vnode.data && vnode.data.attrs && vnode.data.attrs['mobile-page-footer']) ||
          this.mobilePageFooterTemplate.props.title.default,
      },
    })

    template.$mount()

    template.$el.dataset.mobilePageFooter = true

    template.$el.classList.add('mobile-page-footer')

    if (callback) {
      template.$el.addEventListener('click', callback)
    }

    template.$el.addEventListener('click', () => this.mobileClasses(el, false))

    // append
    let prevFooter = el.querySelector('[data-mobile-page-footer]')

    if (prevFooter) {
      prevFooter.remove()
    }

    el.append(template.$el)
  }

  /**
   * Add classes to the div and body object
   *
   * @param el
   * @param active
   */
  mobileClasses(el, active = true, classes = []) {
    let method = active ? 'add' : 'remove'

    el.classList[method]('mobile-page')
    classes.forEach(cls => {
      el.classList[method](cls)
    })
    document.querySelector('body').classList[method]('mobile-page-on')
  }

  /**
   * mobile-page directive
   *
   * @param el
   * @param binding
   * @param vnode
   */
  directiveBind(el, binding, vnode) {
    let pageActive = typeof binding.value === 'boolean' ? binding.value : (binding.value && binding.value.show) || false

    let handlers = (vnode.data && vnode.data.on) || (vnode.componentOptions && vnode.componentOptions.listeners) || {}

    this.classes = []

    if (binding.modifiers['no-padding-x'] === true) {
      this.classes.push('no-padding-x')
    }

    if (binding.modifiers['no-padding-y'] === true) {
      this.classes.push('no-padding-y')
    }

    if (pageActive) {
      this.addMobileHeader(
        el,
        vnode,
        handlers['onMobileCancel'] || null,
        binding.value.content,
        binding.modifiers.close
      )

      if (binding.modifiers['footer'] === true) {
        this.addMobileFooter(el, vnode, handlers['onMobileContinue'] || null)

        this.classes.push('has-footer')
      }

      this.mobileClasses(el, true, this.classes)
    } else {
      this.mobileClasses(el, false, this.classes)
    }
  }

  unbind(el) {
    this.mobileClasses(el, false, this.classes)
  }

  directive() {
    return {
      update: this.directiveBind.bind(this),
      unbind: this.unbind.bind(this),
    }
  }

  /**
   * Default layout Vue component
   * @type {{template: string, computed: {showResetButton(): *, computedTitle(): *, showCloseButton(): *}, props: {closeButton: {default: boolean, type: BooleanConstructor}, title: {default: string, type: StringConstructor}, resetButton: {default: boolean, type: BooleanConstructor}}}}
   */
  mobilePageHeaderTemplate = {
    props: {
      closeButton: {
        type: Boolean,
        default: false,
      },
      resetButton: {
        type: Boolean,
        default: false,
      },
      title: {
        type: String,
        default: 'Close',
      },
    },
    template: `
        <div>
          <div v-if="showCloseButton" class="back-button">
            <slot name="closeButton">x</slot>
          </div>
          <div v-else class="back-button">
            <slot name="backButton">←</slot>
          </div>
          <div class="title" :slot-scope="{title: computedTitle}">
            <slot>{{computedTitle}}</slot>
          </div>
          <div class="reset-button">
            <slot v-if="showResetButton" name="resetButton"></slot>
          </div>
        </div>
      `,
    computed: {
      showResetButton() {
        return getComponentProp(this, 'resetButton')
      },
      showCloseButton() {
        return getComponentProp(this, 'closeButton')
      },
      computedTitle() {
        return getComponentProp(this, 'title')
      },
    },
  }

  /**
   * Default layout Vue component
   * @type {{template: string, computed: {showResetButton(): *, computedTitle(): *, showCloseButton(): *}, props: {closeButton: {default: boolean, type: BooleanConstructor}, title: {default: string, type: StringConstructor}, resetButton: {default: boolean, type: BooleanConstructor}}}}
   */
  mobilePageFooterTemplate = {
    props: {
      title: {
        type: String,
        default: 'Close',
      },
    },
    template: `
        <div>
          <div class="footer-button">
            <slot>{{title}}</slot>
          </div>
        </div>
      `,
    computedTitle() {
      return getComponentProp(this, 'title')
    },
  }

  /**
   * Install the directive
   *
   * @param Vue
   * @param options
   */
  install(Vue, options) {
    this.options = Object.assign(
      {},
      {
        headerTemplate: null,
        footerTemplate: null,
      },
      options
    )
    Vue.directive('mobile-page', this.directive.apply(this))
    Vue.component('mobile-page-header-template', this.mobilePageHeaderTemplate)
    Vue.component('mobile-page-footer-template', this.mobilePageFooterTemplate)
  }
}

export default new MobilePage()
