"use client";

import {
  motion,
  useMotionValue,
  useTransform,
  animate,
  useInView,
  type HTMLMotionProps,
} from "framer-motion";
import {
  forwardRef,
  Key,
  type ReactNode,
  useEffect,
  useRef,
  useState,
} from "react";

// ========================
// Shared animation variants
// ========================

export const fadeInVariants = {
  hidden: { opacity: 0 },
  visible: { opacity: 1 },
};

export const slideUpVariants = {
  hidden: { opacity: 0, y: 24 },
  visible: { opacity: 1, y: 0 },
};

export const slideDownVariants = {
  hidden: { opacity: 0, y: -24 },
  visible: { opacity: 1, y: 0 },
};

export const slideLeftVariants = {
  hidden: { opacity: 0, x: 40 },
  visible: { opacity: 1, x: 0 },
};

export const slideRightVariants = {
  hidden: { opacity: 0, x: -40 },
  visible: { opacity: 1, x: 0 },
};

export const scaleInVariants = {
  hidden: { opacity: 0, scale: 0.9 },
  visible: { opacity: 1, scale: 1 },
};

export const blurInVariants = {
  hidden: { opacity: 0, filter: "blur(10px)" },
  visible: { opacity: 1, filter: "blur(0px)" },
};

export const staggerContainerVariants = {
  hidden: {},
  visible: {
    transition: {
      staggerChildren: 0.08,
    },
  },
};

// ========================
// Spring presets
// ========================

export const springs = {
  gentle: { type: "spring" as const, stiffness: 120, damping: 14 },
  bouncy: { type: "spring" as const, stiffness: 300, damping: 15 },
  snappy: { type: "spring" as const, stiffness: 400, damping: 25 },
  smooth: { duration: 0.5, ease: [0.25, 0.1, 0.25, 1] as const },
};

// ========================
// Generic Motion Wrappers (animate on mount)
// ========================

interface MotionWrapperProps extends HTMLMotionProps<"div"> {
  children: ReactNode;
}

export const FadeIn = forwardRef<HTMLDivElement, MotionWrapperProps>(
  ({ children, ...props }, ref) => (
    <motion.div
      ref={ref}
      initial="hidden"
      animate="visible"
      variants={fadeInVariants}
      transition={{ duration: 0.4 }}
      {...props}
    >
      {children}
    </motion.div>
  ),
);
FadeIn.displayName = "FadeIn";

export const SlideUp = forwardRef<HTMLDivElement, MotionWrapperProps>(
  ({ children, ...props }, ref) => (
    <motion.div
      ref={ref}
      initial="hidden"
      animate="visible"
      variants={slideUpVariants}
      transition={springs.smooth}
      {...props}
    >
      {children}
    </motion.div>
  ),
);
SlideUp.displayName = "SlideUp";

export const ScaleIn = forwardRef<HTMLDivElement, MotionWrapperProps>(
  ({ children, ...props }, ref) => (
    <motion.div
      ref={ref}
      initial="hidden"
      animate="visible"
      variants={scaleInVariants}
      transition={springs.gentle}
      {...props}
    >
      {children}
    </motion.div>
  ),
);
ScaleIn.displayName = "ScaleIn";

export const BlurIn = forwardRef<HTMLDivElement, MotionWrapperProps>(
  ({ children, ...props }, ref) => (
    <motion.div
      ref={ref}
      initial="hidden"
      animate="visible"
      variants={blurInVariants}
      transition={{ duration: 0.6 }}
      {...props}
    >
      {children}
    </motion.div>
  ),
);
BlurIn.displayName = "BlurIn";

// ========================
// Scroll-based motion (whileInView)
// ========================

interface ScrollMotionProps extends HTMLMotionProps<"div"> {
  children: ReactNode;
  /** How much of the element must be visible (0–1). Default: 0.2 */
  threshold?: number;
  /** Animate only once? Default: true */
  once?: boolean;
}

export const ScrollFadeIn = forwardRef<HTMLDivElement, ScrollMotionProps>(
  ({ children, threshold = 0.2, once = true, ...props }, ref) => (
    <motion.div
      ref={ref}
      initial="hidden"
      whileInView="visible"
      viewport={{ once, amount: threshold }}
      variants={fadeInVariants}
      transition={{ duration: 0.5 }}
      {...props}
    >
      {children}
    </motion.div>
  ),
);
ScrollFadeIn.displayName = "ScrollFadeIn";

export const ScrollSlideUp = forwardRef<HTMLDivElement, ScrollMotionProps>(
  ({ children, threshold = 0.15, once = true, ...props }, ref) => (
    <motion.div
      ref={ref}
      initial="hidden"
      whileInView="visible"
      viewport={{ once, amount: threshold }}
      variants={slideUpVariants}
      transition={springs.smooth}
      {...props}
    >
      {children}
    </motion.div>
  ),
);
ScrollSlideUp.displayName = "ScrollSlideUp";

export const ScrollScaleIn = forwardRef<HTMLDivElement, ScrollMotionProps>(
  ({ children, threshold = 0.2, once = true, ...props }, ref) => (
    <motion.div
      ref={ref}
      initial="hidden"
      whileInView="visible"
      viewport={{ once, amount: threshold }}
      variants={scaleInVariants}
      transition={springs.gentle}
      {...props}
    >
      {children}
    </motion.div>
  ),
);
ScrollScaleIn.displayName = "ScrollScaleIn";

export const ScrollBlurIn = forwardRef<HTMLDivElement, ScrollMotionProps>(
  ({ children, threshold = 0.2, once = true, ...props }, ref) => (
    <motion.div
      ref={ref}
      initial="hidden"
      whileInView="visible"
      viewport={{ once, amount: threshold }}
      variants={blurInVariants}
      transition={{ duration: 0.7 }}
      {...props}
    >
      {children}
    </motion.div>
  ),
);
ScrollBlurIn.displayName = "ScrollBlurIn";

export const ScrollSlideLeft = forwardRef<HTMLDivElement, ScrollMotionProps>(
  ({ children, threshold = 0.15, once = true, ...props }, ref) => (
    <motion.div
      ref={ref}
      initial="hidden"
      whileInView="visible"
      viewport={{ once, amount: threshold }}
      variants={slideLeftVariants}
      transition={springs.smooth}
      {...props}
    >
      {children}
    </motion.div>
  ),
);
ScrollSlideLeft.displayName = "ScrollSlideLeft";

export const ScrollSlideRight = forwardRef<HTMLDivElement, ScrollMotionProps>(
  ({ children, threshold = 0.15, once = true, ...props }, ref) => (
    <motion.div
      ref={ref}
      initial="hidden"
      whileInView="visible"
      viewport={{ once, amount: threshold }}
      variants={slideRightVariants}
      transition={springs.smooth}
      {...props}
    >
      {children}
    </motion.div>
  ),
);
ScrollSlideRight.displayName = "ScrollSlideRight";

// ========================
// Stagger Container — animate children one by one
// ========================

interface StaggerProps extends HTMLMotionProps<"div"> {
  children: ReactNode;
  staggerDelay?: number;
  /** Use whileInView instead of animate? Default: false */
  inView?: boolean;
}

export const StaggerContainer = forwardRef<HTMLDivElement, StaggerProps>(
  ({ children, staggerDelay = 0.08, inView = false, ...props }, ref) => {
    const baseProps = {
      ref,
      variants: {
        hidden: {},
        visible: { transition: { staggerChildren: staggerDelay } },
      },
      ...props,
    };

    if (inView) {
      return (
        <motion.div
          {...baseProps}
          initial="hidden"
          whileInView="visible"
          viewport={{ once: true, amount: 0.1 }}
        >
          {children}
        </motion.div>
      );
    }

    return (
      <motion.div {...baseProps} initial="hidden" animate="visible">
        {children}
      </motion.div>
    );
  },
);
StaggerContainer.displayName = "StaggerContainer";

// ========================
// Stagger Item — use as direct child of StaggerContainer
// ========================

export const StaggerItem = forwardRef<HTMLDivElement, MotionWrapperProps>(
  ({ children, ...props }, ref) => (
    <motion.div
      ref={ref}
      variants={slideUpVariants}
      transition={springs.smooth}
      {...props}
    >
      {children}
    </motion.div>
  ),
);
StaggerItem.displayName = "StaggerItem";

// ========================
// Animated Counter — REAL counting with number interpolation
// ========================

interface AnimatedCounterProps {
  /** Target value to count up to */
  value: number;
  suffix?: string;
  prefix?: string;
  /** Duration in seconds. Default: 2 */
  duration?: number;
  /** Only animate when visible? Default: true */
  inView?: boolean;
}

export function AnimatedCounter({
  value,
  suffix = "",
  prefix = "",
  duration = 2,
  inView = true,
}: AnimatedCounterProps) {
  const ref = useRef<HTMLSpanElement>(null);
  const motionValue = useMotionValue(0);
  const rounded = useTransform(motionValue, (latest) =>
    Intl.NumberFormat("tr-TR").format(Math.round(latest)),
  );
  const isInView = useInView(ref, { once: true, amount: 0.5 });

  useEffect(() => {
    if (!inView || isInView) {
      const controls = animate(motionValue, value, {
        duration,
        ease: [0.25, 0.1, 0.25, 1],
      });
      return controls.stop;
    }
  }, [motionValue, value, duration, inView, isInView]);

  return (
    <motion.span
      ref={ref}
      initial={{ opacity: 0, scale: 0.8 }}
      animate={isInView || !inView ? { opacity: 1, scale: 1 } : {}}
      transition={{ type: "spring", stiffness: 200, damping: 15 }}
    >
      {prefix}
      <motion.span>{rounded}</motion.span>
      {suffix}
    </motion.span>
  );
}

// ========================
// Sparkle / Particle Effect
// ========================

interface SparkleProps {
  /** Number of sparkle particles. Default: 6 */
  count?: number;
  /** Color of the sparkle. Default: "primary.300" */
  color?: string;
}

interface SparkleConfig {
  id: number;
  size: number;
  left: number;
  bottom: number;
  y: number;
  duration: number;
  delay: number;
}

export function Sparkles({
  count = 6,
  color = "rgba(56, 178, 172, 0.6)",
}: SparkleProps) {
  const [sparkles, setSparkles] = useState<SparkleConfig[]>([]);

  useEffect(() => {
    const newSparkles = Array.from({ length: count }).map((_, i) => ({
      id: i,
      size: 4 + Math.random() * 4,
      left: 10 + Math.random() * 80,
      bottom: Math.random() * 30,
      y: -(60 + Math.random() * 80),
      duration: 2.5 + Math.random() * 2,
      delay: Math.random() * 3,
    }));
    setSparkles(newSparkles);
  }, [count]);

  if (sparkles.length === 0) {
    return (
      <div
        style={{
          position: "absolute",
          inset: 0,
          overflow: "hidden",
          pointerEvents: "none",
        }}
      />
    );
  }

  return (
    <div
      style={{
        position: "absolute",
        inset: 0,
        overflow: "hidden",
        pointerEvents: "none",
      }}
    >
      {sparkles.map(
        (sparkle: {
          id: Key | null | undefined;
          size: any;
          left: any;
          bottom: any;
          y: string | number | null;
          duration: any;
          delay: any;
        }) => (
          <motion.div
            key={sparkle.id}
            style={{
              position: "absolute",
              width: sparkle.size,
              height: sparkle.size,
              borderRadius: "50%",
              background: color,
              left: `${sparkle.left}%`,
              bottom: `${sparkle.bottom}%`,
            }}
            animate={{
              y: [0, sparkle.y],
              opacity: [0, 1, 1, 0],
              scale: [0.5, 1, 0.8, 0],
            }}
            transition={{
              duration: sparkle.duration,
              repeat: Infinity,
              delay: sparkle.delay,
              ease: "easeOut",
            }}
          />
        ),
      )}
    </div>
  );
}

// ========================
// Gradient Orb — decorative floating orb
// ========================

interface GradientOrbProps {
  /** CSS color/gradient for the orb */
  color?: string;
  /** Size in px */
  size?: number;
  /** Position: top, left, right, bottom (CSS values) */
  top?: string;
  left?: string;
  right?: string;
  bottom?: string;
  /** Blur amount in px. Default: 60 */
  blur?: number;
}

export function GradientOrb({
  color = "rgba(56, 178, 172, 0.15)",
  size = 200,
  top,
  left,
  right,
  bottom,
  blur = 60,
}: GradientOrbProps) {
  return (
    <motion.div
      style={{
        position: "absolute",
        width: size,
        height: size,
        borderRadius: "50%",
        background: color,
        filter: `blur(${blur}px)`,
        top,
        left,
        right,
        bottom,
        pointerEvents: "none",
        zIndex: 0,
      }}
      animate={{
        y: [0, -15, 0],
        scale: [1, 1.05, 1],
      }}
      transition={{
        duration: 6,
        repeat: Infinity,
        ease: "easeInOut",
      }}
    />
  );
}
