"use client";

import React from "react";
import {
  AnimationType,
  AnimationWrapperProps,
  DEFAULT_BUTTON_ANIMATION_TYPE,
} from "./types";
import { motion, useReducedMotion } from "framer-motion";

interface AnimationPreset {
  whileHover: Record<string, unknown>;
  whileTap?: Record<string, unknown>;
  transition: Record<string, unknown>;
}

const ANIMATION_PRESETS: Record<AnimationType, AnimationPreset> = {
  scale: {
    whileHover: { scale: 1.02 },
    whileTap: { scale: 0.98 },
    transition: { duration: 0.3 },
  },
  shadow: {
    whileHover: { boxShadow: "0 10px 25px rgba(0,0,0,0.15)" },
    transition: { duration: 0.3 },
  },
  lift: {
    whileHover: { y: -5 },
    whileTap: { y: 0 },
    transition: { type: "spring", stiffness: 300, damping: 20 },
  },
  opacity: {
    whileHover: { opacity: 0.8 },
    transition: { duration: 0.2 },
  },
  grow: {
    whileHover: { scale: 1.1 },
    whileTap: { scale: 0.95 },
    transition: { type: "spring", stiffness: 300, damping: 20 },
  },
  pop: {
    whileHover: { scale: 1.05 },
    whileTap: { scale: 0.95 },
    transition: { duration: 0.15 },
  },
};

function mergePresets(animationType?: AnimationType | AnimationType[]) {
  if (!animationType) return undefined;

  const types = Array.isArray(animationType) ? animationType : [animationType];
  if (types.length === 0) return undefined;

  return types.reduce<AnimationPreset>(
    (merged, type) => {
      const preset = ANIMATION_PRESETS[type];
      return {
        whileHover: { ...merged.whileHover, ...preset.whileHover },
        ...(merged.whileTap || preset.whileTap
          ? {
              whileTap: { ...merged.whileTap, ...preset.whileTap },
            }
          : {}),
        transition: { ...merged.transition, ...preset.transition },
      };
    },
    { whileHover: {}, transition: {} }
  );
}

export function AnimationWrapper({
  children,
  animationType = DEFAULT_BUTTON_ANIMATION_TYPE,
  // default to true for backward compatibility
  disableAnimation = true,
  whileHover,
  whileTap,
  transition,
  ...motionProps
}: AnimationWrapperProps) {
  const prefersReducedMotion = useReducedMotion();

  const child = React.Children.only(children) as React.ReactElement<
    Record<string, unknown>
  >;

  if (disableAnimation || prefersReducedMotion) {
    return child;
  }

  // Use the provided animationType, falling back to the centralized default.
  const preset = mergePresets(animationType);

  const mergedWhileHover = preset
    ? { ...preset.whileHover, ...(whileHover as Record<string, unknown>) }
    : whileHover;

  const mergedWhileTap =
    preset?.whileTap || whileTap
      ? { ...preset?.whileTap, ...(whileTap as Record<string, unknown>) }
      : undefined;

  const mergedTransition = preset
    ? { ...preset.transition, ...(transition as Record<string, unknown>) }
    : transition;

  const isIntrinsicElement = typeof child.type === "string";

  if (isIntrinsicElement) {
    const MotionComponent = motion[
      child.type as keyof typeof motion
    ] as React.ComponentType<Record<string, unknown>>;

    return (
      <MotionComponent
        {...child.props}
        ref={(child as any).ref}
        whileHover={mergedWhileHover}
        whileTap={mergedWhileTap}
        transition={mergedTransition}
        {...motionProps}
      />
    );
  }

  return (
    <motion.div
      whileHover={mergedWhileHover}
      whileTap={mergedWhileTap}
      transition={mergedTransition}
      {...motionProps}
    >
      {child}
    </motion.div>
  );
}

AnimationWrapper.displayName = "AnimationWrapper";

export { DEFAULT_BUTTON_ANIMATION_TYPE };
export type { AnimationWrapperProps, AnimationType };
