import { debounce } from '@opentiny/utils'
import { on, off } from '@opentiny/utils'

const getButtonPosition =
  ({ sliderState }) =>
  () => {
    const { slideMainPostion, offsetList } = sliderState
    const array = offsetList.slice()
    const length = array.length

    sliderState.boundingIndex = {
      left: -1,
      right: -1
    }

    for (let j = 0; j < length; j++) {
      if (array[j].right > slideMainPostion.right + 2) {
        sliderState.boundingIndex.right = j
        break
      }
    }

    for (let k = length - 1; k >= 0; k--) {
      if (array[k].left < slideMainPostion.left) {
        sliderState.boundingIndex.left = k
        break
      }
    }
  }

const arrowLeftHandler =
  ({ sliderState, api }) =>
  () => {
    const { canLeftScroll, slideMainPostion, offsetList, boundingIndex } = sliderState

    if (!canLeftScroll || sliderState.timer) {
      return
    }

    const leftPosition = boundingIndex.left !== -1 && offsetList[boundingIndex.left]

    if (leftPosition) {
      api.animationEvents(leftPosition.left - slideMainPostion.left)
    }
  }

const arrowRightHandler =
  ({ sliderState, api }) =>
  () => {
    const { canRightScroll, slideMainPostion, offsetList, boundingIndex } = sliderState

    if (!canRightScroll || sliderState.timer) {
      return
    }

    const rightPosition = boundingIndex.right !== -1 && offsetList[boundingIndex.right]

    if (rightPosition) {
      api.animationEvents(rightPosition.right - slideMainPostion.right)
    }
  }

const currentPosition = ({ sliderState, vm, props, api }) =>
  debounce(10, (isInit) => {
    sliderState.offsetList = props.data.map((item, i) => {
      const itemsRef = vm.$refs['block' + i]

      const itemsPosition = (itemsRef && itemsRef[0].getBoundingClientRect()) || {}

      return Object.assign(itemsPosition, { i })
    })

    sliderState.slideMainPostion = vm.$refs.slideMain.getBoundingClientRect()

    api.getButtonPosition()

    isInit === true && api.currentPosition()
  })

const loopAnimation =
  ({ sliderState, api, vm }) =>
  (offset, delay, scorllLeft, cb) => {
    const sliderScrollLeft = vm.$refs.slideMain.scrollLeft
    clearTimeout(sliderState.timer)

    if (sliderScrollLeft !== sliderState.oldScrollLeft && Math.abs(sliderScrollLeft - scorllLeft) > Math.abs(offset)) {
      sliderState.timer = setTimeout(() => {
        vm.$refs.slideMain.scrollLeft += offset
        sliderState.oldScrollLeft = sliderScrollLeft
        api.loopAnimation(offset, delay, scorllLeft, cb)
      }, delay)
    } else {
      sliderState.timer = null

      vm.$refs.slideMain.scrollLeft = scorllLeft
      cb && cb()
    }
  }

const animationEvents =
  ({ api, vm, props }) =>
  (allOffset) => {
    const mathNumber = allOffset > 0 ? Math.ceil : Math.floor
    const offsetInt = mathNumber(allOffset)
    const { duration, delay } = props

    if (!duration) {
      vm.$refs.slideMain.scrollLeft += offsetInt
      api.currentPosition()
      return
    }

    const space = mathNumber(offsetInt / (duration / delay))
    const left = vm.$refs.slideMain.scrollLeft + offsetInt

    api.loopAnimation(space, delay, left, () => {
      api.currentPosition()
    })
  }

const clickHandler = (api) => () => {
  api.currentPosition()
}

export const api = ['sliderState', 'arrowLeftHandler', 'arrowRightHandler', 'currentPosition', 'clickHandler']

export const renderless = (props, { reactive, onMounted, onUnmounted, computed, watch }, { vm }) => {
  const sliderState = reactive({
    canLeftScroll: computed(() => !props.noArrow && sliderState.boundingIndex.left !== -1),
    canRightScroll: computed(() => !props.noArrow && sliderState.boundingIndex.right !== -1),
    timer: null,
    offsetList: [],
    slideMainPostion: {},
    oldScrollLeft: -1,
    sliderSpace: props.sliderSpace,
    boundingIndex: {
      left: -1,
      right: -1
    }
  })

  const api = {}

  Object.assign(api, {
    sliderState,
    arrowLeftHandler: arrowLeftHandler({ sliderState, api }),
    arrowRightHandler: arrowRightHandler({ sliderState, api }),
    animationEvents: animationEvents({ api, vm, props }),
    loopAnimation: loopAnimation({ sliderState, api, vm }),
    getButtonPosition: getButtonPosition({ sliderState, api, vm }),
    currentPosition: currentPosition({ sliderState, vm, props, api }),
    clickHandler: clickHandler(api)
  })

  onUnmounted(() => {
    off(window, 'resize', api.currentPosition)
  })

  onMounted(() => {
    api.currentPosition(true)
    on(window, 'resize', api.currentPosition)
  })

  watch(
    () => props.sliderSpace,
    (value, oldValue) => {
      if (value > oldValue) {
        if (props.currentIndex >= sliderState.boundingIndex.right) {
          api.arrowRightHandler()
        }
      }

      if (value < oldValue) {
        if (props.currentIndex <= sliderState.boundingIndex.left) {
          api.arrowLeftHandler()
        }
      }
      api.currentPosition()
    }
  )

  return api
}