<template>
<view class="luojigou-board" >
  <view class="board" :style="{ transform: `scale(${adaptatio})` ,transformOrigin: '50% 0%'}" >
    <image class="board-img" :src="boardUrl" />
    <view class="board-header" :style="{zIndex: viewZindex.headerView}" id="game-label" >
        <view class="trumpt" @click="emits('playAudio')">
          <!-- <image class="dog" :src="staticImg.trumptDog"   /> -->
          <image
            class="trumpt-icon dog"
            :src="props.playLoading ? staticImg.trumptGif : staticImg.trumptPng"
          />
        </view>
        <view class="tip " :key="props.cardDesc">
          <scroll-view
            scroll-y
            :style="{height: '88rpx',
            }"
          >
            {{props.cardDesc ? props.cardDesc : "加載中"}}
          </scroll-view>
        </view>
        <image
          class="luojigou-dog"
          :src="staticImg.luojigouDog"
        />
    </view>
    <view  class="card" :style="{zIndex: viewZindex.quesView}"  >
        <view class="ques"  id="quesRef" >
          <image id="ques-url"  :src="props.board.quesUrl" alt=""  />
        </view>
    </view>
    <view class="ans"  id="ansRef" :style="{zIndex: viewZindex.quesView}">
      <image :src="props.board.ansUrl" alt="" />
    </view>
    <canvas
      type="2d"
      canvas-id="magnifier-canvas"
      id="magnifier-canvas"
      :style="{width: 600 + 'rpx', height: 772  + 'rpx', zIndex: viewZindex.magnifierView}"
    ></canvas>
    <movable-area
      v-if="props.cardType !== undefined" 
      class="movable-area"
      id="movableAreaRef" 
      :style="{
        width: 357 * rate+ 'rpx', 
        height: 466 * rate  + 'rpx',
        top: 102 * rate / adaptatio + 'rpx',
        left: 50  + '%',
        transform: `translateX(-${50}%)`,
        zIndex: viewZindex.moveView,
        scale: 1 / adaptatio
      }"
    >
      <movable-view
        v-for="item in buttons"
        :key="item.id"
        :disabled="item.disabled"
        :x="item.x  "
        :y="item.y"
        damping="100"
        direction="all"
        class="movable-view"
        :style="{
          zIndex: item.zIndex, 
          width: 46 * rate + 'rpx', 
          height: 46 * rate+ 'rpx',
        }"
        @touchend="touchend($event, item)"
        @touchstart="touchStart(item)"
      >
        <image 
          :id="`rock-id-${item.id}`"
          :class="`movable-image `" 
          :style="{willChange: 'transform', transformOrigin: `center bottom`}"  
          :src="item.url" 
        />
        
        <image
          v-if="item.ans"
          class="success-flag"
          :src="staticImg.successFlag"
        />
      </movable-view>
    </movable-area>
  </view>
</view>

</template>

<script setup lang="ts" name="luojigou-board" >
import { defineProps, reactive, ref, computed, getCurrentInstance, defineEmits, watch } from 'vue'
import { useStaticImg, useNavbarInfo, useSchedulerOnce, useQueryElInfo, useAdaptationIpadAndPhone, useMagnifier,  } from '@/hooks/index'
import type { CardModeEnum } from '@/enum/constant';
import { useCalcQuantityStore } from '@/store/index';
import { AudioController } from '@/controller/AudioController';
import Hammer from 'hammerjs'
import { onMounted, nextTick } from 'vue';


interface Buttons {
  id: number,
  x: number,
  y: number,
  initX: number,
  initY: number,
  url: string,
  color: API.Color,
  index: number,
  zIndex: number,
  ans: API.Color | null
  disabled: boolean
}

interface IProps {
  cardType: 0 | 1, // 0 四钮题卡 | 1 六钮题卡
  board: API.Board,
  mode: CardModeEnum,
  cardDesc: string,
  playLoading: boolean,
  getExpose: (records: any) => void
  tipsButton: number
  audioSrc: string,
  magnifierState: boolean
}

const staticImg = useStaticImg()

const adaptatio = useAdaptationIpadAndPhone()

const calcQuantityStore = useCalcQuantityStore()

const props = defineProps<IProps>()

const emits = defineEmits(['playAudio', 'submit'])

const navbarInfo = useNavbarInfo()

const state = reactive({
  zIndex: 0, // 暂存zIndex
  scale: 1
})

const viewZindex = ref({
  moveView: 32, // 拖拽层
  magnifierView: 31, // 放大镜
  quesView: 29, // 题卡
  headerView: 33,
  introView: 32 // 引导层
})


// 手势操作题卡图片的state
const hammerState = reactive({
  x: 0, // 记录水平方向上的偏移量
  y: 0, // 记录垂直方向上的偏移量
  scaleCount: 2,
  scaleIndex: 1
})

const colorMap = new Map([
  ['red', '#FF0002'],
  ['blue', '#0061B4'],
  ['purple', '#A764AB'],
  ['yellow', '#FFD800'],
  ['green', '#008D46'],
  ['orange', '#FF7F00'],
])



const boardUrl = props.cardType == 1 ? staticImg.boardSix : staticImg.boardFour

const ansRef = ref<UniApp.NodeInfo>()
const quesRef = ref<UniApp.NodeInfo>()
const movableAreaRef = ref<UniApp.NodeInfo>()

useQueryElInfo('#quesRef', (nodeInfo) => quesRef.value = nodeInfo as UniApp.NodeInfo, getCurrentInstance()!)
useQueryElInfo('#ansRef', (nodeInfo) =>  ansRef.value = nodeInfo as UniApp.NodeInfo, getCurrentInstance()!)
useQueryElInfo('#movableAreaRef', (nodeInfo) => movableAreaRef.value = nodeInfo as UniApp.NodeInfo, getCurrentInstance()!)

const baseRatio = adaptatio

const rate = baseRatio * 2

const { windowWidth, windowHeight } = uni.getSystemInfoSync()

const unit = windowWidth / windowHeight > 0.6 ? 1 : 0.5

// 几钮模板
const copies = props.cardType === 0 ? 4 : 6

const ansItemHeight = computed(() => Math.floor(ansRef.value?.height! / copies))

const TPos = (x: number, y: number) => {
  
  return { x: x - movableAreaRef.value?.left! - 23 * rate * unit , y: y - movableAreaRef.value?.top! - 23 * rate * unit }
  
}

const getButtonIndex = (_y: number) => Math.floor(_y / ansItemHeight.value)

const getButtonPosByIndex = (index: number) => {
  
  const x = ansRef.value?.width! + quesRef.value?.width! 
 
  const y = ansItemHeight.value * index + ansItemHeight.value / 2 - 23 * rate * unit

  return { x, y }
}

const buttonWidth = 46 * windowWidth / 375 * baseRatio

const VSpace = props.cardType === 0 ?Math.floor(windowWidth / 375 * 26) * baseRatio + buttonWidth : Math.floor(windowWidth / 375 * 8) * baseRatio + buttonWidth

const Y = 435 * rate

const getX = (index: number) => index * VSpace + Math.floor(windowWidth / 375 * 11) * baseRatio

// 注意一下四钮 用哪几个颜色的按钮
let buttons = reactive<Buttons[]>([
  {id: 0, ans: null, x: getX(0), y: Y * rate  , disabled: false, initX: getX(0), initY: Y * rate,  zIndex: 0, index: -1, url: staticImg.red, color: 'red' },
  {id: 1, ans: null, x: getX(1), y: Y * rate  , disabled: false, initX: getX(1), initY: Y * rate,  zIndex: 0, index: -1, url: staticImg.blue, color: 'blue' },
  {id: 2, ans: null, x: getX(2), y: Y * rate  , disabled: false, initX: getX(2), initY: Y * rate,  zIndex: 0, index: -1, url: staticImg.green, color: 'green' },
  {id: 3, ans: null, x: getX(3), y: Y * rate  , disabled: false, initX: getX(3), initY: Y * rate,  zIndex: 0, index: -1, url: staticImg.orange, color: 'orange' },
  {id: 4, ans: null, x: getX(4), y: Y * rate  , disabled: false, initX: getX(4), initY: Y * rate,  zIndex: 0, index: -1, url: staticImg.yellow, color: "yellow" },
  {id: 5, ans: null, x: getX(5), y: Y * rate  , disabled: false, initX: getX(5), initY: Y * rate,  zIndex: 0, index: -1, url: staticImg.purple, color: 'purple' },
])

buttons.splice(props.cardType == 1 ?  buttons.length : buttons.length - 2, buttons.length)

// 让按钮回到原位
const disPatchButtonGoInitPos = (index: number) => {
  useSchedulerOnce(() => {
    buttons[index].x = buttons[index].initX + Math.random()
    buttons[index].y = buttons[index].initY + Math.random()
    buttons[index].index = -1
    buttons[index].ans = null
  })
}

const touchStart = (item: Buttons) => {
  // viewZindex.value.moveView = viewZindex.value.quesView + 1
  viewZindex.value.moveView = viewZindex.value.magnifierView + 1
  useSchedulerOnce(() => {
    state.zIndex ++
    item.zIndex = state.zIndex
  })
}

// 按钮脱手
const touchend = (ev: TouchEvent, item: Buttons) => {

  if (item.disabled) return

  const { x: itemX, y: itemY } = TPos(ev.changedTouches[0].pageX, ev.changedTouches[0].pageY)
  
  // 返回原点 (没有放在答案区， 按钮回到初始位置)
  if (itemX < quesRef.value?.width! || itemY > ansRef.value?.height! ) {
    disPatchButtonGoInitPos(item.id)
  } else  {
  
    const index = getButtonIndex(itemY <= 0 ? 0 : itemY)
    
    const { x: targetX, y: targetY } = getButtonPosByIndex(index)
    
    //  直接点击答案区的按钮，答案区按钮回到初始位置
    if (item.x == targetX && item.y == targetY) {
      // disPatchButtonGoInitPos(item.id)
    } else {

      // 两个按钮都在答案区， 直接进行按钮之间的交换
      const isHasIndex = buttons.findIndex(button => button.index == index && button.id !== item.id ) 
      
      if (isHasIndex >= 0) { // 答案区的目标区域存在按钮
     
        if (item.index == -1) { // 答案区的目标区域存在按钮 操作按钮是从待操作区域移过来的 目标按钮回到原位
          // disPatchButtonGoInitPos(isHasIndex)
        } else {  // 答案区的目标区域存在按钮 操作按钮是和目标按钮互换位置
          // useSchedulerOnce(() => {
          //   const oldPos = getButtonPosByIndex(item.index)
          //   buttons[isHasIndex].x = oldPos.x
          //   buttons[isHasIndex].y = oldPos.y



          //   buttons[isHasIndex].index = item.index
          // })
        }
      }

      // 将按钮放置到答案区对应的位置
      useSchedulerOnce(() => {
        item.x = targetX
        item.y = targetY
        item.index = index
      })

      checkAns(index, item)

    }
  }


  // 每次松手后把题卡的zIndex提高1
  // viewZindex.value.quesView = viewZindex.value.moveView + 1

  // 每次松手后把放大镜的zIndex提高1
  viewZindex.value.magnifierView = viewZindex.value.moveView + 1

}

// 判断答案 (学习计划适用逻辑)
const checkAns = (index: number, itemData: Buttons) => {
  const targetData = props.board.ansList
  
  // 移动到了正确位置
  if (targetData[index].ans === itemData.color) {
    itemData.ans = targetData[index].color
    
    calcQuantityStore.correctQuantity++

    AudioController.playCorrect()
    itemData.disabled = true

  } else { // 移动到了錯誤位置

    AudioController.playWrong()

    calcQuantityStore.wrongCount++

    itemData.disabled = true

    itemData.ans = null

    const rockNode = document.getElementById(`rock-id-${itemData.id}`)

    rockNode?.classList.add('rock-button-ani')

    useSchedulerOnce(() => {
      disPatchButtonGoInitPos(itemData.id)
      rockNode?.classList.remove('rock-button-ani')
      itemData.disabled = false
    }, 1000)
  }
  
  calcQuantityStore.totalQuantity++

  // 全部正确后触发提交答案的emit

  const ansLen = buttons.filter( button => button.ans).length

  if ( ansLen === ( props.cardType === 0 ? 4 : 6 )) {
    emits('submit')
  }
}

/**
 * @description 放在onMounted生命周期里就可以生效，功能：把题卡放大缩小
 * @description 需要在touchStart时 设置 viewZindex.value.moveView = viewZindex.value.quesView + 1 
 * @description 需要在touchend时 设置  viewZindex.value.quesView = viewZindex.value.moveView + 1
 */
const createHammer = () => {
  var square = document.querySelector('#ques-url');
  var hammer = new Hammer(square);
  hammer.get('pinch').set({ enable: true });
  
  hammer.on('pinchmove pinchstart pinchin pinchout', (e) => {
    if (e.type == "pinchstart") { 
      hammerState.scaleIndex = hammerState.scaleCount || 1
    }
    if (hammerState.scaleIndex * e.scale <= 1) {
      hammerState.scaleCount  = 1
      hammerState.scaleIndex = 1
      return
    }
  
    hammerState.scaleCount = hammerState.scaleIndex * e.scale;
    
    document.getElementById('quesRef')!.style.transform = `scale(${hammerState.scaleIndex * e.scale})`
  })

  hammer.on('panright panleft panup pandown', (e) => {
    document.getElementById('quesRef')!.style.transform = "translateX(" + (e.deltaX + hammerState.x) + "px)" + "translateY(" + (e.deltaY + hammerState.y) + "px)" + "scale(" + (hammerState.scaleCount) + ")"; 
  });

  hammer.on('doubletap', (e) => {
    hammerState.x = 0;
    hammerState.y = 0;
    hammerState.scaleCount = 1; // 重置缩放比例为1
    document.getElementById('quesRef')!.style.transform = "translateX(0px) translateY(0px) scale(1)"; // 重置位置和缩放效果
  });

  hammer.on('panend', (e) => {
    hammerState.x = e.deltaX + hammerState.x; // 记录水平方向上的偏移量
    hammerState.y = e.deltaY + hammerState.y; // 记录垂直方向上的偏移量
    
    const node = document.getElementById('quesRef')
 
    if (hammerState.scaleCount <= 1) {
 
      node!.style.transform = `translateX(0px) translateY(0px) scale(1)`
      hammerState.x = 0
      hammerState.y = 0
      hammerState.scaleCount = 1
      hammerState.scaleIndex  = 1
    } else {
      detectionEdge(0, 0)
    }
  });


  // 放大后拖拽露出边缘后, 回弹的判定函数 回弹条件是当前放大的倍数 * 题卡的（宽/高）
  const detectionEdge = (x: number, y: number) => {
    const node = document.getElementById('quesRef')

    const top = (quesRef.value?.height! * hammerState.scaleCount -  quesRef.value?.height!) / 2
    const bottom = -top
    const left = (quesRef.value?.width! * hammerState.scaleCount -  quesRef.value?.width!) / 2
    const right = -left
   

    if ( Math.abs(hammerState.y)  > top) {
      hammerState.y = hammerState.y > 0 ? top: bottom
    } 
     if ( Math.abs(hammerState.x)  > left) {
      hammerState.x = hammerState.x > 0 ? left: right 
    }

    node!.style.transform = `translateX(${hammerState.x}px) translateY(${hammerState.y}px) scale(${hammerState.scaleCount})`
   
  }

}

let draw = () => {}
let clear = () => {}

// 动态设置canvas的宽高

watch(         
  () => props.magnifierState,
  () => {
    if (props.magnifierState) {
      draw()
      viewZindex.value.magnifierView = viewZindex.value.moveView + 1
    } else {
      clear()
      viewZindex.value.moveView = viewZindex.value.magnifierView + 1
    }
    
  }
)

/**
 * 题卡的放大镜功能
 */

const createMagnifier = () => {
  useMagnifier(
      document.getElementById('magnifier-canvas') as HTMLCanvasElement, 
      'magnifier-canvas',
      {
        ansUrl:  props.board.ansUrl,
        quesUrl:  props.board.quesUrl,
        instance: getCurrentInstance()!,
        rate: rate
      }
  ).then(r => {
    draw = r.draw
    clear = r.clear
  })
}

onMounted(() => {
  useSchedulerOnce(() => {
    createMagnifier()
  }, 1000)
})

</script>

<style lang="less" scoped >
.luojigou-board {
  width: 714rpx;
  height: 1234rpx;
  position: relative;
  display: flex;
  justify-content: center;
  .board {
      width: 714rpx;
      height: 1234rpx;
      position: relative;
      .board-img {
        width: 100%;
        height: 100%;
        position: absolute;
        top: 0;
        left: 0;
        z-index: 1;
      }
      .board-header {
        width: 100%;
        height: 148rpx;
        position: relative;
        top: 7rpx;
        z-index: 32;
        .trumpt {
          width: 96rpx;
          height: 96rpx;
          position: relative;
          top: 44rpx;
          left: 54rpx;
          .dog {
            width: 96rpx;
            height: 96rpx;
            position: absolute;
            z-index: 1;
          }
          .trumpt-icon {
            // width: 40rpx;
            // height: 40rpx;
            position: absolute;
            z-index: 2;
            right: -12rpx;
            bottom: -6rpx;
          }
        }
        .tip {
          width: 490rpx;
          height: 72rpx;
          font-size: 24rpx;
          font-family: PingFangSC-Medium, PingFang SC;
          font-weight: 500;
          color: #ffffff;
          position: absolute;
          top: 50rpx;
          left: 176rpx;
        }
        .luojigou-dog {
          width: 84rpx;
          height: 84rpx;
          position: absolute;
          right: 46rpx;
          top: -48rpx;
        }
      }
      .card {
        position: absolute;
        top: 206rpx;
        left: 26rpx;
        z-index: 2;
        width: 450rpx;
        height: 772rpx;
        overflow: hidden;
        border-top-left-radius: 40rpx;
        border-bottom-left-radius: 40rpx;
      }
      .ques {
        width: 450rpx;
        height: 772rpx;
        border-right: 2rpx solid #006CAA;
        border-top-left-radius: 40rpx;
        border-bottom-left-radius: 40rpx;
        overflow: hidden;
        touch-action: none !important;
        scale: 1;
        box-sizing: border-box;
        image {
          width: 100%;
          height: 100%;
          display: block;
          // border-top-left-radius: 40rpx;
          // border-bottom-left-radius: 40rpx;
        }
      }
      .ans {
        width: 150rpx;
        height: 772rpx;
        display: flex;
        flex-direction: column;
        border-top-right-radius: 40rpx;
        border-bottom-right-radius: 40rpx;
        overflow: hidden;
        background-color: #fff;
        position: absolute;
        top: 206rpx;
        left: 476rpx;
        z-index: 2;
        image {
            width: 100%;
            height: 100%;
            object-fit: cover;
          }
      }
      #magnifier-canvas {
        position: absolute;
        top: 206rpx;
        left: 26rpx;
        z-index: 30;
        /deep/ .uni-canvas-canvas {
          border-radius: 40rpx;
        }
      }
      .ans .ans-item:last-child {
        border-bottom: none
      }
      .buttons {
        position: relative;
        top: 200rpx;
        left: 20rpx;
        width: 680rpx;
        height: 1000rpx;
        image {
          position: absolute;
          left: 0;
          top: 0;
        }
      }

      .movable-area {
        width: 714rpx;
        height: 984rpx;
        background-color: transparent;
        position: absolute;
        top: 192rpx;
        z-index: 30;
        touch-action: none;
        left: 0px;
        -moz-transform: none;
        -webkit-transform: none;
        -o-transform: none;
        -ms-transform: none;
        transform: none;
        transform-origin: 0% 0%;
        .movable-view {
          width: 92rpx;
          height: 92rpx;
          touch-action: none;
          .movable-image {
            width: 100%;
            height: 100%;
            transition: width 0.2s;
            z-index: 1;
          }

          .success-flag {
            width: 36rpx;
            height: 26rpx;
            display: block;
            position: absolute;
            top: 50%;
            left: 50%;
            transform: translate(-50%, -50%);
            z-index: 2;
          }
        }
      }
  }

  .mark-button {
    width: 100%;
    height: 100%;
    position: absolute;
    top: 0px;
    left: 0px;
    z-index: 29;
    .movable-image {
      position: absolute;
      width: 92rpx;
      height: 92rpx;
      display: block;
    }
  }

  .opra {
    width: 100vw;
    height: 1216rpx;
    background: url('../../assets/boardBg.png');
    display: flex;
    justify-content: center;
    padding-top: 46rpx;
  }
}


.rock-button-ani {
  animation: rock 1s;
}

@keyframes rock {
  0% {
    rotate: 0deg;
  }
  25% {
   
    rotate: -10deg;
  }
  50% {
    rotate: 10deg;
  }
  75% {
    rotate: -10deg;
  }
  100% {
    rotate: 0deg;
  }
}


/deep/ .uni-scroll-view-content {
  display: flex;
  align-items: center;
}



</style>