'use client'

import {
  motion,
  useInView,
  useMotionValue,
  useSpring,
  type Variants,
} from 'framer-motion'
import { useEffect, useRef, type ReactNode } from 'react'

type Direction = 'up' | 'down' | 'left' | 'right' | 'zoom-in' | 'zoom-out'

const offset = 40

function getInitial(direction: Direction) {
  switch (direction) {
    case 'up':
      return { opacity: 0, y: offset }
    case 'down':
      return { opacity: 0, y: -offset }
    case 'left':
      return { opacity: 0, x: offset }
    case 'right':
      return { opacity: 0, x: -offset }
    case 'zoom-in':
      return { opacity: 0, scale: 0.9 }
    case 'zoom-out':
      return { opacity: 0, scale: 1.08 }
    default:
      return { opacity: 0, y: offset }
  }
}

export function Reveal({
  children,
  direction = 'up',
  delay = 0,
  duration = 0.7,
  className,
  once = true,
}: {
  children: ReactNode
  direction?: Direction
  delay?: number
  duration?: number
  className?: string
  once?: boolean
}) {
  return (
    <motion.div
      className={className}
      initial={getInitial(direction)}
      whileInView={{ opacity: 1, x: 0, y: 0, scale: 1 }}
      viewport={{ once, amount: 0.25 }}
      transition={{
        duration,
        delay,
        ease: [0.22, 1, 0.36, 1],
      }}
    >
      {children}
    </motion.div>
  )
}

const containerVariants: Variants = {
  hidden: {},
  show: {
    transition: { staggerChildren: 0.12, delayChildren: 0.1 },
  },
}

const itemVariants: Variants = {
  hidden: { opacity: 0, y: 30 },
  show: {
    opacity: 1,
    y: 0,
    transition: { duration: 0.6, ease: [0.22, 1, 0.36, 1] },
  },
}

export function StaggerGroup({
  children,
  className,
}: {
  children: ReactNode
  className?: string
}) {
  return (
    <motion.div
      className={className}
      variants={containerVariants}
      initial="hidden"
      whileInView="show"
      viewport={{ once: true, amount: 0.2 }}
    >
      {children}
    </motion.div>
  )
}

export function StaggerItem({
  children,
  className,
}: {
  children: ReactNode
  className?: string
}) {
  return (
    <motion.div className={className} variants={itemVariants}>
      {children}
    </motion.div>
  )
}

export function Counter({
  value,
  suffix = '',
  className,
}: {
  value: number
  suffix?: string
  className?: string
}) {
  const ref = useRef<HTMLSpanElement>(null)
  const inView = useInView(ref, { once: true, amount: 0.5 })
  const motionValue = useMotionValue(0)
  const spring = useSpring(motionValue, { duration: 1800, bounce: 0 })

  useEffect(() => {
    if (inView) motionValue.set(value)
  }, [inView, value, motionValue])

  useEffect(() => {
    return spring.on('change', (latest) => {
      if (ref.current) {
        ref.current.textContent = Math.round(latest).toString()
      }
    })
  }, [spring])

  return (
    <span className={className}>
      <span ref={ref}>0</span>
      {suffix}
    </span>
  )
}
