"use client"

import React, { useEffect, useRef, useState, useCallback, useMemo } from "react"
import { motion, useMotionValue, useTransform, animate, PanInfo, useAnimation, AnimationControls, useSpring } from "framer-motion"
import { cva, type VariantProps } from "class-variance-authority"
import { cn } from "../../lib/utils"
import { X, Lock, Sparkles } from "lucide-react"
import { useSubscription } from "../../hooks/use-subscription"
import { Card, CardContent } from "../ui/card"
import { Button } from "../ui/button"

// Gesture Drawer Variants
const gestureDrawerVariants = cva(
  "fixed bg-background shadow-2xl overflow-hidden",
  {
    variants: {
      position: {
        bottom: "bottom-0 left-0 right-0 rounded-t-[20px] max-h-[95vh]",
        top: "top-0 left-0 right-0 rounded-b-[20px] max-h-[95vh]",
        left: "left-0 top-0 bottom-0 rounded-r-[20px] max-w-[90vw]",
        right: "right-0 top-0 bottom-0 rounded-l-[20px] max-w-[90vw]"
      },
      size: {
        default: "",
        sm: "",
        md: "",
        lg: "",
        full: ""
      }
    },
    compoundVariants: [
      {
        position: ["bottom", "top"],
        size: "sm",
        class: "h-[30vh]"
      },
      {
        position: ["bottom", "top"],
        size: "md",
        class: "h-[50vh]"
      },
      {
        position: ["bottom", "top"],
        size: "lg",
        class: "h-[70vh]"
      },
      {
        position: ["bottom", "top"],
        size: "full",
        class: "h-[95vh]"
      },
      {
        position: ["left", "right"],
        size: "sm",
        class: "w-[280px]"
      },
      {
        position: ["left", "right"],
        size: "md",
        class: "w-[380px]"
      },
      {
        position: ["left", "right"],
        size: "lg",
        class: "w-[480px]"
      },
      {
        position: ["left", "right"],
        size: "full",
        class: "w-[90vw]"
      }
    ],
    defaultVariants: {
      position: "bottom",
      size: "default"
    }
  }
)

// Handle/Indicator Variants
const handleVariants = cva(
  "absolute bg-muted-foreground/20 transition-all duration-200",
  {
    variants: {
      position: {
        bottom: "top-2 left-1/2 -translate-x-1/2 w-12 h-1 rounded-full",
        top: "bottom-2 left-1/2 -translate-x-1/2 w-12 h-1 rounded-full",
        left: "right-2 top-1/2 -translate-y-1/2 w-1 h-12 rounded-full",
        right: "left-2 top-1/2 -translate-y-1/2 w-1 h-12 rounded-full"
      }
    },
    defaultVariants: {
      position: "bottom"
    }
  }
)

export interface GestureDrawerProps extends Omit<React.HTMLAttributes<HTMLDivElement>, 'onAnimationStart' | 'onAnimationEnd' | 'onAnimationIteration' | 'onDragStart' | 'onDragEnd' | 'onDrag'>,
  VariantProps<typeof gestureDrawerVariants> {
  // Core props
  isOpen: boolean
  onOpenChange: (open: boolean) => void
  children: React.ReactNode
  
  // Position and size
  position?: "bottom" | "top" | "left" | "right"
  size?: "default" | "sm" | "md" | "lg" | "full"
  
  // Snap points (percentages of viewport)
  snapPoints?: number[]
  defaultSnapPoint?: number
  
  // Gesture options
  enableSwipeToClose?: boolean
  closeThreshold?: number
  closeVelocity?: number
  dragElastic?: number
  
  // Visual options
  showHandle?: boolean
  handleClassName?: string
  showCloseButton?: boolean
  closeButtonClassName?: string
  
  // Backdrop options
  showBackdrop?: boolean
  backdropClassName?: string
  backdropBlur?: boolean
  closeOnBackdropClick?: boolean
  
  // Animation options
  animationDuration?: number
  springConfig?: {
    stiffness?: number
    damping?: number
    mass?: number
  }
  
  // Advanced features
  preventBodyScroll?: boolean
  autoHeight?: boolean
  nestedScrolling?: boolean
  onSnapPointChange?: (snapPoint: number) => void
  
  // Component specific
  asChild?: boolean
  isProComponent?: boolean
}

// Body scroll lock hook
const useBodyScrollLock = (isLocked: boolean) => {
  useEffect(() => {
    if (!isLocked) return

    const originalStyle = window.getComputedStyle(document.body).overflow
    document.body.style.overflow = "hidden"

    return () => {
      document.body.style.overflow = originalStyle
    }
  }, [isLocked])
}

// Snap point calculation
const calculateSnapPoint = (
  offset: number,
  velocity: number,
  snapPoints: number[],
  direction: "up" | "down" | "left" | "right",
  viewportSize: number
): number => {
  const currentPosition = Math.abs(offset) / viewportSize * 100
  
  // Velocity-based snap
  if (Math.abs(velocity) > 500) {
    if ((direction === "up" || direction === "left") && velocity < 0) {
      // Swiping to open more
      const higherPoints = snapPoints.filter(p => p > currentPosition)
      return higherPoints.length > 0 ? higherPoints[0] : snapPoints[snapPoints.length - 1]
    } else if ((direction === "down" || direction === "right") && velocity > 0) {
      // Swiping to close
      const lowerPoints = snapPoints.filter(p => p < currentPosition)
      return lowerPoints.length > 0 ? lowerPoints[lowerPoints.length - 1] : 0
    }
  }
  
  // Find closest snap point
  return snapPoints.reduce((prev, curr) => 
    Math.abs(curr - currentPosition) < Math.abs(prev - currentPosition) ? curr : prev
  )
}

const MoonUIGestureDrawerProComponent = React.forwardRef<HTMLDivElement, GestureDrawerProps>(({
  isOpen,
  onOpenChange,
  children,
  position = "bottom",
  size = "default",
  snapPoints = size === "default" ? [25, 50, 75, 100] : [],
  defaultSnapPoint,
  enableSwipeToClose = true,
  closeThreshold = 20,
  closeVelocity = 500,
  dragElastic = 0.2,
  showHandle = true,
  handleClassName,
  showCloseButton = false,
  closeButtonClassName,
  showBackdrop = true,
  backdropClassName,
  backdropBlur = true,
  closeOnBackdropClick = true,
  animationDuration = 0.5,
  springConfig = {
    stiffness: 300,
    damping: 30,
    mass: 1
  },
  preventBodyScroll = true,
  autoHeight = false,
  nestedScrolling = true,
  onSnapPointChange,
  className,
  asChild = false,
  isProComponent = true,
  ...props
}, ref) => {
  const isVertical = position === "bottom" || position === "top"
  const controls = useAnimation()
  const dragControls = useAnimation()
  
  // Motion values
  const x = useMotionValue(0)
  const y = useMotionValue(0)
  const motionValue = isVertical ? y : x
  
  // State
  const [currentSnapPoint, setCurrentSnapPoint] = useState(
    defaultSnapPoint || (snapPoints.length > 0 ? snapPoints[0] : 50)
  )
  const [isDragging, setIsDragging] = useState(false)
  const contentRef = useRef<HTMLDivElement>(null)
  const [contentHeight, setContentHeight] = useState<number | null>(null)
  
  // Body scroll lock
  useBodyScrollLock(isOpen && preventBodyScroll)
  
  // Viewport dimensions
  const viewportSize = useMemo(() => {
    if (typeof window === "undefined") return 1000
    return isVertical ? window.innerHeight : window.innerWidth
  }, [isVertical])
  
  // Calculate position based on snap point
  const calculatePosition = useCallback((snapPoint: number) => {
    // For snap points, we don't need to calculate positions
    // CVA classes handle the static positioning
    // Motion values should only handle transforms during drag
    return 0
  }, [position, viewportSize])
  
  
  // Backdrop opacity - fixed when drawer is open
  const backdropOpacity = isOpen ? 0.5 : 0
  
  // Handle drag end
  const handleDragEnd = useCallback((event: any, info: PanInfo) => {
    setIsDragging(false)
    
    const offset = isVertical ? info.offset.y : info.offset.x
    const velocity = isVertical ? info.velocity.y : info.velocity.x
    
    // Check if should close
    const shouldClose = enableSwipeToClose && (
      (position === "bottom" && offset > closeThreshold && velocity > -closeVelocity) ||
      (position === "top" && offset < -closeThreshold && velocity < closeVelocity) ||
      (position === "right" && offset > closeThreshold && velocity > -closeVelocity) ||
      (position === "left" && offset < -closeThreshold && velocity < closeVelocity)
    )
    
    if (shouldClose) {
      onOpenChange(false)
      return
    }
    
    // Snap to point
    if (snapPoints.length > 0) {
      // Map position to direction for calculateSnapPoint
      const direction = position === "bottom" ? "down" : 
                      position === "top" ? "up" :
                      position === "left" ? "left" : "right"
      
      const newSnapPoint = calculateSnapPoint(
        Math.abs(motionValue.get()),
        velocity,
        snapPoints,
        direction,
        viewportSize
      )
      
      setCurrentSnapPoint(newSnapPoint)
      onSnapPointChange?.(newSnapPoint)
      
      animate(motionValue, calculatePosition(newSnapPoint), {
        type: "spring",
        ...springConfig
      })
    } else {
      // Return to original position
      animate(motionValue, calculatePosition(currentSnapPoint), {
        type: "spring",
        ...springConfig
      })
    }
  }, [
    isVertical,
    position,
    enableSwipeToClose,
    closeThreshold,
    closeVelocity,
    snapPoints,
    motionValue,
    viewportSize,
    calculatePosition,
    currentSnapPoint,
    springConfig,
    onOpenChange,
    onSnapPointChange
  ])
  
  // Handle drag start
  const handleDragStart = useCallback((event: any, info: PanInfo) => {
    setIsDragging(true)
  }, [])
  
  // Auto height calculation
  useEffect(() => {
    if (!autoHeight || !contentRef.current || !isOpen) return
    
    const resizeObserver = new ResizeObserver((entries) => {
      for (const entry of entries) {
        setContentHeight(entry.contentRect.height)
      }
    })
    
    resizeObserver.observe(contentRef.current)
    
    return () => {
      resizeObserver.disconnect()
    }
  }, [autoHeight, isOpen])
  
  // Animation on open/close - reset transform values
  useEffect(() => {
    if (isOpen) {
      // Reset to zero - CVA handles positioning
      animate(motionValue, 0, {
        type: "spring",
        ...springConfig
      })
    } else {
      // Reset transform
      animate(motionValue, 0, {
        type: "spring",
        ...springConfig
      })
    }
  }, [isOpen, motionValue, springConfig])
  
  // Keyboard accessibility
  useEffect(() => {
    if (!isOpen) return
    
    const handleKeyDown = (e: KeyboardEvent) => {
      if (e.key === "Escape" && enableSwipeToClose) {
        onOpenChange(false)
      }
    }
    
    document.addEventListener("keydown", handleKeyDown)
    return () => document.removeEventListener("keydown", handleKeyDown)
  }, [isOpen, enableSwipeToClose, onOpenChange])
  
  // Initial position - CVA handles static positioning
  const getInitialPosition = () => {
    return { x: 0, y: 0 }
  }
  
  // Drag constraints - allow reasonable drag movement
  const getDragConstraints = () => {
    switch (position) {
      case "bottom":
        return { top: -200, bottom: 100 }
      case "top":
        return { top: -100, bottom: 200 }
      case "right":
        return { left: -200, right: 100 }
      case "left":
        return { left: -100, right: 200 }
      default:
        return {}
    }
  }
  
  if (!isOpen) return null
  
  const drawerContent = (
    <motion.div
      initial={{ opacity: 0 }}
      animate={{ opacity: 1 }}
      exit={{ opacity: 0 }}
      transition={{ duration: animationDuration }}
      className="fixed inset-0 z-50"
      style={{ pointerEvents: isDragging ? "none" : "auto" }}
    >
      {/* Backdrop */}
      {showBackdrop && (
        <motion.div
          className={cn(
            "absolute inset-0 bg-black/50",
            backdropBlur && "backdrop-blur-sm",
            backdropClassName
          )}
          style={{ opacity: backdropOpacity }}
          onClick={closeOnBackdropClick ? () => onOpenChange(false) : undefined}
        />
      )}
      
      {/* Drawer */}
      <motion.div
        ref={ref}
        drag={enableSwipeToClose ? (isVertical ? "y" : "x") : false}
        dragConstraints={getDragConstraints()}
        dragElastic={dragElastic}
        onDragStart={handleDragStart}
        onDragEnd={handleDragEnd}
        initial={getInitialPosition()}
        style={{
          ...(isDragging ? { [isVertical ? "y" : "x"]: motionValue } : {}),
          ...(autoHeight && contentHeight && isVertical
            ? { height: `${Math.min(contentHeight + 60, viewportSize * 0.95)}px` }
            : {})
        }}
        className={cn(
          gestureDrawerVariants({ position, size }),
          "will-change-transform",
          className
        )}
        {...props}
      >
        {/* Handle */}
        {showHandle && (
          <div
            className={cn(
              handleVariants({ position }),
              "cursor-grab active:cursor-grabbing",
              isDragging && "bg-muted-foreground/40 scale-x-150",
              handleClassName
            )}
          />
        )}
        
        {/* Close button */}
        {showCloseButton && (
          <button
            onClick={() => onOpenChange(false)}
            className={cn(
              "absolute z-50 p-2 rounded-full bg-background/80 backdrop-blur-sm border shadow-sm",
              "hover:bg-background transition-colors",
              position === "bottom" && "top-3 right-3",
              position === "top" && "bottom-3 right-3",
              position === "left" && "top-3 right-3",
              position === "right" && "top-3 left-3",
              closeButtonClassName
            )}
            aria-label="Close drawer"
          >
            <X className="h-4 w-4" />
          </button>
        )}
        
        {/* Content wrapper for nested scrolling */}
        <div
          ref={contentRef}
          className={cn(
            "h-full overflow-auto overscroll-contain",
            nestedScrolling && "touch-pan-y",
            showHandle && position === "bottom" && "pt-2",
            showHandle && position === "top" && "pb-2"
          )}
          style={{
            // Prevent drag when scrolling content
            touchAction: nestedScrolling ? "pan-y" : "none"
          }}
        >
          {children}
        </div>
      </motion.div>
    </motion.div>
  )
  
  return drawerContent
})

MoonUIGestureDrawerProComponent.displayName = "MoonUIGestureDrawerProComponent"

export const MoonUIGestureDrawerPro = React.forwardRef<
  HTMLDivElement,
  GestureDrawerProps
>((props, ref) => {
  const { hasProAccess, isLoading } = useSubscription()
  
  // Show upgrade prompt if no pro access
  if (!isLoading && !hasProAccess) {
    return (
      <Card className="w-fit mx-auto">
        <CardContent className="py-6 text-center">
          <div className="space-y-4">
            <div className="rounded-full bg-purple-100 dark:bg-purple-900/30 p-3 w-fit mx-auto">
              <Lock className="h-6 w-6 text-purple-600 dark:text-purple-400" />
            </div>
            <div>
              <h3 className="font-semibold text-sm mb-2">Pro Feature</h3>
              <p className="text-muted-foreground text-xs mb-4">
                Gesture Drawer is available exclusively to MoonUI Pro subscribers.
              </p>
              <a href="/pricing">
                <Button size="sm">
                  <Sparkles className="mr-2 h-4 w-4" />
                  Upgrade to Pro
                </Button>
              </a>
            </div>
          </div>
        </CardContent>
      </Card>
    )
  }

  return <MoonUIGestureDrawerProComponent {...props} ref={ref} />
})

MoonUIGestureDrawerPro.displayName = "MoonUIGestureDrawerPro"

// Backward compatibility alias
export const GestureDrawer = MoonUIGestureDrawerPro

// Export types
export type MoonUIGestureDrawerProProps = GestureDrawerProps
export { gestureDrawerVariants as moonUIGestureDrawerProVariants }
export default MoonUIGestureDrawerPro