<template>
  <view class="prize-wheel">
    <view class="prize-container" :style="containerStyle">
      <view class="prize-strip" :style="stripStyle">
        <!-- 左侧复制项 -->
        <view 
          class="prize-item" 
          v-for="(item, index) in visibleItems.prefix" 
          :key="`prefix-${index}`"
          :style="itemStyle"
        >
          <slot :item="item">
            <view class="default-prize" :style="{ color: item.color }">{{item.value}}</view>
          </slot>
        </view>
        
        <!-- 主要项 -->
        <view 
          class="prize-item" 
          v-for="(item, index) in visibleItems.main" 
          :key="`main-${index}`"
          :class="{'prize-active': isActive && activeIndex === index}"
          :style="itemStyle"
        >
          <slot :item="item">
            <view class="default-prize" :style="{ color: item.color }">{{item.value}}</view>
          </slot>
        </view>
        
        <!-- 右侧复制项 -->
        <view 
          class="prize-item" 
          v-for="(item, index) in visibleItems.suffix" 
          :key="`suffix-${index}`"
          :style="itemStyle"
        >
          <slot :item="item">
            <view class="default-prize" :style="{ color: item.color }">{{item.value}}</view>
          </slot>
        </view>
      </view>
    </view>
    
    <!-- 中心指示器 -->
    <view class="center-indicator"></view>
  </view>
</template>

<script>
export default {
  name: 'PrizeWheel',
  props: {
    // 奖品列表
    prizes: {
      type: Array,
      default: () => []
    },
    // 动画时长(秒)
    duration: {
      type: Number,
      default: 4
    },
    // 缓冲数量(前后各多少个)
    bufferCount: {
      type: Number,
      default: 5
    },
    // 单个奖品宽度
    itemWidth: {
      type: Number,
      default: () => uni.upx2px(180)
    },
    // 单个奖品高度
    itemHeight: {
      type: Number,
      default: () => uni.upx2px(150)
    },
    // 是否高亮显示选中项
    highlight: {
      type: Boolean,
      default: true
    },
    // 最大速度
    maxSpeed: {
      type: Number,
      default: 2000
    }
  },
  data() {
    return {
      isSpinning: false,     // 是否正在旋转
      isActive: false,       // 是否高亮显示
      activeIndex: -1,       // 高亮索引
      currentOffset: 0,      // 当前偏移量
      targetPrize: null,     // 目标奖品
      targetIndex: -1,       // 目标奖品索引
      speedPhase: 'initial', // 速度阶段：initial, accelerating, constant, decelerating, stopping
      animationId: null,     // 动画ID
      lastTimestamp: 0,      // 上次时间戳
      speed: 0,              // 当前速度(px/s)
      totalSpinCount: 0,     // 总共旋转次数
      itemsCount: 0,         // 实际奖品数量
      autoResetTimer: null,  // 自动重置定时器
    }
  },
  computed: {
    // 计算可视奖品列表(前缀+主体+后缀)
    visibleItems() {
      if (!this.prizes || this.prizes.length === 0) {
        return { prefix: [], main: [], suffix: [] }
      }
      
      // 基本项数
      const baseItems = [...this.prizes]
      this.itemsCount = baseItems.length
      
      // 主体区域重复数次以填满屏幕
      let mainItems = []
      const repeatCount = Math.ceil(30 / baseItems.length) // 确保足够多的项目
      for (let i = 0; i < repeatCount; i++) {
        mainItems = [...mainItems, ...baseItems]
      }
      
      // 前缀和后缀(与主体数据相同，用于无缝循环)
      const prefix = [...baseItems]
      const suffix = [...baseItems]
      
      return {
        prefix,
        main: mainItems,
        suffix
      }
    },
    
    // 容器样式
    containerStyle() {
      return {
        height: `${this.itemHeight}px`,
        width: '100%',
        overflow: 'hidden'
      }
    },
    
    // 奖品条带样式
    stripStyle() {
      let transitionStyle = this.isSpinning ? 'none' : `transform ${this.duration / 3}s cubic-bezier(0.34, 1.56, 0.64, 1)`
      return {
        transform: `translateX(${this.currentOffset}px)`,
        transition: transitionStyle
      }
    },
    
    // 单个项目样式
    itemStyle() {
      return {
        width: `${this.itemWidth}px`,
        height: `${this.itemHeight}px`,
        flexShrink: 0
      }
    },
    
    // 计算中心位置偏移量
    centerOffset() {
      const containerWidth = uni.getSystemInfoSync().windowWidth
      return containerWidth / 2 - this.itemWidth / 2
    },
    
    // 单个周期的宽度(一组奖品的总宽度)
    cycleWidth() {
      return this.itemWidth * this.prizes.length
    }
  },
  mounted() {
    // 初始化位置到中心
    this.resetPosition()
  },
  beforeDestroy() {
    // 清理资源
    this.stopAnimation()
    if (this.autoResetTimer) {
      clearTimeout(this.autoResetTimer)
    }
  },
  methods: {
    // 重置位置到中心
    resetPosition() {
      // 计算初始偏移量，确保一个完整的周期显示在中间
      this.currentOffset = this.centerOffset - (this.prizes.length * this.itemWidth)
    },
    
    // 开始抽奖
    startSpin() {
      if (this.isSpinning) return
      
      this.isSpinning = true
      this.speedPhase = 'accelerating'
      this.speed = 30 // 初始速度
      this.targetPrize = null
      this.targetIndex = -1
      this.totalSpinCount = 0
      this.lastTimestamp = performance.now()
      
      // 发出开始事件
      this.$emit('spin-start')
      
      // 启动动画循环
      this.animationId = requestAnimationFrame(this.animate)
    },
    
    // 设置最终奖品并开始减速
    setPrize(prize) {
      if (!this.isSpinning) return
      
      // 保存目标奖品
      this.targetPrize = prize
      
      // 查找目标奖品在列表中的位置
      this.targetIndex = this.prizes.findIndex(item => 
        (item.id && item.id === prize.id) || 
        (item.value && item.value === prize.value)
      )
      
      if (this.targetIndex === -1) {
        console.warn('目标奖品不在奖品列表中')
        // 如果找不到，默认使用第一个
        this.targetIndex = 0
      }
      
      // 计划减速
      setTimeout(() => {
        if (this.isSpinning) {
          this.speedPhase = 'decelerating'
        }
      }, 1000) // 匀速运行一段时间后开始减速
    },
    
    // 动画函数
    animate(timestamp) {
      if (!this.isSpinning) return
      
      // 计算时间差
      const delta = timestamp - this.lastTimestamp
      this.lastTimestamp = timestamp
      
      // 根据阶段更新速度
      switch(this.speedPhase) {
        case 'accelerating':
          // 加速阶段
          this.speed = Math.min(this.maxSpeed, this.speed * 1.08)
          if (this.speed >= this.maxSpeed) {
            this.speedPhase = 'constant'
          }
          break
          
        case 'decelerating':
          // 减速阶段
          this.speed *= 0.97
          
          // 当速度足够慢且有目标奖品时，准备停止
          if (this.speed < 200 && this.targetIndex !== -1) {
            this.speedPhase = 'stopping'
            this.prepareToStop()
          }
          break
          
        case 'stopping':
          // 停止阶段 - 速度进一步降低
          this.speed *= 0.85
          
          // 当速度非常慢时完全停止
          if (this.speed < 10) {
            this.finalizePosition()
            this.stopAnimation()
            return
          }
          break
      }
      
      // 移动奖品条
      this.moveStrip(delta)
      
      // 继续动画
      this.animationId = requestAnimationFrame(this.animate)
    },
    
    // 移动奖品条
    moveStrip(deltaTime) {
      // 计算移动距离
      const distance = (this.speed * deltaTime) / 1000
      
      // 更新位置
      this.currentOffset -= distance
      
      // 检查是否需要重置位置（循环效果）
      this.checkResetPosition()
      
      // 计算当前中心位置的项
      this.updateActiveItem()
    },
    
    // 检查并重置位置以实现无限循环
    checkResetPosition() {
      const cycleWidth = this.itemWidth * this.prizes.length
      
      // 如果滚动过远，重置到等效位置
      if (Math.abs(this.currentOffset) > cycleWidth * 3) {
        // 计算偏移量对一个周期的余数
        const remainder = this.currentOffset % cycleWidth
        // 重置位置，保持视觉上的连续性
        this.currentOffset = this.centerOffset - cycleWidth + remainder
        this.totalSpinCount++
      }
    },
    
    // 更新活跃项
    updateActiveItem() {
      if (!this.highlight) return
      
      // 计算当前中心位置对应的项
      const relativePos = -this.currentOffset + this.centerOffset
      // 计算相对于一个周期的位置
      const cyclePos = (relativePos % this.cycleWidth + this.cycleWidth) % this.cycleWidth
      // 计算对应项的索引
      const itemIndex = Math.floor(cyclePos / this.itemWidth)
      
      if (itemIndex >= 0 && itemIndex < this.prizes.length) {
        this.isActive = true
        this.activeIndex = itemIndex
      } else {
        this.isActive = false
      }
    },
    
    // 准备停止动画，对准目标奖品
    prepareToStop() {
      if (this.targetIndex === -1) return
      
      // 计算当前位置
      const relativePos = -this.currentOffset + this.centerOffset
      // 当前位置在一个周期内的偏移量
      const cyclePos = (relativePos % this.cycleWidth + this.cycleWidth) % this.cycleWidth
      // 当前项的索引
      const currentItemIndex = Math.floor(cyclePos / this.itemWidth)
      
      // 计算需要移动的距离，确保目标奖品最终落在中心
      // 这里的计算考虑了当前减速状态下的停止位置
      
      // 减速率因子 - 影响最终停止位置的精度
      const decelerationFactor = 0.95
      
      // 计算目标索引相对于当前索引的位置
      // 确保我们总是向前滚动到目标（不会反向）
      let stepsToTarget = this.targetIndex - currentItemIndex
      if (stepsToTarget <= 0) {
        stepsToTarget += this.prizes.length
      }
      
      // 根据当前速度微调速度，确保能够准确停在目标奖品上
      // 这是一个关键的计算，需要考虑减速曲线
      if (this.speed > 100) {
        this.speed = Math.max(100, this.speed * decelerationFactor)
      }
    },
    
    // 最终化位置，确保奖品对准中心
    finalizePosition() {
      if (this.targetIndex === -1) return
      
      // 计算精确位置使目标奖品居中
      // 注意：这里不再使用额外的周期位移，直接计算目标位置
      const relativePos = -this.currentOffset + this.centerOffset
      const cyclePos = (relativePos % this.cycleWidth + this.cycleWidth) % this.cycleWidth
      const currentItemIndex = Math.floor(cyclePos / this.itemWidth)
      
      // 计算最短路径到目标奖品
      let adjustedOffset = this.currentOffset
      
      // 如果目标就在附近，直接微调位置
      if (Math.abs(currentItemIndex - this.targetIndex) <= this.prizes.length / 2) {
        const delta = (currentItemIndex - this.targetIndex) * this.itemWidth
        adjustedOffset += delta
      }
      
      // 使用CSS过渡平滑地移动到最终位置
      this.isSpinning = false
      this.currentOffset = adjustedOffset
      
      // 设置活跃项
      this.isActive = true
      this.activeIndex = this.targetIndex
    },
    
    // 停止动画
    stopAnimation() {
      if (!this.isSpinning && !this.animationId) return
      
      cancelAnimationFrame(this.animationId)
      this.animationId = null
      this.isSpinning = false
      
      // 发出停止事件，传递选中的奖品
      this.$emit('spin-end', this.targetPrize || this.prizes[this.activeIndex])
      
      // 移除自动重置定时器，让奖品停在当前位置
      if (this.autoResetTimer) {
        clearTimeout(this.autoResetTimer)
        this.autoResetTimer = null
      }
    }
  }
}
</script>

<style lang="scss">
.prize-wheel {
  position: relative;
  width: 100%;
  
  .prize-container {
    position: relative;
    overflow: hidden;
  }
  
  .prize-strip {
    display: flex;
    flex-direction: row;
    flex-wrap: nowrap;
  }
  
  .prize-item {
    display: flex;
    justify-content: center;
    align-items: center;
    box-sizing: border-box;
    transition: transform 0.2s ease;
    
    &.prize-active {
      transform: scale(1.1);
      z-index: 1;
      
      .default-prize {
        background-color: rgba(255, 215, 0, 0.3);
        box-shadow: 0 0 10px rgba(255, 215, 0, 0.5);
      }
    }
  }
  
  .default-prize {
    width: 90%;
    height: 90%;
    display: flex;
    justify-content: center;
    align-items: center;
    background-color: rgba(255, 255, 255, 0.8);
    border-radius: 8px;
    font-size: 30rpx;
    padding: 10rpx;
    transition: all 0.2s ease;
  }
  
  .center-indicator {
    position: absolute;
    top: 0;
    left: 50%;
    transform: translateX(-50%);
    width: 2px;
    height: 100%;
    background-color: #ff5a5f;
    z-index: 10;
    
    &:before {
      content: '';
      position: absolute;
      top: 0;
      left: 50%;
      transform: translateX(-50%);
      width: 0;
      height: 0;
      border-left: 10px solid transparent;
      border-right: 10px solid transparent;
      border-top: 10px solid #ff5a5f;
    }
    
    &:after {
      content: '';
      position: absolute;
      bottom: 0;
      left: 50%;
      transform: translateX(-50%);
      width: 0;
      height: 0;
      border-left: 10px solid transparent;
      border-right: 10px solid transparent;
      border-bottom: 10px solid #ff5a5f;
    }
  }
}
</style> 