<template>
  <view class="floating-bubbles">
    <!-- 角色图片区域 -->
    <view class="character-layer">
      <view
        v-for="char in activeCharacters"
        :key="char.id"
        class="character-wrapper"
        :style="char.style"
      >
        <image
          :src="char.imageSrc"
          class="character-img"
          mode="aspectFit"
        />
      </view>
    </view>
    
    <!-- 对话框层 - 独立于角色层，始终在最上方 -->
    <view class="bubble-layer">
      <view
        v-for="char in activeCharacters"
        :key="'bubble-' + char.id"
        class="bubble-wrapper"
        :style="char.style"
      >
        <view class="character-bubble-wrapper">
          <view
            v-for="bubble in char.bubbles"
            :key="bubble.id"
            class="dialog-bubble"
            :class="'arrow-' + char.arrowPosition"
            :style="bubble.style"
          >
            <view class="bubble-text-container">
              <text class="bubble-text">{{ bubble.text }}</text>
              <text v-if="bubble.showSupport" class="bubble-text-zl">(点击助力)</text>
            </view>
            <!-- 对话框小三角 -->
            <view class="dialog-arrow" :class="'arrow-' + char.arrowPosition"></view>
          </view>
        </view>
      </view>
    </view>
  </view>
</template>

<script setup>
import { ref, watch, onUnmounted, computed } from 'vue'
import screenCache from '@/utils/screen-cache'
import { BUBBLE_CONFIG } from '@/utils/performance-config'

// 互动角色图片
const CHARACTER_IMAGES = [
  '/static/rank/activity-support-icon/square-interaction-char/1.png',
  '/static/rank/activity-support-icon/square-interaction-char/2.png',
  '/static/rank/activity-support-icon/square-interaction-char/3.png',
  '/static/rank/activity-support-icon/square-interaction-char/4.png'
]

const props = defineProps({
  bubbleTexts: {
    type: Array,
    default: () => []
  },
  isActive: {
    type: Boolean,
    default: true
  },
  current: {
    type: Number,
    default: 0
  },
  target: {
    type: Number,
    default: 1000
  }
})

const activeBubbles = ref([])
const activeCharacters = ref([])
const MAX_BUBBLES = BUBBLE_CONFIG.MAX_COUNT
const MAX_ACTIVE_DIALOGS = 4 // 最多同时显示4个对话框
let bubbleIdCounter = 0
let characterIdCounter = 0
let generationTimer = null
let characterBubbleTimer = null
let isGenerating = false
let cachedViewportWidth = 0
// 跟踪所有 setTimeout 定时器以便清理
let characterGenerationTimers = []
let bubbleRemovalTimers = []

// 计算进度百分比
const progressPercent = computed(() => {
  if (props.target === 0) return 0
  return Math.min((props.current / props.target) * 100, 100)
})

// 根据进度计算角色数量 (进度越高，角色越多，最多10个)
const characterCount = computed(() => {
  const percent = progressPercent.value
  if (percent >= 90) return 10
  if (percent >= 70) return 8
  if (percent >= 50) return 6
  if (percent >= 30) return 4
  if (percent >= 10) return 2
  return 1
})

// 在蓝色框内随机生成位置，避开蛋糕禁区
function generateRandomPosition(existingPositions, minDistance = 60) {
  const maxAttempts = 100
  let attempts = 0
  
  // 蓝色框（容器）尺寸
  const containerWidth = 728 // rpx
  const containerHeight = 536 // rpx
  const characterWidth = 120 // rpx
  const characterHeight = 200 // rpx
  
  // 蛋糕禁区尺寸 - 中心区域
  const cakeZoneWidth = 300 // rpx
  const cakeZoneHeight = 300 // rpx
  
  // 对话框显示区域 - 容器下半部分
  const dialogAreaTop = containerHeight / 2 // 从容器中心线开始（下半部分）
  
  while (attempts < maxAttempts) {
    // 在蓝色框内随机生成位置
    const x = (Math.random() - 0.5) * (containerWidth - characterWidth - 40)
    const y = (Math.random() - 0.5) * (containerHeight - characterHeight - 40)
    
    // 检查是否在蛋糕禁区内
    const isInCakeZone = 
      Math.abs(x) < (cakeZoneWidth / 2) && 
      Math.abs(y) < (cakeZoneHeight / 2)
    
    if (isInCakeZone) {
      attempts++
      continue // 在蛋糕禁区内，重新生成
    }
    
    // 检查是否超出蓝色框边界
    const isOutOfBounds = 
      Math.abs(x) + (characterWidth / 2) > (containerWidth / 2) ||
      Math.abs(y) + (characterHeight / 2) > (containerHeight / 2)
    
    if (isOutOfBounds) {
      attempts++
      continue // 超出边界，重新生成
    }
    
    // 检查是否与现有位置重叠
    const isTooClose = existingPositions.some(pos => {
      const distance = Math.sqrt(
        Math.pow(pos.x - x, 2) + Math.pow(pos.y - y, 2)
      )
      return distance < minDistance
    })
    
    if (!isTooClose) {
      // 计算角度（用于判断小三角方向）
      const angle = Math.atan2(y, x) * (180 / Math.PI) + 180
      
      // 判断是否在容器下半部分（对话框显示区域）
      // y坐标大于0表示在容器下半部分
      const isInDialogArea = y > 0
      
      // 判断小三角方向：根据x坐标判断
      // x < 0 在左侧，x >= 0 在右侧
      const arrowPosition = x < 0 ? 'left' : 'right'
      
      return { x, y, angle, isInDialogArea, arrowPosition }
    }
    
    attempts++
  }
  
  // 如果尝试多次仍然失败，返回 null 表示无法生成
  return null
}

// 初始化角色图片 - 根据进度动态添加角色
function initCharacters() {
  const targetCount = characterCount.value
  const currentCount = activeCharacters.value.length
  
  // 如果当前角色数量已经达到目标，不再添加
  if (currentCount >= targetCount) return
  
  // 收集现有角色的位置
  const existingPositions = activeCharacters.value.map(char => {
    // 从 transform 中提取 x, y 坐标
    const transform = char.style.transform || ''
    const match = transform.match(/translate\((-?\d+(?:\.\d+)?)rpx,\s*(-?\d+(?:\.\d+)?)rpx\)/)
    if (match) {
      return { x: parseFloat(match[1]), y: parseFloat(match[2]) }
    }
    return { x: 0, y: 0 }
  })
  
  // 只添加需要增加的角色
  let addedCount = 0
  for (let i = currentCount; i < targetCount && addedCount < 20; i++) {
    const timerId = setTimeout(() => {
      const randomIndex = Math.floor(Math.random() * CHARACTER_IMAGES.length)
      const imageSrc = CHARACTER_IMAGES[randomIndex]
      const charId = characterIdCounter++
      
      // 在蓝色框内随机生成位置，避开红色框
      const position = generateRandomPosition(existingPositions)
      
      // 如果无法生成有效位置（在红色框内或超出边界或重叠），跳过
      if (!position) {
        return
      }
      
      existingPositions.push(position) // 添加到已有位置列表
      
      activeCharacters.value.push({
        id: charId,
        imageSrc: imageSrc,
        bubbles: [],
        arrowPosition: position.arrowPosition, // 使用位置函数返回的方向
        isInDialogArea: position.isInDialogArea, // 记录是否在对话框显示区域（容器下半部分）
        style: {
          left: '50%',
          top: '50%',
          transform: `translate(${position.x}rpx, ${position.y}rpx) translateX(-50%) translateY(-50%)`,
          animation: 'character-appear 0.5s ease-out forwards'
        }
      })
      
      addedCount++
      
      // 当第一个角色显示后，开始生成气泡
      if (activeCharacters.value.length === 1) {
        const bubbleTimerId = setTimeout(() => {
          startCharacterBubbleGeneration()
        }, 500)
        characterGenerationTimers.push(bubbleTimerId)
      }
    }, addedCount * 300) // 每个新角色间隔300ms出现
    characterGenerationTimers.push(timerId)
  }
}

// 在角色头顶生成气泡
function generateCharacterBubble() {
  if (!props.bubbleTexts || props.bubbleTexts.length === 0) return

  // 只选择在容器下半部分的角色
  const charactersInDialogArea = activeCharacters.value.filter(char => char.isInDialogArea)
  
  if (charactersInDialogArea.length === 0) return

  // 计算当前已显示的对话框总数
  const currentDialogCount = activeCharacters.value.reduce((count, char) => {
    return count + char.bubbles.length
  }, 0)

  // 如果已经达到最大数量，不再生成新对话框
  if (currentDialogCount >= MAX_ACTIVE_DIALOGS) return

  // 过滤出没有对话框的角色
  const availableCharacters = charactersInDialogArea.filter(char => char.bubbles.length === 0)
  
  if (availableCharacters.length === 0) return

  // 获取所有已有对话框的角色位置
  const existingBubblePositions = activeCharacters.value
    .filter(char => char.bubbles.length > 0)
    .map(char => {
      const transform = char.style.transform || ''
      const match = transform.match(/translate\((-?\d+(?:\.\d+)?)rpx,\s*(-?\d+(?:\.\d+)?)rpx\)/)
      if (match) {
        return { x: parseFloat(match[1]), y: parseFloat(match[2]) }
      }
      return null
    })
    .filter(pos => pos !== null)

  // 从可用角色中筛选出对话框不会重叠的角色
  const nonOverlappingCharacters = availableCharacters.filter(char => {
    const transform = char.style.transform || ''
    const match = transform.match(/translate\((-?\d+(?:\.\d+)?)rpx,\s*(-?\d+(?:\.\d+)?)rpx\)/)
    if (!match) return true
    
    const charX = parseFloat(match[1])
    const charY = parseFloat(match[2])
    
    // 检查是否与现有对话框位置重叠（对话框在角色上方）
    const minDistance = 150 // rpx，对话框之间的最小距离
    const isOverlapping = existingBubblePositions.some(pos => {
      const distance = Math.sqrt(
        Math.pow(pos.x - charX, 2) + Math.pow(pos.y - charY, 2)
      )
      return distance < minDistance
    })
    
    return !isOverlapping
  })

  if (nonOverlappingCharacters.length === 0) return

  // 随机选择一个不会重叠的角色
  const charIndex = Math.floor(Math.random() * nonOverlappingCharacters.length)
  const character = nonOverlappingCharacters[charIndex]

  // 随机选择气泡文字
  const text = props.bubbleTexts[Math.floor(Math.random() * props.bubbleTexts.length)]

  const bubbleId = bubbleIdCounter++

  const bubble = {
    id: bubbleId,
    text,
    showSupport: Math.random() > 0.5, // 50%概率显示"(点击助力)"
    style: {}
  }

  // 添加到角色头顶（只保留一个）
  character.bubbles = [bubble]

  // 30秒后移除对话框
  const removalTimerId = setTimeout(() => {
    const index = character.bubbles.findIndex(b => b.id === bubbleId)
    if (index > -1) {
      character.bubbles.splice(index, 1)
    }
    // 从跟踪列表中移除
    const timerIndex = bubbleRemovalTimers.indexOf(removalTimerId)
    if (timerIndex > -1) {
      bubbleRemovalTimers.splice(timerIndex, 1)
    }
  }, 30000) // 30秒
  bubbleRemovalTimers.push(removalTimerId)
}

// 启动角色头顶气泡生成
function startCharacterBubbleGeneration() {
  if (characterBubbleTimer) return

  // 初始生成1-2个气泡
  const initialCount = Math.floor(Math.random() * 2) + 1
  for (let i = 0; i < initialCount; i++) {
    const timerId = setTimeout(() => {
      generateCharacterBubble()
    }, i * 500)
    characterGenerationTimers.push(timerId)
  }

  // 每隔随机时间生成新对话框（保持最多4个在线）
  characterBubbleTimer = setInterval(() => {
    if (props.isActive) {
      generateCharacterBubble()
    }
  }, Math.random() * 5000 + 5000) // 5-10秒随机间隔
}

// 停止角色头顶气泡生成
function stopCharacterBubbleGeneration() {
  if (characterBubbleTimer) {
    clearInterval(characterBubbleTimer)
    characterBubbleTimer = null
  }
}

// 监听角色数量变化 - 根据进度实时添加角色
watch(characterCount, (newCount, oldCount) => {
  if (newCount > activeCharacters.value.length) {
    // 需要添加更多角色
    initCharacters()
  }
}, { immediate: true })

// 监听 isActive 变化 - 合并重复的 watcher
watch(() => props.isActive, (newVal) => {
  if (newVal) {
    // 初始化角色（如果还没有）
    if (activeCharacters.value.length === 0) {
      initCharacters()
    }
    // 启动气泡生成
    startCharacterBubbleGeneration()
  } else {
    // 停止气泡生成
    stopCharacterBubbleGeneration()
  }
}, { immediate: true })

// 初始化时缓存视口宽度
cachedViewportWidth = screenCache.getWindowWidth()

onUnmounted(() => {
  stopCharacterBubbleGeneration()
  clearAllBubbleTimers()
  clearAllCharacterGenerationTimers()
  clearAllBubbleRemovalTimers()
})

/**
 * 清除所有气泡定时器（防止内存泄漏）
 */
function clearAllBubbleTimers() {
  // 清除角色气泡定时器
  activeCharacters.value.forEach(char => {
    char.bubbles = []
  })
}

/**
 * 清除所有角色生成定时器
 */
function clearAllCharacterGenerationTimers() {
  characterGenerationTimers.forEach(timerId => {
    clearTimeout(timerId)
  })
  characterGenerationTimers = []
}

/**
 * 清除所有气泡移除定时器
 */
function clearAllBubbleRemovalTimers() {
  bubbleRemovalTimers.forEach(timerId => {
    clearTimeout(timerId)
  })
  bubbleRemovalTimers = []
}
</script>

<style scoped>
.floating-bubbles {
  position: fixed;
  top: 31%;
  left: 0;
  right: 0;
  height: 48%;
  pointer-events: none;
  z-index: 100;
  overflow: visible;
}

/* 角色图片层 - 定位在蛋糕区域周围 */
.character-layer {
  position: absolute;
  top: 65%;
  left: 50%;
  transform: translate(-50%, -50%);
  width: 728rpx;
  height: 536rpx;
  overflow: visible;
  z-index: 1;
}

/* 对话框层 - 独立层，始终在角色层上方 */
.bubble-layer {
  position: absolute;
  top: 65%;
  left: 50%;
  transform: translate(-50%, -50%);
  width: 728rpx;
  height: 536rpx;
  overflow: visible;
  z-index: 100;
  pointer-events: none;
}

.bubble-wrapper {
  position: absolute;
  width: 120rpx;
  height: 200rpx;
}

.character-wrapper {
  position: absolute;
  width: 120rpx;
  height: 200rpx;
  z-index: 1;
}

.character-img {
  width: 100%;
  height: 100%;
  position: relative;
  z-index: 1;
}

/* 角色头顶对话框容器 */
.character-bubble-wrapper {
  position: absolute;
  bottom: 76%;
  left: 50%;
  transform: translateX(-50%);
  display: flex;
  flex-direction: column;
  align-items: center;
  pointer-events: none;
  z-index: 1000;
}

/* 对话框样式 */
.dialog-bubble {
  position: relative;
  padding: 16rpx 24rpx;
  background: rgba(0, 0, 0, 0.5);
  border-radius: 16rpx;
  animation: dialog-appear 0.3s ease-out forwards;
  white-space: nowrap;
  max-width: 280rpx;
  display: flex;
  flex-direction: column;
  z-index: 1001;
}

/* 对话框文本容器 - 上下布局 */
.bubble-text-container {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 4rpx;
}

/* 对话框小三角 - 默认在底部中心 */
.dialog-arrow {
  position: absolute;
  bottom: -10rpx;
  left: 50%;
  transform: translateX(-50%);
  width: 0;
  height: 0;
  border-left: 12rpx solid transparent;
  border-right: 12rpx solid transparent;
  border-top: 12rpx solid rgba(0, 0, 0, 0.5);
}

/* 左侧角色 - 对话框向右偏移，小三角在左边对准角色头部 */
.dialog-bubble.arrow-left {
  animation: dialog-appear-left 0.3s ease-out forwards;
}

.dialog-bubble.arrow-left .dialog-arrow {
  left: 10rpx;
  right: auto;
  transform: none;
}

/* 右侧角色 - 对话框向左偏移，小三角在右边对准角色头部 */
.dialog-bubble.arrow-right {
  animation: dialog-appear-right 0.3s ease-out forwards;
}

.dialog-bubble.arrow-right .dialog-arrow {
  left: auto;
  right: 10rpx;
  transform: none;
}

.bubble-text {
  font-size: 17rpx;
  color: #fff;
  text-shadow:
        0 3rpx 6rpx rgba(0, 0, 0, 0.4),
        0 1rpx 3rpx rgba(0, 0, 0, 0.3);
  white-space: nowrap;
  font-family: 'ZaoZiGongFangJianHei-1';
  text-align: center;
}

.bubble-text-zl {
  font-size: 17rpx;
  color: #FFA500;
  white-space: nowrap;
  font-family: 'ZaoZiGongFangJianHei-1', sans-serif;
  text-align: center;
  margin-top: 4rpx;
}


/* 对话框出现动画 - 左侧角色（向右偏移） */
@keyframes dialog-appear-left {
  0% {
    transform: translateX(80rpx) scale(0.8) translateY(10rpx);
    opacity: 0;
  }
  100% {
    transform: translateX(48rpx) scale(1) translateY(0);
    opacity: 1;
  }
}

/* 对话框出现动画 - 右侧角色（向左偏移） */
@keyframes dialog-appear-right {
  0% {
    transform: translateX(-80rpx) scale(0.8) translateY(10rpx);
    opacity: 0;
  }
  100% {
    transform: translateX(-48rpx) scale(1) translateY(0);
    opacity: 1;
  }
}

/* 对话框出现动画 - 默认（保留以防万一） */
@keyframes dialog-appear {
  0% {
    transform: scale(0.8) translateY(10rpx);
    opacity: 0;
  }
  100% {
    transform: scale(1) translateY(0);
    opacity: 1;
  }
}

/* 对话框淡出动画 */
@keyframes dialog-fade {
  0%, 70% {
    opacity: 1;
  }
  100% {
    opacity: 0;
  }
}

/* 角色出现动画 */
@keyframes character-appear {
  0% {
    transform: translate(var(--char-x, 0), var(--char-y, 0)) translateX(-50%) translateY(-50%) scale(0);
    opacity: 0;
  }
  100% {
    transform: translate(var(--char-x, 0), var(--char-y, 0)) translateX(-50%) translateY(-50%) scale(1);
    opacity: 1;
  }
}
</style>