<template>
  <div id="SlideAlbum">
    <div class="img-slide-wrapper">
      <div
        class="img-slide-list"
        ref="slideListEl"
        @touchstart.passive="touchStart"
        @touchmove="touchMove"
        @touchend="touchEnd"
      >
        <div class="img-slide-item" :key="index" v-for="(img, index) in item.imgs">
          <img :ref="(e) => setItemRef(e, 'itemRefs')" :src="img + '&d=' + index" />
        </div>
      </div>
    </div>
    <Icon
      icon="fluent:play-28-filled"
      class="pause-icon"
      v-if="
        state.status === SlideItemPlayStatus.Pause &&
        state.operationStatus === SlideAlbumOperationStatus.Normal
      "
    />

    <template v-if="state.operationStatus === SlideAlbumOperationStatus.Normal">
      <!--      <ItemToolbar-->
      <!--        class="mb3r"-->
      <!--        v-model:item="state.localItem"-->
      <!--        :position="position"-->
      <!--        v-bind="$attrs"-->
      <!--      />-->
      <!--      <ItemDesc class="mb3r" v-model:item="state.localItem" :position="position" />-->
    </template>
    <!--不知为啥touch事件，在下部20px的空间内不触发，加上click事件不好了  -->
    <div
      class="progress-bar"
      v-if="!state.isPreview && state.operationStatus !== SlideAlbumOperationStatus.Zooming"
      @click="null"
      @touchstart="progressBarTouchStart"
      @touchmove="progressBarTouchMove"
      @touchend="progressBarTouchMEnd"
    >
      <div class="bar" :key="index" v-for="(img, index) in item.imgs">
        <div class="progress" :style="getWidth(index)"></div>
      </div>
    </div>
    <Teleport to="#home-index" v-if="state.isPreview">
      <div class="preview">
        <div class="preview-wrapper">
          <img
            :src="img + '&d=' + index"
            :class="{ 'preview-img': index === state.localIndex }"
            :key="index"
            v-for="(img, index) in props.item.imgs"
            :ref="(e) => setItemRef(e, 'previewImgs')"
          />
        </div>
        <div class="indicator">
          <span class="index">{{ state.localIndex + 1 }}</span
          >&nbsp;/&nbsp;{{ props.item.imgs.length }}
        </div>
      </div>
    </Teleport>
    <Teleport to="#home-index" v-if="state.operationStatus !== SlideAlbumOperationStatus.Normal">
      <div class="album-toolbar">
        <div class="left">
          <Icon
            icon="iconamoon:close"
            @click="state.operationStatus = SlideAlbumOperationStatus.Normal"
          />
        </div>
        <div class="right">
          <Icon icon="heroicons-outline:menu-alt-1" @click="Utils._no" />
          <Icon
            icon="fluent:play-28-filled"
            v-if="state.status === SlideItemPlayStatus.Pause"
            class="pause"
            @click="startPlay"
          />
          <Icon icon="bi:pause-fill" v-else class="pause" @click="stopPlay" />
          <Icon icon="system-uicons:push-down" @click="_notice('已保存到系统相册')" />
        </div>
      </div>
    </Teleport>
  </div>
</template>

<script setup lang="jsx">
import enums from '../../utils/enums'
import Utils from '../../utils'
import GM, { _notice } from '../../utils'
import { mat4 } from 'gl-matrix'
import { Icon } from '@iconify/vue'
import {
  nextTick,
  onBeforeUpdate,
  onMounted,
  onUnmounted,
  provide,
  reactive,
  ref,
  watch
} from 'vue'
import {
  getSlideOffset,
  slideInit,
  slideReset,
  slideTouchEnd,
  slideTouchMove,
  slideTouchStart
} from '@/utils/slide'
import { SlideAlbumOperationStatus, SlideItemPlayStatus, SlideType } from '../../utils/const_var'
import { cloneDeep } from '@/utils'
import bus, { EVENT_KEY } from '../../utils/bus'

let out = new Float32Array([0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0])
let ov = new Float32Array([1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1])
let origin = cloneDeep(ov)
const rectMap = new Map()

// provide('isPlaying', computed(() => this.isPlaying))
provide('isPlaying', false)
const props = defineProps({
  item: {
    type: Object,
    default() {
      return {
        type: 'imgs',
        imgs: [
          'https://cdn.seovx.com/?mom=302',
          'https://cdn.seovx.com/?mom=302',
          'https://cdn.seovx.com/?mom=302',
          'https://cdn.seovx.com/?mom=302',
          'https://cdn.seovx.com/?mom=302',
          'https://cdn.seovx.com/?mom=302',
          'https://cdn.seovx.com/?mom=302',
          'https://cdn.seovx.com/?mom=302'
        ],
        id: '034ae83b-ca0a-401a-b7c6-cf78361bae7b',
        video: 'http://douyin.ttentau.top/0.mp4',
        video_data_size: 26829508,
        duration: 427780,
        desc: '我不管我们宿舍第一好看',
        allow_download: 0,
        allow_duet: 0,
        allow_react: 0,
        allow_music: 1,
        allow_douplus: 1,
        allow_share: 1,
        digg_count: 10480000,
        comment_count: 79000,
        download_count: 6,
        play_count: 0,
        share_count: 119000,
        forward_count: 0,
        collect_count: 3,
        sort: 195,
        is_top: 0,
        city: '北京',
        address: '中央戏剧学院',
        musicId: '2ee213c6-3e3f-4758-ba5a-7f1c955604a4',
        create_time: '1630423555',
        creator_id: '93864497380',
        status: 1,
        topics: [
          {
            id: '85ceda30-898f-4b57-b891-0e58b3ab99a9',
            name: '敬礼变装',
            creator_id: '93864497380',
            create_time: '1630423555',
            status: 1
          },
          {
            id: '85ceda30-898f-4b57-b891-0e58b3ab99a9',
            name: '宿舍',
            creator_id: '93864497380',
            create_time: '1630423555',
            status: 1
          }
        ],
        music: {
          id: 'cde50af2-628c-4d28-b9c6-67237a62518e',
          cover:
            'https://p29.douyinpic.com/img/tos-cn-avt-0015/f4de202ff2e41b523838a4a767aebd16~c5_100x100.jpeg?from=116350172',
          mp3: 'https://sf3-cdn-tos.douyinstatic.com/obj/ies-music/1658584661080088.mp3',
          title: '@穷电影创作的原声-小高快起来跳舞',
          creator_id: '93864497380',
          create_time: '1630423555',
          status: 1
        },
        author: {
          id: '1',
          unique_id_modify_time: '1630393144',
          unique_id: '10040050',
          favoriting_count: 143,
          avatar: new URL('../../assets/img/icon/avatar/3.png', import.meta.url).href,
          school: {
            name: '中央戏剧学院',
            department: null,
            joinTime: null,
            education: null,
            displayType: enums.DISPLAY_TYPE.ALL
          },
          city: '',
          province: '北京',
          country: '',
          location: '',
          birthday: '2002-01-01',
          cover: 'https://p3.douyinpic.com/obj/c8510002be9a3a61aad2?from=116350172',
          following_count: 66,
          follower_count: 235000,
          aweme_count: 1796000,
          nickname: '我是小睿耶',
          certification: '',
          phone: '',
          sex: '',
          last_login_time: '1630423555',
          create_time: '1630423555',
          status: 1,
          desc: `一个普普通通学表演的\n看到的人都能开开心心`,
          is_private: 0
        }
      }
    }
  },
  position: {
    type: Object,
    default: () => {
      return {
        uniqueId: '',
        index: ''
      }
    }
  }
})
const slideListEl = ref(null)

//用于解决，touch事件触发startPlay,然后click事件又触发stopLoop的问题
let lockDatetime = 0

const state = reactive({
  type: SlideType.HORIZONTAL,
  judgeValue: 20,
  name: 'SlideHorizontal',
  localIndex: 0,
  needCheck: true,
  isPreview: false,
  isZoom: false,
  operationStatus: SlideAlbumOperationStatus.Normal,
  next: false,
  wrapper: { width: 0, height: 0, childrenLength: 0 },
  last: {
    point1: { x: 0, y: 0 },
    point2: { x: 0, y: 0 }
  },
  start: {
    x: 0,
    y: 0,
    point1: { x: 0, y: 0 },
    point2: { x: 0, y: 0 },
    center: { x: 0, y: 0 },
    time: 0
  },
  move: { x: 0, y: 0 },
  itemRefs: [],
  previewImgs: [],
  cycleFn: -1,
  status: SlideItemPlayStatus.Play,
  isAutoPlay: true,
  localItem: props.item
})

function stopPlay() {
  state.status = SlideItemPlayStatus.Pause
  stopLoop()
}

function startPlay() {
  state.isAutoPlay = true
  state.status = SlideItemPlayStatus.Play
  startLoop()
}

function stopLoop() {
  clearInterval(state.cycleFn)
  state.cycleFn = -1
}

function startLoop() {
  if (state.cycleFn !== -1) return
  if (!state.isAutoPlay) return
  state.cycleFn = setInterval(() => {
    state.status = SlideItemPlayStatus.Play
    if (state.localIndex < props.item.imgs.length - 1) {
      state.localIndex++
    } else {
      state.localIndex = 0
    }
  }, 2000)
}

onMounted(async () => {
  await nextTick()
  slideInit(slideListEl.value, state, SlideType.HORIZONTAL)
  startPlay()
  // setTimeout(() => {
  //   state.operationStatus = SlideAlbumOperationStatus.Zooming
  // }, 1000)
  bus.on(EVENT_KEY.SINGLE_CLICK_BROADCAST, click)
})

onUnmounted(() => {
  bus.off(EVENT_KEY.SINGLE_CLICK_BROADCAST, click)
})

function click({ uniqueId, index, type }) {
  // console.log('position,', type, Date.now() - lockDatetime)
  if (props.position.uniqueId === uniqueId && props.position.index === index) {
    // if (type === EVENT_KEY.ITEM_TOGGLE) {
    //   if (state.status === SlideItemPlayStatus.Play) {
    //     stopLoop()
    //   } else {
    //     state.isAutoPlay = true
    //     startLoop()
    //   }
    // }
    if (type === EVENT_KEY.ITEM_STOP) {
      stopPlay()
      setTimeout(() => {
        state.localIndex = 0
        state.status = SlideItemPlayStatus.Play
        state.operationStatus = SlideAlbumOperationStatus.Normal
      }, 500)
    }
    if (type === EVENT_KEY.ITEM_PLAY) {
      state.localIndex = 0
      startPlay()
    }
  }
}

// 确保在每次更新之前重置ref
onBeforeUpdate(() => {
  state.itemRefs = []
  state.previewImgs = []
})

watch(
  () => state.localIndex,
  () => {
    GM.$setCss(slideListEl.value, 'transition-duration', `300ms`)
    GM.$setCss(
      slideListEl.value,
      'transform',
      `translate3d(${getSlideOffset(state, slideListEl.value)}px, 0, 0)`
    )
  }
)

watch(
  () => state.operationStatus,
  (newVal) => {
    if (newVal !== SlideAlbumOperationStatus.Normal) {
      bus.emit(EVENT_KEY.ENTER_FULLSCREEN)
    } else {
      bus.emit(EVENT_KEY.EXIT_FULLSCREEN)
    }
  }
)

function calcCurrentIndex(e) {
  state.isPreview = true
  let x = e.touches[0].pageX

  let current = -1
  let length = state.previewImgs.length
  for (let i = length - 1; i >= 0; i--) {
    let rect = state.previewImgs[i].getBoundingClientRect()
    if (rect.x < x) {
      current = i
      break
    }
  }
  if (current > -1) {
    state.localIndex = current
  }
}

function progressBarTouchStart(e) {
  Utils.$stopPropagation(e)
}

function progressBarTouchMove(e) {
  Utils.$stopPropagation(e)
  calcCurrentIndex(e)
}

function progressBarTouchMEnd(e) {
  Utils.$stopPropagation(e)
  state.isPreview = false
}

function touchStart(e) {
  lockDatetime = Date.now()

  // Utils.$showNoticeDialog('start'+e.touches.length)
  console.log('start', e.touches.length)
  if (e.touches.length === 1) {
    slideTouchStart(e, slideListEl.value, state)
  } else {
    if (state.operationStatus === SlideAlbumOperationStatus.Zooming) {
      // state.start.center = Utils.getCenter(state.start.point1, state.start.point2)
      return
    }
    state.operationStatus = SlideAlbumOperationStatus.Zooming
    state.itemRefs[state.localIndex].style['transition-duration'] = '0ms'
    state.last.point1 = state.start.point1 = {
      x: e.touches[0].pageX,
      y: e.touches[0].pageY
    }
    state.last.point2 = state.start.point2 = {
      x: e.touches[1].pageX,
      y: e.touches[1].pageY
    }
    state.start.center = Utils.getCenter(state.start.point1, state.start.point2)
  }
}

function touchMove(e) {
  const s = true
  if (s) return

  // Utils.$showNoticeDialog('move'+e.touches.length)
  // console.log('move', e.touches.length, state.operationStatus)
  let current1 = { x: e.touches[0].pageX, y: e.touches[0].pageY }
  stopLoop()

  //单手移动
  if (e.touches.length === 1) {
    if (state.operationStatus === SlideAlbumOperationStatus.Zooming) {
      // console.log('m1')
      Utils.$stopPropagation(e)

      // console.log('单手移动',)
      let movementX = current1.x - state.last.point1.x
      let movementY = current1.y - state.last.point1.y
      // console.log(movementX, movementY)
      const t = new Float32Array([1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, movementX, movementY, 0, 1])
      ov = mat4.multiply(out, t, ov)
      state.itemRefs[state.localIndex].style.transform = `matrix3d(${ov.toString()})`
      state.last.point1 = current1
    } else {
      // console.log('m2')
      state.isAutoPlay = false
      slideTouchMove(
        e,
        slideListEl.value,
        state,
        canNext,
        () => {
          //TODO 这里需要这个事件吗
          if (state.operationStatus !== SlideAlbumOperationStatus.Normal) {
            Utils.$stopPropagation(e)
          }
          // console.log('move-notNextcb')
          // state.operationStatus = SlideAlbumOperationStatus.Normal
        },
        () => {
          if (state.operationStatus !== SlideAlbumOperationStatus.Normal) {
            Utils.$stopPropagation(e)
          }
        }
      )
    }
  } else {
    // console.log('m3')
    state.operationStatus = SlideAlbumOperationStatus.Zooming
    Utils.$stopPropagation(e)

    let rect = { x: 0, y: 0 }
    if (rectMap.has(state.localIndex)) {
      rect = rectMap.get(state.localIndex)
    } else {
      //TODO 这里去掉jquery
      //getBoundingClientRect在手机上获取不到值
      // let offset = $(state.itemRefs[state.localIndex]).offset()
      // rect = { x: offset.left, y: offset.top }
      // rectMap.set(state.localIndex, rect)
    }

    let current2 = { x: e.touches[1].pageX, y: e.touches[1].pageY }

    // 双指缩放比例，就是对应的放大倍数
    let currentRatio =
      Utils.getDistance(current1, current2) /
      Utils.getDistance(state.start.point1, state.start.point2)
    let movementRatio = currentRatio - ov[0]
    // console.log('movementRatio',movementRatio)
    //如果本次比例和上次的不超过0.02。那么判定为平移
    if (Math.abs(movementRatio) <= 0.02) {
      let movementX = current1.x - state.last.point1.x
      let movementY = current1.y - state.last.point1.y
      let movement2X = current2.x - state.last.point2.x
      let movement2Y = current2.y - state.last.point2.y

      let minX = Math.min(movementX, movement2X)
      let minY = Math.min(movementY, movement2Y)
      const t1 = new Float32Array([1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, minX, minY, 0, 1])
      ov = mat4.multiply(out, t1, ov)
    } else {
      let center = Utils.getCenter(current1, current2)
      center.x -= rect.x
      center.y -= rect.y
      //用最新的放大倍数ratio除以之前的放大ov[0]倍数，算出本次要累加放大的倍数
      let zoom = currentRatio / ov[0]
      const x = center.x * (1 - zoom)
      const y = center.y * (1 - zoom)
      const t = new Float32Array([zoom, 0, 0, 0, 0, zoom, 0, 0, 0, 0, 1, 0, x, y, 0, 1])
      //如果zoom是每次都是最后放大倍数，第三个参数用原值（即，矩阵x乘时，都是乘以单位矩阵）
      //如果zoom是累加放大（比如每次都是0.15），第三个参数用ov。这里还是采用累加计算
      ov = mat4.multiply(out, t, ov)
    }

    state.itemRefs[state.localIndex].style.transform = `matrix3d(${ov.toString()})`
    state.last.point1 = current1
    state.last.point2 = current2
  }
}

function touchEnd(e) {
  // console.log('Date.now() - lockDatetime', Date.now() - lockDatetime,)
  if (
    Date.now() - lockDatetime < 300 &&
    state.move.x === 0 &&
    state.move.y === 0 &&
    state.operationStatus !== SlideAlbumOperationStatus.Zooming
  ) {
    if (state.status === SlideItemPlayStatus.Play) {
      stopPlay()
    } else {
      startPlay()
    }
    return
  }

  state.isPreview = false
  //这里，如果是双指触控的话，会触发两次事件，第一次touches长度为1，第二次为0
  //如果是单指触控的话，触发一次事件，touches长度为0
  console.log('end', e.touches.length, state.operationStatus)

  // e.touches.length === 1 说明，松开了第一只手指
  if (e.touches.length === 1) {
    //双指缩放状态下，但只松开了一只手
    if (state.operationStatus === SlideAlbumOperationStatus.Zooming) {
      Utils.$stopPropagation(e)
      state.last.point1 = { x: e.touches[0].pageX, y: e.touches[0].pageY }
      startLoop()
    }
  } else {
    if (state.operationStatus === SlideAlbumOperationStatus.Zooming) {
      Utils.$stopPropagation(e)
      ov = origin
      state.itemRefs[state.localIndex].style['transition-duration'] = '300ms'
      state.itemRefs[state.localIndex].style.transform = `matrix3d(${origin.toString()})`
      startLoop()
      state.operationStatus = SlideAlbumOperationStatus.Look
    } else {
      slideTouchEnd(
        e,
        state,
        canNext,
        () => {
          console.log('nextCb')
        },
        () => {
          if (state.operationStatus !== SlideAlbumOperationStatus.Normal) {
            state.operationStatus = SlideAlbumOperationStatus.Normal
          }
          console.log('doNotNextCb')
          startLoop()
        }
      )
      slideReset(e, slideListEl.value, state)
    }
  }
}

function getWidth(index) {
  if (state.localIndex >= index) return { width: '100%' }
}

function setItemRef(el, key) {
  el && state[key].push(el)
}

function canNext(state, isNext) {
  let res = !(
    (state.localIndex === 0 && !isNext) ||
    (state.localIndex === props.item.imgs.length - 1 && isNext)
  )
  return res
}
</script>

<style scoped lang="less">
#SlideAlbum {
  transition: height 0.3s;
  position: relative;
  width: 100%;
  height: 100%;
  overflow: hidden;
  color: white;
  font-size: 14rem;

  .img-slide-wrapper {
    position: relative;
    height: 100%;
    width: 100%;

    .img-slide-list {
      height: 100%;
      width: 100%;
      display: flex;
      position: relative;

      .img-slide-item {
        height: 100%;
        width: 100%;
        flex-shrink: 0;
        display: flex;
        align-items: center;
        justify-content: center;

        img {
          transform-origin: 0 0;
          width: 100%;
        }
      }
    }
  }

  .progress-bar {
    position: absolute;
    width: 100%;
    bottom: 10rem;
    display: flex;
    box-sizing: border-box;
    padding: 0 5rem;
    @h: 4rem;
    //height: @h;
    height: 10rem;
    //background-color: red;
    align-items: flex-end;
    justify-content: space-between;

    .bar {
      border-radius: 10rem;
      flex: 1;
      margin: 0 2rem;
      height: @h;
      background: #75757580;
      position: relative;
      overflow: hidden;

      .progress {
        border-radius: 10rem;
        position: absolute;
        left: 0;
        height: @h;
        background: #e5e5e587;
      }
    }
  }
}
</style>
<style lang="less">
.preview {
  transition: opacity 0.3s;
  position: fixed;
  bottom: 0;
  width: 100%;
  display: flex;
  align-items: center;
  justify-content: center;
  flex-direction: column;

  .preview-wrapper {
    img {
      transition: all 0.3s;
      margin: 0 5rem;
      width: 30rem;
      height: 45rem;
      background-color: black;
      border-radius: 3rem;
      overflow: hidden;
      object-fit: cover;

      &.preview-img {
        margin: 0 15rem;
        width: 40rem;
      }
    }
  }

  .indicator {
    background: var(--footer-color);
    width: 100%;
    height: var(--footer-height);
    color: gray;
    display: flex;
    align-items: center;
    justify-content: center;

    .index {
      color: white;
    }
  }
}

.album-toolbar {
  position: absolute;
  bottom: 0;
  color: white;
  font-size: 24rem;
  background: var(--footer-color);
  width: 100%;
  box-sizing: border-box;
  height: var(--footer-height);
  display: flex;
  align-items: center;
  justify-content: space-between;
  padding: 0 10rem;

  @padding: 18rem;

  .left {
    height: 40rem;
    background-color: rgba(71, 71, 86, 0.53);
    border-radius: 10rem;
    padding: 0 @padding;
    display: flex;
    align-items: center;
    justify-content: center;
  }

  .right {
    .left;

    display: flex;
    align-items: center;
    gap: 20rem;
  }
}
</style>
