<template>
  <div class="lucky-wheel-wrapper" :class="{ 'scale-80': smallerThanXl }">
    <LuckyWheel
      ref="myLucky"
      width="260px"
      height="260px"
      :blocks="blocks"
      :buttons="buttons"
      :prizes="computedPrizes"
      :default-config="defaultConfig"
      :default-style="defaultStyle"
      @end="endCallback"
    />
    <!-- 自定义指针 -->
    <div class="wheel-pointer">
      <div class="pointer-pin" />
      <div class="pointer-dot" />
    </div>
    <button
      class="go-btn"
      :class="{ 'is-spinning': isSpinning }"
      :disabled="isSpinning"
      @click="popClick"
    >
      <span class="go-text">GO</span>
    </button>
  </div>
</template>

<script lang="ts" setup>
import { LuckyWheel } from '@lucky-canvas/vue'
import ringTexture from '@/assets/img/lucky-wheel-outer-ring.svg'
import spinMusic from '@/assets/audio/lucky-wheel-happy-adventure.mp3'
import type { WheelPrizeItemDto, LuckWheelResultDto, WheelConfigDto } from '@/api'
import { participateLuckyWheel, getWheelPrizeList } from '@/api'

import { breakpointsTailwind, useBreakpoints } from '@vueuse/core'
import { useMessageBox } from '@/hooks'
import { useYaBiStore } from '@/stores'
import { push } from 'notivue'
const { wheelConfig } = defineProps<{
  wheelConfig: WheelConfigDto
}>()
const yabiStore = useYaBiStore()
const { confirm } = useMessageBox()

const breakpoints = useBreakpoints(breakpointsTailwind)
const smallerThanXl = breakpoints.smaller('xl')

const wheelPrizeList = ref<WheelPrizeItemDto[]>([])
const emit = defineEmits<{
  handlePrizeResult: [LuckWheelResultDto]
}>()

const myLucky = ref<InstanceType<typeof LuckyWheel>>()

const defaultConfig = {
  offsetDegree: 0,
  speed: 20,
  accelerationTime: 1000,
  decelerationTime: 1000,
}

const defaultStyle = {
  fontColor: '#333',
  fontWeight: 'bold',
  lineHeight: '14px',
  lengthLimit: '60%',
}

const blocks = [
  { padding: '2px', background: '#e8e4ff' },
  {
    padding: '16px',
    background: '#6858ec',
    imgs: [
      {
        src: ringTexture,
        width: '100%',
        height: '100%',
        rotate: true,
      },
    ],
  },
  { padding: '3px', background: '#7b6fef' },
]

const computedPrizes = computed(() => {
  const width = wheelPrizeList.value.length >= 6 ? '37%' : '30%'
  return wheelPrizeList.value.map((item: WheelPrizeItemDto, index: number) => {
    return {
      background: index % 2 === 0 ? '#ffffff' : '#f3f0ff',
      fonts: [
        {
          text: item.name,
          top: '8%',
          fontSize: '10px',
          fontColor: index % 2 === 0 ? '#6858ec' : '#e5a012',
          lineClamp: 1,
        },
      ],
      imgs: [
        {
          src: item.imageUrl,
          width,
          top: '35%',
        },
      ],
      id: item.id,
    }
  })
})

const buttons = [
  { radius: '25%', background: '#fce4e4' },
  { radius: '20%', background: '#f75a5a' },
  {
    radius: '18%',
    background: '#e63939',
    pointer: false,
    fonts: [{ text: '', top: '-14px' }],
  },
]

const isSpinning = ref(false)

let resultPrize: null | LuckWheelResultDto = null
let spinAudio: HTMLAudioElement | null = null

const startSpinMusic = () => {
  stopSpinMusic()
  spinAudio ||= new Audio(spinMusic)
  spinAudio.loop = true
  spinAudio.volume = 0.35
  spinAudio.play().catch(() => {})
}

const stopSpinMusic = () => {
  if (!spinAudio) return

  spinAudio.pause()
  spinAudio.currentTime = 0
}

const startCallback = async () => {
  if (isSpinning.value) return
  isSpinning.value = true

  startSpinMusic()
  myLucky.value?.play()
  setTimeout(async () => {
    try {
      const { data } = await participateLuckyWheel()
      const idx = computedPrizes.value.findIndex((item) => item.id === data.prizeId)
      myLucky.value?.stop(idx)
      yabiStore.fetchYaBiData()
      resultPrize = data
    } catch (error) {
      console.error(error)
      stopSpinMusic()
      isSpinning.value = false
    }
  }, 600)
}

// 获取最新的奖品列表 对比 是否更新了
const popClick = async () => {
  if (isSpinning.value) return
  if (yabiStore.yabiData.currentValue < wheelConfig!.costYaCoin)
    return push.error(
      `您的YA币不足,抽奖所需${wheelConfig!.costYaCoin}YA币,当前YA币${yabiStore.yabiData.currentValue}`,
    )

  const { data } = await getWheelPrizeList()
  const newWheelPrizeList = data
  const oldWheelPrizeList = wheelPrizeList.value
  // 暂时只需要对比 1长度不一致 需要更新 2如果长度一样 如果有一组的名字或者图片 不一样 需要更新
  let shouldUpdate = false
  if (newWheelPrizeList.length !== oldWheelPrizeList.length) {
    shouldUpdate = true
  } else {
    newWheelPrizeList.forEach((item: WheelPrizeItemDto, index: number) => {
      if (
        item.name !== oldWheelPrizeList[index]?.name ||
        item.imageUrl !== oldWheelPrizeList[index]?.imageUrl
      ) {
        shouldUpdate = true
      }
    })
  }
  if (shouldUpdate) {
    // 给用户提示 奖池更新了 请重新点击
    await confirm({
      title: '检测到后台奖池有更新',
      message: '请重新点击按钮开始抽奖',
      type: 'warning',
      showCancelButton: false,
    })
    wheelPrizeList.value = newWheelPrizeList
  } else {
    // 二次确认
    await confirm({
      title: `本次抽奖消耗${wheelConfig?.costYaCoin} YA币，确定开始吗？`,
    })
    startCallback()
  }
}

const endCallback = () => {
  setTimeout(() => {
    isSpinning.value = false
    emit('handlePrizeResult', resultPrize as LuckWheelResultDto)
  }, 280)
}

const initWheelPrizeList = async () => {
  const { data } = await getWheelPrizeList()
  wheelPrizeList.value = data
}
onMounted(() => {
  initWheelPrizeList()
})

onBeforeUnmount(() => {
  stopSpinMusic()
})

defineExpose({
  stopSpinMusic,
})
</script>

<style scoped>
.lucky-wheel-wrapper {
  position: relative;
  display: inline-block;
  width: 260px;
  height: 260px;
  border-radius: 50%;
  box-shadow:
    0 2px 8px rgba(104, 88, 236, 0.6),
    0 0 16px 1px rgba(104, 88, 236, 0.08);
}

.go-btn {
  position: absolute;
  top: 50%;
  left: 50%;
  transform: translate(-50%, -50%);
  width: 50px;
  height: 50px;
  border-radius: 50%;
  border: 3px solid #ff8a80;
  background: linear-gradient(145deg, #ff5252, #d32f2f);
  box-shadow:
    0 4px 12px rgba(211, 47, 47, 0.5),
    inset 0 2px 4px rgba(255, 255, 255, 0.3);
  cursor: pointer;
  z-index: 10;
  transition: all 0.2s ease;
  display: flex;
  align-items: center;
  justify-content: center;
}

.go-btn:hover:not(:disabled) {
  transform: translate(-50%, -50%) scale(1.1);
  box-shadow:
    0 6px 20px rgba(211, 47, 47, 0.6),
    inset 0 2px 4px rgba(255, 255, 255, 0.4);
  background: linear-gradient(145deg, #ff6e6e, #e53935);
}

.go-btn:active:not(:disabled) {
  transform: translate(-50%, -50%) scale(0.92);
  box-shadow:
    0 2px 6px rgba(211, 47, 47, 0.4),
    inset 0 3px 6px rgba(0, 0, 0, 0.15);
  background: linear-gradient(145deg, #d32f2f, #c62828);
}

.go-btn:disabled {
  cursor: not-allowed;
  opacity: 0.8;
}

.go-btn.is-spinning {
  animation: pulse-spin 1.2s ease-in-out infinite;
}

.go-text {
  font-size: 22px;
  font-weight: 900;
  color: #fff;
  text-shadow: 0 1px 3px rgba(0, 0, 0, 0.3);
  letter-spacing: 2px;
  user-select: none;
  pointer-events: none;
}

@keyframes pulse-spin {
  0%,
  100% {
    transform: translate(-50%, -50%) scale(1);
    opacity: 0.8;
  }
  50% {
    transform: translate(-50%, -50%) scale(1.06);
    opacity: 1;
  }
}

.wheel-pointer {
  position: absolute;
  top: -6px;
  left: 50%;
  transform: translateX(-50%);
  z-index: 20;
  display: flex;
  flex-direction: column;
  align-items: center;
  filter: drop-shadow(0 2px 4px rgba(0, 0, 0, 0.3));
}

.pointer-pin {
  width: 0;
  height: 0;
  border-left: 10px solid transparent;
  border-right: 10px solid transparent;
  border-top: 22px solid #ffd54f;
  position: relative;
}

.pointer-pin::before {
  content: '';
  position: absolute;
  top: -22px;
  left: -8px;
  width: 0;
  height: 0;
  border-left: 8px solid transparent;
  border-right: 8px solid transparent;
  border-top: 18px solid #ffe082;
}

.pointer-dot {
  width: 12px;
  height: 12px;
  border-radius: 50%;
  background: linear-gradient(145deg, #ffe082, #ffc107);
  border: 2px solid #fff;
  box-shadow: 0 1px 4px rgba(0, 0, 0, 0.25);
  margin-top: -3px;
}
</style>
