<route lang="json5">
{
  style: {
    navigationStyle: 'custom',
    navigationBarTitleText: '',
  },
}
</route>
<script setup lang="ts">
import WebApp from '@twa-dev/sdk'

// === 类型定义 ===
interface Note {
  id: number
  lane: number
  position: number
  type: string
}

// === 状态管理 ===
const classData = ref<string>('')
const speed = ref(0)
const isContinuous = ref(false)
const isMiss = ref(false)
const score = ref(0)
const isPlaying = ref(false)
const activeTab = ref('one')
const continuousData = ref(0)
const dz = ref(-1)
const remainingTime = ref(45)
const screenHeight = ref(0)
const statusBarHeight = ref(0)
const isLoading = ref(true)
const loadingProgress = ref(0)
const isAudioReady = ref(false)
const showStartButton = ref(false) // 新增：控制开始按钮显示
const gameStarted = ref(false) // 新增：控制游戏是否已经开始过

// === 音频管理 ===
const musicType = ref<number>(Math.floor(Math.random() * 3) + 1)
const bgm = ref<UniApp.InnerAudioContext>()
const missSound = ref<UniApp.InnerAudioContext>()

const audioSources = {
  bgm: {
    1: '/static/audio/play.mp3',
    2: '/static/audio/play.mp3',
    3: '/static/audio/play.mp3',
  },
  effects: {
    miss: '/static/audio/miss.mp3',
  },
}

// === 游戏状态 ===
const activeNotes = ref<Note[]>([])
const pressedKeys = ref(Array(4).fill(false))
const buttons = ['A', 'B', 'C', 'D']
const buttonTypes = buttons.map((b) => b.toLowerCase())

let timerInterval: number | null = null
let animationFrame: number | null = null
let lastTime = 0
let noteId = 0

// === 计算属性 ===
const containerStyle = computed(() => ({
  height: `${screenHeight.value - statusBarHeight.value}px`,
  backgroundSize: '100% 100%',
}))

const playButtonSrc = computed(() =>
  isPlaying.value ? '/static/images/play/stop.png' : '/static/images/play/start.png',
)
// 添加倒计时相关的计算属性
const showCountdown = computed(() => {
  return remainingTime.value <= 10 && remainingTime.value > 0
})

const countdownClass = computed(() => {
  return {
    'text-red-500': remainingTime.value <= 3,
    'text-yellow-500': remainingTime.value > 3 && remainingTime.value <= 5,
    'text-white': remainingTime.value > 5,
  }
})
// === 音频管理方法 ===
const initBGM = () => {
  const audio = uni.createInnerAudioContext()
  audio.src = audioSources.bgm[musicType.value]
  audio.loop = true
  audio.autoplay = false
  audio.obeyMuteSwitch = false

  // 音频事件监听
  audio.onError((res) => {
    console.error('BGM error:', res)
  })

  return audio
}

const initSoundEffect = () => {
  const audio = uni.createInnerAudioContext()
  audio.src = audioSources.effects.miss
  audio.autoplay = false
  audio.obeyMuteSwitch = false

  audio.onError((res) => {
    console.error('Sound effect error:', res)
  })

  return audio
}

const initializeAudio = async () => {
  isLoading.value = true
  loadingProgress.value = 0

  return new Promise<void>((resolve) => {
    try {
      bgm.value = initBGM()
      missSound.value = initSoundEffect()

      let loadedCount = 0
      const checkLoaded = () => {
        loadedCount++
        loadingProgress.value = loadedCount * 50
        if (loadedCount >= 2) {
          isAudioReady.value = true
          showStartButton.value = true
          isLoading.value = false
          resolve()
        }
      }

      bgm.value.onCanplay(() => {
        checkLoaded()
      })

      missSound.value.onCanplay(() => {
        checkLoaded()
      })

      setTimeout(() => {
        if (!isAudioReady.value) {
          isAudioReady.value = true
          showStartButton.value = true
          isLoading.value = false
          resolve()
        }
      }, 2000)
    } catch (e) {
      console.error('Audio init error:', e)
      isLoading.value = false
      showStartButton.value = true
      resolve()
    }
  })
}

const playBGM = async () => {
  if (!bgm.value || !isAudioReady.value) return

  try {
    bgm.value.seek(0)
    await new Promise<void>((resolve) => {
      setTimeout(() => {
        if (bgm.value) {
          bgm.value.play()
          resolve()
        }
      }, 100)
    })
  } catch (e) {
    console.error('Play BGM error:', e)
  }
}

const playMissSound = () => {
  if (!missSound.value || !isAudioReady.value) return

  try {
    missSound.value.stop()
    missSound.value.seek(0)
    setTimeout(() => {
      missSound.value?.play()
    }, 50)
  } catch (e) {
    console.error('Play sound effect error:', e)
  }
}

// === 游戏核心逻辑 ===
const getLanePosition = (lane: number) => {
  const buttonWidth = 90
  const spacing = 80
  const startX = 100
  return startX + lane * (buttonWidth + spacing)
}

const gameLoop = (timestamp: number) => {
  if (!isPlaying.value) return

  const deltaTime = timestamp - lastTime
  if (deltaTime >= 16) {
    updateNotes()
    lastTime = timestamp
  }

  animationFrame = requestAnimationFrame(gameLoop)
}

const updateNotes = () => {
  if (!isPlaying.value) return

  activeNotes.value = activeNotes.value.filter((note) => {
    const moveSpeed = activeTab.value === 'one' ? 5 : activeTab.value === 'two' ? 6 : 7

    note.position += moveSpeed

    const endPosition = screenHeight.value + 290
    if (note.position > endPosition) {
      playMissSound()
      handleMiss()
      return false
    }

    return true
  })
}

const generateNotes = () => {
  if (!isPlaying.value) return

  spawnNote()
  speed.value = musicType.value === 1 ? 600 : musicType.value === 2 ? 1000 : 800

  setTimeout(generateNotes, speed.value)
}

const spawnNote = () => {
  if (!isPlaying.value) return

  const lane = Math.floor(Math.random() * buttons.length)
  activeNotes.value.push({
    id: noteId++,
    lane,
    position: -134,
    type: buttonTypes[lane],
  })
}

// === 游戏控制 ===
const startGame = async () => {
  if (!isAudioReady.value || gameStarted.value) return

  gameStarted.value = true
  showStartButton.value = false
  isPlaying.value = true
  remainingTime.value = 45 // 确保每次开始时重置为45秒

  try {
    await playBGM()

    if (!animationFrame) {
      lastTime = performance.now()
      animationFrame = requestAnimationFrame(gameLoop)
      startTimer()
      generateNotes()
    }
  } catch (e) {
    console.error('Start game error:', e)
  }
}

const pauseGame = () => {
  isPlaying.value = false

  if (bgm.value) {
    bgm.value.pause()
  }

  if (animationFrame) {
    cancelAnimationFrame(animationFrame)
    animationFrame = null
  }
  stopTimer()
}

const handleKeyPress = (index: number) => {
  pressedKeys.value[index] = true

  const endPosition = screenHeight.value + 230
  const hitbox = 150

  activeNotes.value = activeNotes.value.filter((note) => {
    if (note.lane === index && Math.abs(note.position - endPosition) < hitbox) {
      dz.value = note.lane
      score.value += 1
      shake()
      continuous()
      return false
    }
    return true
  })

  setTimeout(() => {
    pressedKeys.value[index] = false
  }, 100)
}

const handleMiss = () => {
  isMiss.value = true
  isContinuous.value = false
  continuousData.value = 0

  setTimeout(() => {
    isMiss.value = false
  }, 500)
}

const continuous = () => {
  if (continuousData.value < 8) {
    isContinuous.value = true
    setTimeout(() => {
      isContinuous.value = false
    }, 500)
    continuousData.value += 1
  } else {
    setTimeout(() => {
      continuousData.value = 0
    }, 500)
  }
}

const shake = () => {
  if (WebApp.HapticFeedback) {
    WebApp.HapticFeedback.impactOccurred('medium')
  } else {
    console.info('🚀 ~ file:game method:shake line:340 -----', 11)
    uni.vibrateShort({
      success: function () {},
      fail: function () {},
    })
  }
}

const togglePause = () => {
  if (!gameStarted.value) return

  isPlaying.value = !isPlaying.value
  if (isPlaying.value) {
    // 继续游戏
    if (bgm.value) {
      bgm.value.play()
    }
    lastTime = performance.now()
    animationFrame = requestAnimationFrame(gameLoop)
    startTimer()
    generateNotes()
  } else {
    pauseGame()
  }
}

// === 计时器控制 ===
const startTimer = () => {
  if (!timerInterval) {
    timerInterval = setInterval(() => {
      if (remainingTime.value <= 0) {
        gameOver()
        return
      }
      remainingTime.value--
    }, 1000)
  }
}

const stopTimer = () => {
  if (timerInterval) {
    clearInterval(timerInterval)
    timerInterval = null
  }
}

const gameOver = () => {
  gameStarted.value = false
  isPlaying.value = false
  pauseGame()
  stopTimer()

  uni.redirectTo({
    url: `/pages/play/detail?correct=${classData.value}&score=${score.value}`,
  })
}

const cleanupAudio = () => {
  try {
    if (bgm.value) {
      bgm.value.stop()
      bgm.value.destroy()
    }
    if (missSound.value) {
      missSound.value.stop()
      missSound.value.destroy()
    }
  } catch (e) {
    console.error('Cleanup audio error:', e)
  }
}

const back = () => {
  gameStarted.value = false
  pauseGame()
  cleanupAudio()
  uni.navigateTo({
    url: '/pages/play/index',
  })
}

// === 生命周期钩子 ===
onMounted(async () => {
  const systemInfo = uni.getSystemInfoSync()
  screenHeight.value = systemInfo.windowHeight
  statusBarHeight.value = systemInfo.statusBarHeight || 0

  uni.onWindowResize(() => {
    screenHeight.value = uni.getSystemInfoSync().windowHeight
  })

  await initializeAudio()
})

onLoad((res) => {
  if (res.correct) {
    classData.value = res.correct
  }
  if (res.activeTab) {
    activeTab.value = res.activeTab
  }
})

onUnmounted(() => {
  pauseGame()
  stopTimer()
  cleanupAudio()
})
</script>
<template>
  <image src="/static/images/play/bg.jpg" class="w-100% h-100% absolute" />
  <view class="flex flex-col items-center relative" :style="containerStyle">
    <!-- 加载遮罩和开始按钮 -->
    <view
      v-if="(isLoading || showStartButton) && !gameStarted"
      class="fixed inset-0 bg-black/50 flex flex-col items-center justify-center z-50 transition-all duration-300"
    >
      <template v-if="isLoading">
        <view class="text-white text-xl mb-4">
          <view class="flex items-center">
            <view class="loading-spinner mr-2"></view>
            <text>loading... {{ loadingProgress }}%</text>
          </view>
        </view>
      </template>

      <template v-else-if="showStartButton && !gameStarted">
        <view
          class="relative w-240rpx h-80rpx rounded-lg overflow-hidden flex items-center justify-center text-white font-bold shadow-lg cursor-pointer active:scale-95 transition-all duration-300 transform"
          @click="startGame"
          style="background-color: #ffd700; box-shadow: 5px 5px 0px #000000"
        >
          <text
            class="text-3xl tracking-wider"
            style="
              font-family: 'Comic Sans MS', cursive, sans-serif;
              text-shadow: 2px 2px 4px #000000;
            "
          >
            START
          </text>
        </view>
      </template>
    </view>

    <!-- 顶部分数和控制栏 -->
    <view
      class="top-bg w-680rpx h-160rpx rounded-30rpx bg-cardlight m-b mt-20rpx flex items-center justify-around"
    >
      <view @click="back" class="w-80rpx h-80rpx rounded-10rpx flex items-center justify-center">
        <image src="/static/images/play/exit.png" class="w-45rpx h-35rpx" />
      </view>

      <view class="flex flex-col w-150rpx items-center text-white">
        <view class="text-60rpx mb-10rpx">{{ score }}</view>
        <!-- 星星评分 -->
        <view class="flex items-center" v-if="score < parseInt(classData) / 3">
          <image
            v-for="i in 3"
            :key="i"
            src="/static/images/play/no.png"
            mode="scaleToFill"
            class="w-38rpx h-38rpx"
            :class="{ 'mr-1': i !== 3 }"
          />
        </view>

        <view
          class="flex items-center"
          v-else-if="score >= parseInt(classData) / 3 && score < (parseInt(classData) * 2) / 3"
        >
          <image src="/static/images/play/star.png" class="w-38rpx h-38rpx mr-1" />
          <image
            v-for="i in 2"
            :key="i"
            src="/static/images/play/no.png"
            mode="scaleToFill"
            class="w-38rpx h-38rpx"
            :class="{ 'mr-1': i !== 2 }"
          />
        </view>

        <view
          class="flex items-center"
          v-else-if="score >= (parseInt(classData) * 2) / 3 && score < parseInt(classData)"
        >
          <image
            v-for="i in 2"
            :key="i"
            src="/static/images/play/star.png"
            class="w-38rpx h-38rpx mr-1"
          />
          <image src="/static/images/play/no.png" mode="scaleToFill" class="w-38rpx h-38rpx" />
        </view>

        <view class="flex items-center" v-else>
          <image
            v-for="i in 3"
            :key="i"
            src="/static/images/play/star.png"
            class="w-38rpx h-38rpx"
            :class="{ 'mr-1': i !== 3 }"
          />
        </view>
      </view>

      <view
        class="w-80rpx h-80rpx rounded-10rpx opacity-60 flex items-center justify-center"
        @click="togglePause"
      >
        <image :src="playButtonSrc" class="w-22rpx h-27rpx" />
      </view>
    </view>

    <!-- 游戏区域 -->
    <view class="flex-1 w-full relative">
      <!-- 倒计时显示 -->
      <view
        v-if="showCountdown"
        class="absolute top-1/3 left-1/2 transform -translate-x-1/2 -translate-y-1/2 z-50"
      >
        <text
          :class="['text-8xl font-black relative z-10', countdownClass]"
          :style="{
            fontFamily: 'Comic Sans MS',
            textShadow: '2px 2px 4px #000000',
          }"
        >
          {{ remainingTime }}
        </text>
      </view>
      <!-- 连击效果 -->
      <view class="w-100% z-100 absolute text-center">
        <view class="flex flex-col items-center" v-show="isContinuous && continuousData > 1">
          <text
            class="text-yellow-300 text-[60rpx] font-black"
            :style="{
              fontFamily: 'Comic Sans MS',
              textShadow: '2px 2px 4px #000000',
              transform: `scale(${1 + continuousData / 20})`,
            }"
          >
            {{ continuousData }}
          </text>
          <text
            class="text-white text-[40rpx] font-bold tracking-wider"
            style="font-family: 'Impact', sans-serif"
          >
            COMBO
          </text>
          <view
            class="w-40rpx h-40rpx rounded-full bg-yellow-400 absolute -top-10rpx -left-10rpx blur-[30rpx]"
          ></view>
        </view>

        <view
          v-show="isMiss"
          class="text-red-500 text-[80rpx] font-black tracking-widest relative z-10"
          style="font-family: 'Impact', sans-serif"
        >
          <text
            style="
              font-family: 'Comic Sans MS', cursive, sans-serif;
              text-shadow: '2px 2px 4px #000000';
              font-size: 36rpx;
            "
          >
            MISS!
          </text>
          <view
            class="w-60rpx h-60rpx rounded-full bg-red-600 absolute -bottom-10rpx -right-10rpx blur-[30rpx]"
          ></view>
        </view>

        <text
          v-show="continuousData >= 8 && !isContinuous"
          class="text-[60rpx] text-green-400 font-black tracking-wider relative z-10"
          style="
            font-family: 'Comic Sans MS', cursive, sans-serif;
            text-shadow: '2px 2px 4px #000000';
          "
        >
          Good!
          <view
            class="w-50rpx h-50rpx rounded-full bg-green-500 absolute -top-10rpx -right-10rpx blur-[30rpx]"
          ></view>
        </text>
      </view>

      <!-- 音符区域 -->
      <view class="w-full h-full absolute top-0 left-0 overflow-hidden">
        <view
          v-for="note in activeNotes"
          :key="note.id"
          class="absolute note"
          :style="{
            left: `${getLanePosition(note.lane) - 25}rpx`,
            top: `${note.position}rpx`,
            opacity: 1 - Math.max(0, (note.position - 200) / 1000), // 模拟景深效果
            transform: `scale(${1 + Math.max(0, (100 - note.position) / 200)})`, // 模拟弹跳效果
          }"
        >
          <image :src="`/static/images/play/${note.type}.png`" class="w-92rpx h-150rpx" />
        </view>
      </view>
    </view>

    <!-- 底部按键区域 -->
    <view
      class="absolute overflow-hidden bottom-20rpx w-680rpx h-195rpx rounded-30rpx flex items-center justify-around"
    >
      <view v-for="(key, index) in buttons" :key="index">
        <image
          src="`/static/images/play/tong.png`"
          :style="{ color: pressedKeys[index] ? '#0E0E0E' : '#fff' }"
          :class="[
            'w-150rpx h-175rpx rounded-20rpx flex items-center justify-center text-32rpx fw-550 relative z-[10]',
            pressedKeys[index] ? 'anniu-custom-ac' : 'anniu-custom',
          ]"
          @tap="handleKeyPress(index)"
        />
        <image
          v-show="isContinuous && index == dz"
          src="/static/images/play/bz.png"
          mode="scaleToFill"
          class="w-160rpx h-160rpx absolute mt-[-160rpx] ml-[-15rpx] z-[11]"
          :class="{ 'img-bz': isContinuous }"
        />
      </view>
    </view>
  </view>
</template>

<style lang="scss" scoped>
.m-b {
  border: 1px solid #686868;
}

.m-b-b {
  background: transparent;
  background-color: rgba(132, 132, 133, 0.8);
  backdrop-filter: blur(30px);
  -webkit-backdrop-filter: blur(30px);
}

.m-b-b-no {
  background: transparent;
  background-color: rgba(255, 0, 0, 0.15);
  border: 1px solid #ff0000;
  backdrop-filter: blur(30px);
  -webkit-backdrop-filter: blur(30px);
}

.anniu-custom {
  background: #555;
  transition: all 0.2s ease;

  &:active {
    transform: scale(0.95);
  }
}

.anniu-custom-ac {
  background: var(--primary-color);
  transition: all 0.2s ease;
  transform: scale(0.95);
}

.note {
  transition: top 16ms linear;
  transform: translateZ(0);
  will-change: top;

  &.fade-enter-active,
  &.fade-leave-active {
    transition: opacity 0.3s ease;
  }

  &.fade-enter-from,
  &.fade-leave-to {
    opacity: 0;
  }
}

.text {
  background-image: linear-gradient(#ffffff, #2fbec7);
  -webkit-background-clip: text;
  background-clip: text;
  -webkit-text-fill-color: transparent;
  animation: resizeText 0.7s 1;
}

.miss-text {
  background-image: linear-gradient(#ffffff, #ff0000);
  -webkit-background-clip: text;
  background-clip: text;
  -webkit-text-fill-color: transparent;
  animation: resizeText 0.7s 1;
}

@keyframes resizeText {
  0% {
    font-size: 0rpx;
    opacity: 0;
    transform: scale(0.5);
  }
  50% {
    opacity: 1;
    transform: scale(1.2);
  }
  100% {
    font-size: 50rpx;
    transform: scale(1);
  }
}

.continuous-number {
  animation: number 0.5s 1;
}

@keyframes number {
  0% {
    font-size: 0rpx;
    opacity: 0;
    transform: translateY(20rpx);
  }
  50% {
    opacity: 1;
    transform: translateY(-10rpx);
  }
  100% {
    font-size: 50rpx;
    transform: translateY(0);
  }
}

@keyframes fireworks {
  0% {
    transform: scale(0);
    opacity: 0;
  }
  50% {
    opacity: 1;
    transform: scale(1.2);
  }
  100% {
    transform: scale(1);
  }
}

.img-bz {
  animation: fireworks 0.2s ease-out forwards;
}

// 添加全局过渡效果
.fade-enter-active,
.fade-leave-active {
  transition: opacity 0.3s ease;
}

.fade-enter-from,
.fade-leave-to {
  opacity: 0;
}

// 添加加载动画
@keyframes spin {
  0% {
    transform: rotate(0deg);
  }
  100% {
    transform: rotate(360deg);
  }
}

.loading-spinner {
  width: 24rpx;
  height: 24rpx;
  border: 4rpx solid #ccc;
  border-radius: 50%;
  border-top-color: #333;
  animation: spin 1s linear infinite;
}

// 添加倒计时动画样式
.countdown-animation {
  animation: countdown-pulse 1s ease-in-out infinite;
  text-shadow: 0 0 10px rgba(255, 255, 255, 0.5);
}

@keyframes countdown-pulse {
  0% {
    transform: scale(1);
    opacity: 1;
  }
  50% {
    transform: scale(1.2);
    opacity: 0.8;
  }
  100% {
    transform: scale(1);
    opacity: 1;
  }
}

.top-bg {
  box-shadow: 0px 4px 4px 0px rgba(255, 255, 255, 0.25);
  backdrop-filter: blur(6.099999904632568px);
}
</style>
