<template>
  <canvas
    ref="canvas"
    class="layout-fireworks"
  ></canvas>
</template>

<script>
// 对象池大小
const POOL_SIZE = 600

// 烟花配置
const CONFIG = {
  // 每次爆炸产生的粒子数量
  PARTICLES_PER_BURST: 200,
  // 各种形状的尺寸配置
  SIZES: {
    RECTANGLE: { WIDTH: 24, HEIGHT: 12 }, // 矩形宽高
    SQUARE: { SIZE: 12 }, // 正方形边长
    CIRCLE: { SIZE: 12 }, // 圆形直径
    TRIANGLE: { SIZE: 10 }, // 三角形边长
    OVAL: { WIDTH: 24, HEIGHT: 12 }, // 椭圆宽高
    IMAGE: { WIDTH: 30, HEIGHT: 30 } // 图片尺寸
  },
  // 旋转相关参数
  ROTATION: {
    BASE_SPEED: 2, // 基础旋转速度
    RANDOM_SPEED: 3, // 随机旋转速度增量
    DECAY: 0.85 // 旋转衰减系数
  },
  // 烟花粒子颜色配置(带透明度)
  COLORS: ['rgba(255, 68, 68, 1)', 'rgba(255, 68, 68, 0.9)', 'rgba(255, 68, 68, 0.8)', 'rgba(255, 116, 188, 1)', 'rgba(255, 116, 188, 0.9)', 'rgba(255, 116, 188, 0.8)', 'rgba(68, 68, 255, 0.8)', 'rgba(92, 202, 56, 0.7)', 'rgba(255, 68, 255, 0.8)', 'rgba(68, 255, 255, 0.7)', 'rgba(255, 136, 68, 0.7)', 'rgba(68, 136, 255, 1)', 'rgba(250, 198, 122, 0.8)'],
  // 烟花粒子形状配置(矩形出现概率更高)
  SHAPES: ['rectangle', 'rectangle', 'rectangle', 'rectangle', 'rectangle', 'rectangle', 'rectangle', 'circle', 'triangle', 'oval']
}

// 图片缓存
const imageCache = {}

// 预加载图片函数
const preloadImage = (url) => {
  return new Promise((resolve, reject) => {
    if (imageCache[url]) {
      if (imageCache[url].complete) {
        resolve(imageCache[url])
      } else {
        imageCache[url].onload = () => resolve(imageCache[url])
        imageCache[url].onerror = reject
      }
    } else {
      const img = new Image()
      img.crossOrigin = 'anonymous' // 处理CORS
      img.src = url
      img.onload = () => {
        imageCache[url] = img
        resolve(img)
      }
      img.onerror = reject
    }
  })
}

import bp from './imgs/hb.png'
import sd from './imgs/sd.png'
// import yd from './imgs/yd.png'
import xc from './imgs/xc.png'
import birthdayCake from './imgs/birthday-cake.svg'

export default {
  name: 'BiFireworks',
  data() {
    return {
      ctx: null,
      particlePool: [],
      fireworks: [],
      animationFrame: null,
      showBirthdayCake: false, // 控制是否显示大蛋糕
      cakeImage: null, // 大蛋糕图片对象
      lastFrameTime: 0, // 上一帧时间
      cakeHideTimer: null // 蛋糕隐藏定时器
    }
  },
  mounted() {
    this.init()
  },
  beforeDestroy() {
    this.cleanup()
  },
  methods: {
    async init() {
      if (this.$refs.canvas) {
        this.ctx = this.$refs.canvas.getContext('2d')
        this.resizeCanvas()
      }
      this.initParticlePool()

      // 预加载所有图片
      await this.preloadAllImages()

      this.animate()
      this.addEventListeners()

      // 监听触发烟花的事件
      this.$root.$on('triggerFireworks', this.handleTriggerFireworks)
    },

    cleanup() {
      if (this.animationFrame) {
        cancelAnimationFrame(this.animationFrame)
      }
      if (this.cakeHideTimer) {
        clearTimeout(this.cakeHideTimer)
        this.cakeHideTimer = null
      }
      this.removeEventListeners()
      this.$root.$off('triggerFireworks', this.handleTriggerFireworks)
    },

    // 初始化对象池
    initParticlePool() {
      for (let i = 0; i < POOL_SIZE; i++) {
        this.particlePool.push({
          x: 0,
          y: 0,
          color: '',
          velocity: { x: 0, y: 0 },
          rotation: 0,
          rotationX: 0,
          rotationY: 0,
          scale: 1,
          shape: 'circle',
          active: false,
          rotationSpeed: { x: 0, y: 0, z: 0 },
          opacity: 1 // 初始化透明度为1
        })
      }
    },

    // 从对象池获取粒子
    getParticleFromPool() {
      const particle = this.particlePool.find((p) => !p.active)
      if (particle) {
        particle.active = true
        return particle
      }
      return null
    },

    // 创建烟花
    createFirework(imageUrl) {
      // 异步创建粒子，避免阻塞主线程
      setTimeout(() => {
        const startX = Math.random() * window.innerWidth
        const startY = window.innerHeight

        const availableShapes = imageUrl && imageCache[imageUrl] ? ['image'] : CONFIG.SHAPES

        for (let i = 0; i < CONFIG.PARTICLES_PER_BURST; i++) {
          const particle = this.getParticleFromPool()
          if (!particle) continue

          const angle = (Math.PI * i) / (CONFIG.PARTICLES_PER_BURST / 2)
          const speed = (12 + Math.random() * 6) * 1.5
          const spread = Math.random() * Math.PI * 2

          Object.assign(particle, {
            x: startX,
            y: startY,
            color: CONFIG.COLORS[Math.floor(Math.random() * CONFIG.COLORS.length)],
            velocity: {
              x: Math.cos(angle) * Math.cos(spread) * speed * (Math.random() * 0.5 + 0.5),
              y: Math.sin(angle) * speed - 15
            },
            rotation: Math.random() * 360,
            rotationX: Math.random() * 360 - 180,
            rotationY: Math.random() * 360 - 180,
            scale: 0.8 + Math.random() * 0.4,
            shape: availableShapes[Math.floor(Math.random() * availableShapes.length)],
            imageUrl: imageUrl && imageCache[imageUrl] ? imageUrl : undefined,
            rotationSpeed: {
              x: (Math.random() * CONFIG.ROTATION.RANDOM_SPEED + CONFIG.ROTATION.BASE_SPEED) * (Math.random() > 0.5 ? 1 : -1),
              y: (Math.random() * CONFIG.ROTATION.RANDOM_SPEED + CONFIG.ROTATION.BASE_SPEED) * (Math.random() > 0.5 ? 1 : -1),
              z: (Math.random() * CONFIG.ROTATION.RANDOM_SPEED + CONFIG.ROTATION.BASE_SPEED) * (Math.random() > 0.5 ? 1 : -1)
            },
            opacity: 1 // 初始化透明度为1
          })

          this.fireworks.push(particle)
        }
      }, 0)
    },

    // 更新烟花状态
    updateFireworks() {
      const velocityThreshold = 10 // 设置下落速度阈值，超过此值开始淡出
      const opacityDecay = 0.02 // 设置透明度减少的速度（增大值加快淡出速度）

      for (let i = this.fireworks.length - 1; i >= 0; i--) {
        const firework = this.fireworks[i]
        firework.x += firework.velocity.x
        firework.y += firework.velocity.y
        firework.velocity.y += 0.525
        firework.rotation += firework.rotationSpeed.z
        firework.rotationX += firework.rotationSpeed.x
        firework.rotationY += firework.rotationSpeed.y

        firework.rotationSpeed.x *= CONFIG.ROTATION.DECAY
        firework.rotationSpeed.y *= CONFIG.ROTATION.DECAY
        firework.rotationSpeed.z *= CONFIG.ROTATION.DECAY

        // 如果粒子的下落速度超过阈值，开始减少透明度
        if (firework.velocity.y > velocityThreshold) {
          firework.opacity -= opacityDecay // 根据需要调整淡出的速度
          if (firework.opacity <= 0) {
            firework.active = false
            this.fireworks.splice(i, 1)
            continue
          }
        }

        // 如果粒子超出屏幕范围，回收粒子
        if (firework.x < -100 || firework.x > window.innerWidth + 100 || firework.y < -100 || firework.y > window.innerHeight + 100) {
          firework.active = false
          this.fireworks.splice(i, 1)
        }
      }

      // 智能蛋糕隐藏：如果显示蛋糕但没有烟花粒子了，延迟隐藏蛋糕
      if (this.showBirthdayCake && this.fireworks.length === 0 && !this.cakeHideTimer) {
        this.cakeHideTimer = setTimeout(() => {
          this.showBirthdayCake = false
          this.cakeHideTimer = null
        }, 1000) // 烟花结束后1秒隐藏蛋糕
      }
    },

    // 绘制单个粒子
    drawFirework(firework) {
      if (!this.ctx) return

      this.ctx.save()
      this.ctx.globalAlpha = firework.opacity // 设置当前粒子的透明度
      this.ctx.translate(firework.x, firework.y)
      this.ctx.rotate((firework.rotation * Math.PI) / 180)
      this.ctx.scale(firework.scale, firework.scale)

      switch (firework.shape) {
        case 'rectangle':
          this.ctx.fillStyle = firework.color
          this.ctx.fillRect(-CONFIG.SIZES.RECTANGLE.WIDTH / 2, -CONFIG.SIZES.RECTANGLE.HEIGHT / 2, CONFIG.SIZES.RECTANGLE.WIDTH, CONFIG.SIZES.RECTANGLE.HEIGHT)
          break
        case 'square':
          this.ctx.fillStyle = firework.color
          this.ctx.fillRect(-CONFIG.SIZES.SQUARE.SIZE / 2, -CONFIG.SIZES.SQUARE.SIZE / 2, CONFIG.SIZES.SQUARE.SIZE, CONFIG.SIZES.SQUARE.SIZE)
          break
        case 'circle':
          this.ctx.fillStyle = firework.color
          this.ctx.beginPath()
          this.ctx.arc(0, 0, CONFIG.SIZES.CIRCLE.SIZE / 2, 0, Math.PI * 2)
          this.ctx.closePath()
          this.ctx.fill()
          break
        case 'triangle':
          this.ctx.fillStyle = firework.color
          this.ctx.beginPath()
          this.ctx.moveTo(0, -CONFIG.SIZES.TRIANGLE.SIZE)
          this.ctx.lineTo(CONFIG.SIZES.TRIANGLE.SIZE, CONFIG.SIZES.TRIANGLE.SIZE)
          this.ctx.lineTo(-CONFIG.SIZES.TRIANGLE.SIZE, CONFIG.SIZES.TRIANGLE.SIZE)
          this.ctx.closePath()
          this.ctx.fill()
          break
        case 'oval':
          this.ctx.fillStyle = firework.color
          this.ctx.beginPath()
          // 兼容性处理：如果浏览器不支持ellipse方法，使用arc绘制圆形作为fallback
          if (this.ctx.ellipse) {
            this.ctx.ellipse(0, 0, CONFIG.SIZES.OVAL.WIDTH / 2, CONFIG.SIZES.OVAL.HEIGHT / 2, 0, 0, Math.PI * 2)
          } else {
            // fallback: 绘制圆形
            this.ctx.arc(0, 0, Math.max(CONFIG.SIZES.OVAL.WIDTH, CONFIG.SIZES.OVAL.HEIGHT) / 2, 0, Math.PI * 2)
          }
          this.ctx.closePath()
          this.ctx.fill()
          break
        case 'image':
          if (firework.imageUrl) {
            const img = imageCache[firework.imageUrl]
            if (img && img.complete) {
              this.ctx.drawImage(img, -CONFIG.SIZES.IMAGE.WIDTH / 2, -CONFIG.SIZES.IMAGE.HEIGHT / 2, CONFIG.SIZES.IMAGE.WIDTH, CONFIG.SIZES.IMAGE.HEIGHT)
            }
          }
          break
        default:
          break
      }

      this.ctx.restore()
    },

    // 绘制所有烟花
    draw() {
      if (!this.ctx || !this.$refs.canvas) return

      this.ctx.clearRect(0, 0, this.$refs.canvas.width, this.$refs.canvas.height)

      // 绘制大蛋糕背景（如果启用）
      if (this.showBirthdayCake) {
        this.drawBirthdayCake()
      }

      this.ctx.globalCompositeOperation = 'lighter'

      this.fireworks.forEach((firework) => {
        this.drawFirework(firework)
      })
    },

    // 绘制大蛋糕在canvas中央
    drawBirthdayCake() {
      if (!this.ctx || !this.$refs.canvas) {
        return
      }

      const canvas = this.$refs.canvas
      const cakeWidth = 200 * 1.5
      const cakeHeight = 240 * 1.5
      const x = (canvas.width - cakeWidth) / 2
      const y = (canvas.height - cakeHeight) / 2

      this.ctx.save()

      // 如果有蛋糕图片，绘制真正的SVG
      if (this.cakeImage && this.cakeImage.complete) {
        this.ctx.globalAlpha = 0.8 // 略微透明，不完全遮挡烟花
        this.ctx.drawImage(this.cakeImage, x, y, cakeWidth, cakeHeight)
      } else {
        // 如果图片加载失败，显示备用的测试矩形
        this.ctx.fillStyle = 'rgba(255, 182, 193, 0.8)' // 粉色半透明
        this.ctx.fillRect(x, y, cakeWidth, cakeHeight)

        // 绘制边框
        this.ctx.strokeStyle = 'rgba(255, 105, 180, 1)'
        this.ctx.lineWidth = 3
        this.ctx.strokeRect(x, y, cakeWidth, cakeHeight)

        // 绘制文字
        this.ctx.fillStyle = 'white'
        this.ctx.font = 'bold 24px Arial'
        this.ctx.textAlign = 'center'
        this.ctx.fillText('🎂 Birthday Cake 🎂', canvas.width / 2, canvas.height / 2)
      }

      this.ctx.restore()
    },

    // 动画循环
    animate() {
      const currentTime = performance.now()

      this.updateFireworks()
      this.draw()
      this.lastFrameTime = currentTime
      this.animationFrame = requestAnimationFrame(this.animate)
    },

    // 处理快捷键
    handleKeyPress(event) {
      // 检查是否同时按下 Ctrl + Shift + P (Windows/Linux) 或 Command + Shift + P (macOS)
      if ((event.ctrlKey && event.shiftKey && event.key.toLowerCase() === 'p') || (event.metaKey && event.shiftKey && event.key.toLowerCase() === 'p')) {
        event.preventDefault()
        this.createFirework()
      }
    },

    // 调整Canvas大小
    resizeCanvas() {
      if (this.$refs.canvas) {
        this.$refs.canvas.width = window.innerWidth
        this.$refs.canvas.height = window.innerHeight
      }
    },

    // 预加载所有需要的图片
    async preloadAllImages() {
      const imageUrls = [bp, sd, xc, birthdayCake]

      try {
        await Promise.all(imageUrls.map((url) => preloadImage(url)))

        // 设置大蛋糕图片
        this.cakeImage = imageCache[birthdayCake]
      } catch (error) {
        console.error('Image preloading failed', error)
      }
    },

    // 事件监听器管理
    addEventListeners() {
      // window.addEventListener('keydown', this.handleKeyPress)
      window.addEventListener('resize', this.resizeCanvas)
    },

    removeEventListeners() {
      // window.removeEventListener('keydown', this.handleKeyPress)
      window.removeEventListener('resize', this.resizeCanvas)
    },

    // 处理触发烟花事件
    handleTriggerFireworks(imageUrl) {
      // 检查是否是生日蛋糕模式（传入'cake-mode'）
      if (imageUrl === 'cake-mode') {
        // 如果蛋糕还没显示，则显示蛋糕
        if (!this.showBirthdayCake) {
          this.showBirthdayCake = true
        }

        // 清除之前的隐藏定时器
        if (this.cakeHideTimer) {
          clearTimeout(this.cakeHideTimer)
          this.cakeHideTimer = null
        }

        // 重新设置隐藏定时器，每次蛋糕模式都延长显示时间
        this.cakeHideTimer = setTimeout(() => {
          this.showBirthdayCake = false
          this.cakeHideTimer = null
        }, 2000) // 改为2秒，与烟花粒子生命周期更匹配

        // 使用默认几何图形创建烟花
        this.createFirework()
        return
      }

      if (imageUrl && imageCache[imageUrl] && imageCache[imageUrl].complete) {
        this.createFirework(imageUrl)
      } else {
        this.createFirework()
      }
    }
  }
}
</script>

<style scoped>
.layout-fireworks {
  position: fixed;
  top: 0;
  left: 0;
  z-index: 9999;
  width: 100%;
  height: 100%;
  pointer-events: none;
}
</style>
