<template>
  <div
    class="jigsaw-game"
    :class="{
      celebrating: isCelebrating,
    }"
  >
    <div class="left-wrapper">
      <div
        v-loading="isLoading"
        class="object-wrapper"
      >
        <object
          ref="svgContainer"
          :data="require(`@/assets/images/jigsaw-game-${$route.query.sceneL2Idx}/compound.svg`)"
          type=""
        />
      </div>
      <div
        ref="forDrop"
        class="for-drop"
        :style="{
          left: leftForDrop + 'px',
          top: topForDrop + 'px',
          width: widthForDrop + 'px',
          height: heightForDrop + 'px',
        }"
        @dragover.prevent
        @drop.prevent="onDrop"
      />
      <button
        v-click-audio
        class="replay"
        @click="onClickReplay"
      />
    </div>

    <div class="jigsaw-list">
      <h1>
        <img
          class=""
          :src="require(`@/assets/images/title-level2-${$route.query.sceneL2Idx}.png`)"
          alt=""
          draggable="false"
        >
      </h1>
      <li
        v-for="(jigsawItem, idx) in jigsawItems"
        :key="idx"
      >
        <img
          class=""
          :style="{
            cursor: !jigsawProgressSceneL2.isJigsawDone && (activeJigsawIdx === (Number(jigsawItem.name.split('.')[0]) - 1)) ? 'grab' : 'default',
            filter: !jigsawProgressSceneL2.isJigsawDone && !jigsawItem.hasPut ? '' : 'brightness(0.5)',
          }"
          :src="require(`@/assets/images/jigsaw-game-${$route.query.sceneL2Idx}/jigsaw/${jigsawItem.name}`)"
          alt=""
          :draggable="!jigsawProgressSceneL2.isJigsawDone && (activeJigsawIdx === (Number(jigsawItem.name.split('.')[0]) - 1)) ? true : false"
          @dragstart="(e) => {
            onDragStart(e, jigsawItem.name, idx)
          }"
          @dragend="onDragEnd(jigsawItem.name)"
        >
        <div
          v-if="!jigsawItem.name.includes('chuan') && !jigsawItem.name.includes('lin')"
          class="jigsaw-name"
          :title="jigsawItem.name.split('.')[1]"
        >
          {{ jigsawItem.name.split('.')[1] }}
        </div>
        <div
          v-if="jigsawItem.name.includes('chuan')"
          class="jigsaw-name"
          :title="jigsawItem.name.split('.')[1].replace('chuan', 'chuán')"
        >
          {{ jigsawItem.name.split('.')[1].split('（')[0] }}（<span style="font-family: pinyin">chuán</span>）{{ jigsawItem.name.split('.')[1].split('）')[1] }}
        </div>
        <div
          v-if="jigsawItem.name.includes('lin')"
          class="jigsaw-name"
          :title="jigsawItem.name.split('.')[1].replace('lin', 'lǐn')"
        >
          {{ jigsawItem.name.split('.')[1].split('（')[0] }}（<span style="font-family: pinyin">lǐn</span>）{{ jigsawItem.name.split('.')[1].split('）')[1] }}
        </div>
      </li>
    </div>
    <audio
      v-show="false"
      ref="audio-drop-effect"
      class="drop-effect"
      :src="require(`@/assets/audios/drop-effect.mp3`)"
    />
    <audio
      v-show="false"
      ref="complete-tip"
      class="complete-tip"
      :src="require(`@/assets/audios/complete-tip.mp3`)"
    />
    <Teleport
      to="body"
    >
      <transition
        name="fade-in-out"
      >
        <div
          v-if="isCelebrating"
          class="celebrate"
        >
          <img
            class=""
            src="@/assets/images/celebrate.gif"
            alt=""
            draggable="false"
          >
        </div>
      </transition>
    </Teleport>
  </div>
</template>

<script>
import useWindowSizeAdaptor from '@/useFunctions/useWindowSizeAdaptor.js'
import { shuffle } from "lodash"

export default {
  name: 'JigsawGame',
  setup () {
    const { windowSizeWhenDesign, unit } = useWindowSizeAdaptor()

    return {
      windowSizeWhenDesign,
      unit
    }
  },
  data() {
    return {
      jigsawItems: [],
      activeJigsawIdx: 0,
      leftForDrop: 0,
      topForDrop: 0,
      widthForDrop: 0,
      heightForDrop: 0,
      imgFrameThicknessWhenDesign: '15',
      isCelebrating: false,
      isLoading: true,
    }
  },
  computed: {
    ...mapState([
      'gameProgress',
    ]),
    jigsawProgressSceneL2() {
      return this.gameProgress.jigsawProgress[Number(this.$route.query.sceneL2Idx)]
    },
  },
  mounted() {
    if (this.jigsawProgressSceneL2.isJigsawDone) {
      this.isLoading = false
    }
    this.resetStatus()
  },
  unmounted() {
  },
  methods: {
    ...mapMutations([
      'recordJigsawDone',
      'replayJigsaw',
    ]),
    resetStatus(needDelay = true) {
      this.activeJigsawIdx = 0
      this.jigsawItems = shuffle(config.sceneTree[Number(this.$route.query.sceneL2Idx)].jigsawList.map((item) => {
        return {
          name: item,
          hasPut: false,
        }
      }))
      if (needDelay) {
        setTimeout(() => {
          if (!this.jigsawProgressSceneL2.isJigsawDone) {
            this.hideAllInSvg()
          }
        }, 1000)
      } else {
        setTimeout(() => {
          if (!this.jigsawProgressSceneL2.isJigsawDone) {
            this.hideAllInSvg()
          }
        }, 100)
      }
    },
    hideAllInSvg() {
      const objectDocument = this.$refs.svgContainer.contentDocument
      const gList = objectDocument.getElementsByTagName('g')
      for (let index = 1; index < gList.length; index++) {
        const element = gList[index]
        element.setAttribute('visibility', 'hidden')
      }
      this.isLoading = false
    },
    onDragStart(e, jigsawImgName, idx) {
      // 不知道为啥，在svg内部元素上无法触发drop事件，求助gpt也没用。只好用一个透明方块放在需要能drop的svg内部元素上面。

      // reset div for drop
      this.leftForDrop = 0
      this.topForDrop = 0
      this.widthForDrop = 0
      this.heightForDrop = 0

      // get id
      let temp = jigsawImgName.split('.')
      temp.pop()
      const id = `_${temp.join('.')}-剪影_图像`

      // get elements
      const objectDocument = this.$refs.svgContainer.contentDocument
      const svgEl = objectDocument.getElementsByTagName('svg')[0]
      const gTarget = objectDocument.getElementById(id)
      const imgTarget = gTarget.getElementsByTagName('image')[0]

      // get svg original size from viewBox attribute
      const svgWidth = Number(svgEl.getAttribute('viewBox').split(' ')[2])
      const svgHeight = Number(svgEl.getAttribute('viewBox').split(' ')[3])
      console.log('svg original size by viewBox attribute: ', svgWidth, svgHeight)

      // show g element
      if (process.env.VUE_APP_CLI_MODE === 'dev') {
        gTarget.setAttribute('visibility', 'show')
      }

      // save drag info
      e.dataTransfer.setData('text/plain', jigsawImgName)
      e.dataTransfer.setData('text/html', String(idx)) // 并非真的html类型，只是为了传输数据

      // get image's original size
      const imageWidthOriginal = Number(imgTarget.getAttribute('width'))
      const imageHeightOriginal = Number(imgTarget.getAttribute('height'))
      console.log("image's original size: ", imageWidthOriginal, imageHeightOriginal)

      // get image's original top left from transform attribute
      let imageLeftOriginal = 0
      let imageTopOriginal = 0
      const transformString = imgTarget.getAttribute('transform')
      if (transformString) {
        const regForTransform = /translate\((.+)\)/
        const matchRes = transformString.match(regForTransform)
        if (matchRes) {
          imageLeftOriginal = Number(matchRes[1].split(' ')[0])
          imageTopOriginal = Number(matchRes[1].split(' ')[1]) || 0
        } else {
          imageLeftOriginal = 0
          imageTopOriginal = 0
        }
      } else {
        imageLeftOriginal = 0
        imageTopOriginal = 0
      }
      console.log("image's original top left: ", imageLeftOriginal, imageTopOriginal)

      // 计算画框粗细
      let imageFrameThicknessActual = 0
      if (this.unit === '100vh') {
        imageFrameThicknessActual = Number(this.imgFrameThicknessWhenDesign) / 1080 * window.innerHeight
      } else {
        imageFrameThicknessActual = Number(this.imgFrameThicknessWhenDesign) / 1920 * window.innerWidth
      }
      console.log("image frame's actual thickness: ", imageFrameThicknessActual)

      // compute image's actual left top
      const topLeft = utils.mapPosFromDraftToWindow({
        x: imageLeftOriginal,
        y: imageTopOriginal,
      }, 'cover', svgWidth, svgHeight, this.$refs.svgContainer.clientWidth, this.$refs.svgContainer.clientHeight)
      console.log("image's actual left top: ", topLeft.x, topLeft.y)

      const rightBottom = utils.mapPosFromDraftToWindow({
        x: imageLeftOriginal + imageWidthOriginal,
        y: imageTopOriginal + imageHeightOriginal,
      }, 'cover', svgWidth, svgHeight, this.$refs.svgContainer.clientWidth, this.$refs.svgContainer.clientHeight)
      console.log("image's actual right top: ", rightBottom.x, rightBottom.y)

      this.leftForDrop = topLeft.x + imageFrameThicknessActual
      this.topForDrop = topLeft.y + imageFrameThicknessActual
      this.widthForDrop = rightBottom.x - topLeft.x
      this.heightForDrop = rightBottom.y - topLeft.y
      console.log("image's actual ltwh for render: ", this.leftForDrop, this.topForDrop, this.widthForDrop, this.heightForDrop)
    },
    onDragEnd(jigsawImgName) {
      let temp = jigsawImgName.split('.')
      temp.pop()
      const id = `_${temp.join('.')}-剪影_图像`
      const objectDocument = this.$refs.svgContainer.contentDocument
      objectDocument.getElementById(id).setAttribute('visibility', 'hidden')
    },
    onDrop(e) {
      e.preventDefault()
      let jigsawImgName = e.dataTransfer.getData('text/plain')
      let temp = jigsawImgName.split('.')
      temp.pop()
      const id = `_${temp.join('.')}_图像`
      const objectDocument = this.$refs.svgContainer.contentDocument
      objectDocument.getElementById(id).setAttribute('visibility', 'show')

      const idx = Number(e.dataTransfer.getData('text/html'))
      this.jigsawItems[idx].hasPut = true

      this.activeJigsawIdx++

      this.$refs['audio-drop-effect'].play()

      if (!this.jigsawItems.find((item) => {
        return !item.hasPut
      })) {
        this.recordJigsawDone(Number(this.$route.query.sceneL2Idx))
        this.$refs['complete-tip'].play()
        setTimeout(() => {
          this.isCelebrating = true
          setTimeout(() => {
            this.isCelebrating = false
          }, 4000)
        }, 0)
      }
    },
    onClickReplay() {
      this.jigsawItems.forEach(element => {
        element.hasPut = false
      })
      this.resetStatus(false)
      this.replayJigsaw(Number(this.$route.query.sceneL2Idx))
    }
  },
}
</script>

<style lang="less">
:root{
  --el-overlay-color-lighter: transparent !important;
  --el-mask-color: #fff !important;
}
</style>
<style lang="less" scoped>
.jigsaw-game {
  position: absolute;
  left: 0;
  top: 0;
  width: 100%;
  height: 100%;
  background-image: url(@/assets/images/bg-game.jpg);
  background-size: cover;
  background-repeat: no-repeat;
  background-position: center center;
  display: flex;
  justify-content: center;
  align-items: center;
  &.celebrating{
    // animation: flash 0.8s forwards;
  }
  // @keyframes flash {
  //   0% {
  //     filter: brightness(1)
  //   }
  //   50% {
  //     filter: brightness(1.1) saturate(1.2)
  //   }
  //   100% {
  //     filter: brightness(1)
  //   }
  // }
  >.left-wrapper {
    width: calc(950 / v-bind('windowSizeWhenDesign') * v-bind('unit'));
    height: calc(628 / v-bind('windowSizeWhenDesign') * v-bind('unit'));
    background-image: url(@/assets/images/bg-jigsaw-game-page-frame.jpg);
    background-size: cover;
    background-repeat: no-repeat;
    background-position: center center;
    margin-right: calc(83 / v-bind('windowSizeWhenDesign') * v-bind('unit'));
    padding: calc(v-bind('imgFrameThicknessWhenDesign') / v-bind('windowSizeWhenDesign') * v-bind('unit'));
    position: relative;
    >.object-wrapper {
      width: 100%;
      height: 100%;
      overflow: hidden;
      >object {
        user-select: none;
        // width: 100%;
      }
    }
    >.for-drop {
      position: absolute;
      // background-color: red;
      // opacity: 0.2;
      z-index: 1;
    }
    >button.replay {
      position: absolute;
      bottom: calc(-30 / v-bind('windowSizeWhenDesign') * v-bind('unit'));
      left: 50%;
      transform: translate(-50%, 100%);
      width: calc(220 / v-bind('windowSizeWhenDesign') * v-bind('unit'));
      height: calc(110 / v-bind('windowSizeWhenDesign') * v-bind('unit'));
      background-image: url(@/assets/images/btn-replay.png);
      background-size: contain;
      background-repeat: no-repeat;
      background-position: center center;
      &:hover{
        transform: translate(-50%, 100%) scale(1.1);
      }
    }
  }
  >.jigsaw-list {
    position: relative;
    width: calc(580 / v-bind('windowSizeWhenDesign') * v-bind('unit'));
    height: calc(648 / v-bind('windowSizeWhenDesign') * v-bind('unit'));
    padding-top: calc(8 / v-bind('windowSizeWhenDesign') * v-bind('unit'));
    overflow: auto;

    >h1 {
      position: absolute;
      left: 0;
      top: calc(-101 / v-bind('windowSizeWhenDesign') * v-bind('unit'));
      height: calc(74 / v-bind('windowSizeWhenDesign') * v-bind('unit'));;
      font-size: 0;
      >img {
        height: 100%;
      }
    }
    >li {
      display: inline-block;
      margin-right: calc(28 / v-bind('windowSizeWhenDesign') * v-bind('unit'));
      margin-bottom: calc(17 / v-bind('windowSizeWhenDesign') * v-bind('unit'));
      text-align: center;
      >img {
        width: calc(157 / v-bind('windowSizeWhenDesign') * v-bind('unit'));
        height: calc(157 / v-bind('windowSizeWhenDesign') * v-bind('unit'));
        background: #fff;
        margin-bottom: calc(15 / v-bind('windowSizeWhenDesign') * v-bind('unit'));
      }
      >.jigsaw-name {
        font-size: calc(20 / v-bind('windowSizeWhenDesign') * v-bind('unit'));
        font-family: Source Han Sans CN-Bold, Source Han Sans CN;
        font-weight: bold;
        color: #C26827;
        overflow: hidden;
        white-space: pre;
        text-overflow: ellipsis;
        user-select: none;
      }
    }
  }
}
</style>

<style lang="less">
.celebrate{
  position: absolute;
  left: 0;
  top: 0;
  width: 100%;
  height: 100%;
  background-color: #fff;
  >img{
    position: absolute;
    left: 50%;
    top: 50%;
    transform: translate(-50%, -50%);
    width: 100%;
    height: 100%;
    object-fit: contain;
  }
}
</style>