<script setup lang="jsx">
import {computed, createApp, h, onMounted, reactive, ref, render, watch} from "vue";
import GM from '../../utils'
import {getSlideDistance, slideInit, slideReset, slideTouchEnd, slideTouchMove, slideTouchStart} from "./common";
import {SlideType} from "@/utils/const_var";
import SlideItem from '@/components/slide/SlideItem.vue'
import bus, {EVENT_KEY} from "../../utils/bus";
import {useStore} from 'vuex'
import Loading from "@/components/Loading.vue";

const props = defineProps({
  index: {
    type: Number,
    default: () => {
      return -1
    }
  },
  render: {
    type: Function,
    default: () => {
      return null
    }
  },
  list: {
    type: Array,
    default: () => {
      return []
    }
  },
  virtualTotal: {
    type: Number,
    default: () => 5
  },
  name: {
    type: String,
    default: () => ''
  },
  uniqueId: {
    type: String,
    default: () => ''
  },
  loading: {
    type: Boolean,
    default: () => false
  },
  active: {
    type: Boolean,
    default: () => false
  },
})
const emit = defineEmits(['update:index', 'loadMore', 'refresh'])

const appInsMap = new Map()
const itemClassName = 'slide-item'
const wrapperEl = ref(null)
const state = reactive({
  name: props.name,
  localIndex: props.index,
  needCheck: true,
  next: false,
  start: {x: 0, y: 0, time: 0},
  move: {x: 0, y: 0},
  wrapper: {width: 0, height: 0, childrenLength: 0}
})
const store = useStore()
const homeRefresh = computed(() => store.state.homeRefresh)
const judgeValue = computed(() => store.state.judgeValue)

watch(
    () => props.list,
    (newVal, oldVal) => {
      // console.log('watch', newVal.length, oldVal.length, props.list)
      //新数据比老数据小或等于，是刷新
      if (newVal.length <= oldVal.length) {
        insertContent()
      } else {
        if (oldVal.length === 0) {
          insertContent()
        } else {
          let endIndex = oldVal.length + 3
          let top = $(wrapperEl.value).find(`.${itemClassName}:last`).css('top')
          newVal.slice(oldVal.length, endIndex).map((item, index) => {
            let el = getInsEl(item, oldVal.length + index)
            //这里必须要设置个top值，不然会把前面的条目给覆盖掉
            //2022-3-27，这里不用计算，直接用已用slide-item最后一条的top值，
            //因为有一条情况：当滑动最后一条和二条的时候top值不会继续加。此时新增的数据如果还
            // 计算top值的，会和前面的对不上
            $(el).css('top', top)
            wrapperEl.value.appendChild(el)
            state.wrapper.childrenLength++
          })
        }
      }
    }
)

watch(
    () => props.index,
    (newVal, oldVal) => {
      if (!props.list.length) return
      // console.log('watch-index', newVal, oldVal)
      bus.emit(EVENT_KEY.CURRENT_ITEM, props.list[newVal])
      bus.emit(EVENT_KEY.SINGLE_CLICK_BROADCAST, {
        uniqueId: props.uniqueId,
        index: newVal,
        type: EVENT_KEY.ITEM_PLAY
      })
      setTimeout(() => {
        bus.emit(EVENT_KEY.SINGLE_CLICK_BROADCAST, {
          uniqueId: props.uniqueId,
          index: oldVal,
          type: EVENT_KEY.ITEM_STOP
        })
      }, 200)
    }
)

watch(
    () => props.active,
    (newVal, oldVal) => {
      if (newVal && !props.list.length) {
        return emit('refresh')
      }
      console.log('active', 'newVal', newVal, 'oldVal', oldVal)
      if (newVal) {
        bus.emit(EVENT_KEY.CURRENT_ITEM, props.list[state.localIndex])
      }
      bus.emit(EVENT_KEY.SINGLE_CLICK_BROADCAST, {
        uniqueId: props.uniqueId,
        index: state.localIndex,
        type: newVal === false ? EVENT_KEY.ITEM_STOP : EVENT_KEY.ITEM_PLAY
      })
    },
    {immediate: true}
)

onMounted(() => {
  slideInit(wrapperEl.value, state, SlideType.VERTICAL)
  insertContent()
})

function insertContent(list = props.list) {
  if (!list.length) return
  $(wrapperEl.value).empty()
  let half = (props.virtualTotal - 1) / 2
  let start = 0
  if (state.localIndex >= half) {
    start = state.localIndex - half
  }
  let end = start + props.virtualTotal
  if (end >= list.length) {
    end = list.length
    start = end - props.virtualTotal
  }
  if (start < 0) start = 0
  list.slice(start, end).map(
      (item, index) => {
        //自动播放，当前条（可能是0，可能是其他），试了下用jq来找元素，然后trigger play事件，要慢点样
        let el = getInsEl(item, start + index, start + index === state.localIndex)
        wrapperEl.value.appendChild(el)
      }
  )
  GM.$setCss(wrapperEl.value, 'transform', `translate3d(0px,${getSlideDistance(state, SlideType.VERTICAL)}px,  0px)`)

  if (state.localIndex > 2 && list.length > 5) {
    $(wrapperEl.value).find(`.${itemClassName}`).each(function () {
      if ((list.length - state.localIndex) > 2) {
        $(this).css('top', (state.localIndex - 2) * state.wrapper.height)
      } else {
        $(this).css('top', start * state.wrapper.height)
      }
    })
  }
  state.wrapper.childrenLength = wrapperEl.value.children.length
  bus.emit(EVENT_KEY.CURRENT_ITEM, list[state.localIndex])

}

function dislike(item) {
  let currentItem = $(wrapperEl.value).find(`.${itemClassName}[data-index=${state.localIndex}]`)
  let replaceItem = getInsEl(item, state.localIndex, true)
  $(replaceItem).css('top', currentItem.css('top'))
  currentItem.replaceWith(replaceItem)
}

defineExpose({dislike})

function getInsEl(item, index, play = false) {
  // console.log('index', index, play)
  let slideVNode = props.render(item, index, play, props.uniqueId)
  const parent = document.createElement('div')
  //TODO 打包到线上时用这个，这个在开发时任何修改都会刷新页面
  if (import.meta.env.PROD) {
    parent.classList.add('slide-item')
    parent.setAttribute('data-index', index)
    render(slideVNode, parent)
    appInsMap.set(index, {
      unmount: () => {
        render(null, parent)
        parent.remove()
      }
    })
    return parent
  }
  const app = createApp({
    render() {
      return <SlideItem data-index={index}>{slideVNode}</SlideItem>
    }
  })
  const ins = app.mount(parent)
  appInsMap.set(index, ins)
  return ins.$el
}

function touchStart(e) {
  slideTouchStart(e, wrapperEl.value, state)
}

//TODO 2022-3-28:在最顶部，反复滑动会抖动一下，初步猜测是因为方向变了，导致的加判断距离变成了减
function touchMove(e) {
  slideTouchMove(e, wrapperEl.value, state, judgeValue.value, canNext, null, SlideType.VERTICAL)
}

function touchEnd(e) {
  let isNext = state.move.y < 0
  if (state.localIndex === 0 && !isNext && state.move.y > (homeRefresh.value + judgeValue.value)) {
    emit('refresh')
  }
  slideTouchEnd(e, state, canNext, (isNext) => {
    let half = (props.virtualTotal + 1) / 2
    if (props.list.length > props.virtualTotal) {
      if (isNext) {
        if (state.localIndex > props.list.length - props.virtualTotal && state.localIndex >= half) {
          emit('loadMore')
        }
        let addItemIndex = state.localIndex + 2
        let res = $(wrapperEl.value).find(`.${itemClassName}[data-index=${addItemIndex}]`)
        if (state.wrapper.childrenLength < props.virtualTotal) {
          if (res.length === 0) {
            wrapperEl.value.appendChild(getInsEl(props.list[addItemIndex], addItemIndex))
          }
        }
        if (state.wrapper.childrenLength === props.virtualTotal
            && state.localIndex >= (props.virtualTotal + 1) / 2
            && state.localIndex <= props.list.length - 3
        ) {
          if (res.length === 0) {
            wrapperEl.value.appendChild(getInsEl(props.list[addItemIndex], addItemIndex))
            appInsMap.get($(wrapperEl.value).find(`.${itemClassName}:first`).data('index')).unmount()
            // $(wrapperEl.value).find(".base-slide-item:first").remove()
            $(wrapperEl.value).find(`.${itemClassName}`).each(function () {
              $(this).css('top', (state.localIndex - 2) * state.wrapper.height)
            })
          }
        }
        if (state.wrapper.childrenLength > props.virtualTotal) {
          $(wrapperEl.value).find(`.${itemClassName}`).each(function () {
            let index = $(this).data('index')
            if (index < (state.localIndex - 2)) {
              appInsMap.get(index).unmount()
            }
            $(this).css('top', (state.localIndex - 2) * state.wrapper.height)
          })
        }
      } else {
        let addItemIndex = state.localIndex - 2
        let res = $(wrapperEl.value).find(`.${itemClassName}[data-index=${addItemIndex}]`)

        if (state.localIndex > 1 && state.localIndex <= props.list.length - 4) {
          if (res.length === 0) {
            wrapperEl.value.prepend(getInsEl(props.list[addItemIndex], addItemIndex))
            appInsMap.get($(wrapperEl.value).find(`.${itemClassName}:last`).data('index')).unmount()
            // $(wrapperEl.value).find(".base-slide-item:last").remove()
            $(wrapperEl.value).find(`.${itemClassName}`).each(function () {
              $(this).css('top', (state.localIndex - 2) * state.wrapper.height)
            })
          }
        }

        if (state.wrapper.childrenLength > props.virtualTotal) {
          appInsMap.get($(wrapperEl.value).find(`.${itemClassName}:last`).data('index')).unmount()
        }
      }
      state.wrapper.childrenLength = wrapperEl.value.children.length
    }
  }, null, SlideType.VERTICAL)
  slideReset(wrapperEl.value, state, SlideType.VERTICAL, emit)
}

function canNext(isNext) {
  return !((state.localIndex === 0 && !isNext) || (state.localIndex === props.list.length - 1 && isNext));
}
</script>

<template>
  <div class="slide slide-infinite">
    <Loading v-if="props.loading && props.list.length === 0"/>
    <div class="slide-list flex-direction-column"
         ref="wrapperEl"
         @click="null"
         @touchstart="touchStart"
         @touchmove="touchMove"
         @touchend="touchEnd"
    >
      <slot></slot>
    </div>
  </div>
</template>
