import { useEffect, useRef } from 'react'

// PetalFall is the cozy ambient layer: a fixed, non-interactive 2D canvas that
// drifts soft cherry-blossom petals down the page. Each petal is a real
// petal-shaped sprite (notched sakura silhouette with a gentle gradient and
// soft alpha), pre-rendered once per color and then blitted many times with
// rotation + sway. It sits behind the chrome, ignores pointer events, pauses
// when the tab is hidden, and renders nothing for prefers-reduced-motion.

// Saturated-but-soft blossom colors. Each petal fades from a light, near-white
// tip to its color at the base, so it reads as a real petal rather than a blob.
const PALETTE: { r: number; g: number; b: number }[] = [
  { r: 255, g: 150, b: 190 }, // rose pink
  { r: 255, g: 184, b: 205 }, // pale blossom
  { r: 255, g: 158, b: 130 }, // warm peach
  { r: 209, g: 160, b: 255 }, // lavender
  { r: 255, g: 122, b: 172 }, // deep rose
]

const SPRITE_PX = 160 // off-screen render resolution per petal sprite

function rgba(c: { r: number; g: number; b: number }, a: number): string {
  return `rgba(${Math.round(c.r)}, ${Math.round(c.g)}, ${Math.round(c.b)}, ${a})`
}
function mixWhite(c: { r: number; g: number; b: number }, t: number) {
  return { r: c.r + (255 - c.r) * t, g: c.g + (255 - c.g) * t, b: c.b + (255 - c.b) * t }
}
function scale(c: { r: number; g: number; b: number }, t: number) {
  return { r: c.r * t, g: c.g * t, b: c.b * t }
}

// Draw one petal sprite: a notched sakura silhouette filled with a tip→base
// gradient and a faint central highlight, on a transparent canvas.
function makeSprite(color: { r: number; g: number; b: number }): HTMLCanvasElement {
  const s = SPRITE_PX
  const cv = document.createElement('canvas')
  cv.width = s
  cv.height = s
  const g = cv.getContext('2d')!
  g.translate(s / 2, s / 2)

  const hw = s * 0.3 // half width
  const hh = s * 0.44 // half height

  g.beginPath()
  g.moveTo(0, hh) // pointed base
  g.bezierCurveTo(hw, hh * 0.42, hw * 0.92, -hh * 0.52, hw * 0.2, -hh * 0.92) // right side → near tip
  g.quadraticCurveTo(0, -hh * 0.72, -hw * 0.2, -hh * 0.92) // the sakura notch
  g.bezierCurveTo(-hw * 0.92, -hh * 0.52, -hw, hh * 0.42, 0, hh) // left side → base
  g.closePath()

  const grad = g.createLinearGradient(0, -hh, 0, hh)
  grad.addColorStop(0, rgba(mixWhite(color, 0.55), 0.78)) // light, soft tip
  grad.addColorStop(0.45, rgba(color, 0.88))
  grad.addColorStop(1, rgba(scale(color, 0.8), 0.95)) // deeper base
  g.fillStyle = grad
  g.fill()

  // A soft white sheen down the centre for a delicate, glossy feel.
  const sheen = g.createLinearGradient(-hw * 0.3, 0, hw * 0.3, 0)
  sheen.addColorStop(0, 'rgba(255,255,255,0)')
  sheen.addColorStop(0.5, 'rgba(255,255,255,0.28)')
  sheen.addColorStop(1, 'rgba(255,255,255,0)')
  g.fillStyle = sheen
  g.fill()

  return cv
}

interface Petal {
  baseX: number
  y: number
  size: number
  vy: number // fall speed (px/s)
  angle: number
  spin: number // rad/s
  swayAmp: number
  swayFreq: number
  swayPhase: number
  alpha: number
  sprite: number
}

export function PetalFall() {
  const canvasRef = useRef<HTMLCanvasElement>(null)

  useEffect(() => {
    const reduce =
      typeof window !== 'undefined' &&
      window.matchMedia?.('(prefers-reduced-motion: reduce)').matches
    if (reduce) return // respect users who don't want ambient motion

    const el = canvasRef.current
    if (!el) return
    const c2d = el.getContext('2d')
    if (!c2d) return
    // Non-null aliases so the render closures keep the narrowed types.
    const canvas = el
    const ctx = c2d

    const sprites = PALETTE.map(makeSprite)
    const dpr = Math.min(window.devicePixelRatio || 1, 2)
    let W = window.innerWidth
    let H = window.innerHeight

    // Scale petal count to the viewport so it stays sparse and gentle.
    const count = Math.round(Math.min(46, Math.max(16, (W * H) / 46000)))
    const rnd = (a: number, b: number) => a + Math.random() * (b - a)

    const spawn = (initial: boolean): Petal => ({
      baseX: rnd(0, W),
      y: initial ? rnd(-H, H) : rnd(-60, -20),
      size: rnd(16, 38),
      vy: rnd(22, 52),
      angle: rnd(0, Math.PI * 2),
      spin: rnd(-0.9, 0.9),
      swayAmp: rnd(14, 42),
      swayFreq: rnd(0.3, 0.85),
      swayPhase: rnd(0, Math.PI * 2),
      alpha: rnd(0.5, 0.82),
      sprite: Math.floor(Math.random() * sprites.length),
    })

    let petals = Array.from({ length: count }, () => spawn(true))

    function resize() {
      W = window.innerWidth
      H = window.innerHeight
      canvas.width = Math.floor(W * dpr)
      canvas.height = Math.floor(H * dpr)
      canvas.style.width = `${W}px`
      canvas.style.height = `${H}px`
      ctx.setTransform(dpr, 0, 0, dpr, 0, 0)
    }
    resize()
    window.addEventListener('resize', resize)

    let raf = 0
    let running = true
    let last = performance.now()

    function frame(now: number) {
      if (!running) return
      const dt = Math.min(0.05, (now - last) / 1000) // clamp big gaps (tab wake)
      last = now
      const t = now / 1000
      ctx.clearRect(0, 0, W, H)

      for (const p of petals) {
        p.y += p.vy * dt
        p.angle += p.spin * dt
        const x = p.baseX + p.swayAmp * Math.sin(t * p.swayFreq + p.swayPhase)

        // Recycle once fully past the bottom.
        if (p.y - p.size > H) {
          Object.assign(p, spawn(false))
          continue
        }

        ctx.save()
        ctx.translate(x, p.y)
        ctx.rotate(p.angle)
        ctx.globalAlpha = p.alpha
        ctx.drawImage(sprites[p.sprite], -p.size / 2, -p.size / 2, p.size, p.size)
        ctx.restore()
      }
      raf = requestAnimationFrame(frame)
    }

    const onVisibility = () => {
      if (document.hidden) {
        running = false
        cancelAnimationFrame(raf)
      } else if (!running) {
        running = true
        last = performance.now()
        raf = requestAnimationFrame(frame)
      }
    }
    document.addEventListener('visibilitychange', onVisibility)
    raf = requestAnimationFrame(frame)

    return () => {
      running = false
      cancelAnimationFrame(raf)
      window.removeEventListener('resize', resize)
      document.removeEventListener('visibilitychange', onVisibility)
      petals = []
    }
  }, [])

  return (
    <canvas
      ref={canvasRef}
      aria-hidden
      className="petal-fall pointer-events-none fixed inset-0"
      style={{ zIndex: 20 }}
    />
  )
}
