import { gsap } from 'gsap'
import { clamp, each } from 'lodash'
import { mapGetters, mapActions } from 'vuex'

export default {
  data: () => ({
    scroll: null,
    element: null,
    timelineIn: null,
    timelineOut: null,
    elements: {},
    y: {
      current: 0,
      start: 0,
      end: 0
    }
  }),
  computed: {
    ...mapGetters(['scrollToTarget', 'scrollEvent'])
  },
  watch: {
    scrollEvent() {
      this.scroll &&
        this.scrollToTarget !== '' &&
        this.scroll.scrollTo(this.scrollToTarget)
    }
  },
  beforeDestroy() {
    if (this.scroll) {
      this.scroll.destroy()
    }
  },
  methods: {
    ...mapActions(['setTarget']),
    createAnimations() {
      this.animations = {}

      each(
        [
          this.elements.title,
          ...this.elements.biography,
          ...this.elements.subtitles,
          ...this.elements.links,
          this.elements.credits
        ],
        (element, index) => {
          this.animations[`animation_${index}`] = new Text({
            append: true,
            element
          })

          const percent = '15%'

          element.setAttribute('data-scroll', '')
          element.setAttribute('data-scroll-call', `animation_${index}`)
          element.setAttribute('data-scroll-offset', percent)
        }
      )
    },
    onResize() {
      if (this.scroll) {
        this.scroll.update()
      }
    },
    createScroll() {
      // eslint-disable-next-line new-cap
      this.scroll = new this.locomotiveScroll({
        el: this.element,
        scrollbarClass: 'scrollbar',
        getDirection: true,
        getPosition: true,
        smooth: true
      })

      this.scroll.on('scroll', (instance) => {
        instance.scroll.y > 30
          ? document.documentElement.classList.add('is-scrolled')
          : document.documentElement.classList.remove('is-scrolled')
        instance.scroll.y > 100 &&
          document.documentElement.setAttribute(
            'data-direction',
            instance.direction
          )
      })

      this.scroll.on('call', (id) => {
        if (this.animations[id]) {
          this.animations[id].animateIn()
        }
      })
    },
    // eslint-disable-next-line new-cap
    show(animation = new gsap.timeline()) {
      return new Promise((resolve) => {
        animation.call(() => {
          resolve()
        })

        this.addEventListeners()
      })
    },
    // eslint-disable-next-line new-cap
    hide(animation = new gsap.timeline()) {
      return new Promise((resolve) => {
        this.removeEventListeners()

        animation.call(() => {
          resolve()
        })
      })
    },

    onMouseDown({ clientY }) {
      this.isMouseDown = true

      this.y.start = clientY
      this.y.current = this.scroll.scroll.instance.scroll.y
    },

    onMouseMove({ clientY }) {
      if (!this.isMouseDown) {
        return
      }

      this.y.end = clientY

      const distance = (this.y.start - this.y.end) * 2
      const { scroll } = this.scroll

      scroll.instance.delta.y = this.y.current + distance
      scroll.instance.delta.y = clamp(
        scroll.instance.delta.y,
        0,
        scroll.instance.limit
      )
      scroll.isScrolling = true
      scroll.checkScroll()
    },

    onMouseUp({ clientY }) {
      this.isMouseDown = false
    },

    addEventListeners() {
      if (this.scroll) {
        this.onMouseDownEvent = this.onMouseDown.bind(this)
        this.onMouseMoveEvent = this.onMouseMove.bind(this)
        this.onMouseUpEvent = this.onMouseUp.bind(this)

        window.addEventListener('mousedown', this.onMouseDownEvent)
        window.addEventListener('mousemove', this.onMouseMoveEvent)
        window.addEventListener('mouseup', this.onMouseUpEvent)
        window.addEventListener('resize', this.onResize)
      }
    },

    removeEventListeners() {
      if (this.scroll) {
        window.removeEventListener('mousedown', this.onMouseDownEvent)
        window.removeEventListener('mousemove', this.onMouseMoveEvent)
        window.removeEventListener('mouseup', this.onMouseUpEvent)
        window.removeEventListener('resize', this.onResize)
      }
    }
  },
  transition: {
    mode: 'out-in',
    css: false,
    beforeEnter(el, done) {
      // eslint-disable-next-line new-cap
      this.timelineIn = new gsap.timeline()

      this.timelineIn.to(el, 5, {
        autoAlpha: 1,
        onComplete: done
      })
    },
    leave(el, done) {
      // eslint-disable-next-line new-cap
      this.timelineOut = new gsap.timeline()

      this.timelineOut.to(el, 0.5, {
        autoAlpha: 0
      })
    }
  }
}
