import React, {
  useRef,
  useEffect,
  useImperativeHandle,
  useCallback,
  forwardRef,
  ReactNode,
  Ref,
  useState,
} from 'react'
import gsap from 'gsap'
import { Draggable } from 'gsap/Draggable'
import { motion } from 'framer-motion'

gsap.registerPlugin(Draggable)

export interface HorizontalScrollerProps {
  children: ReactNode[]
  itemWidth?: number | string
  gap?: number
  selectedIndex?: number
  onItemClick?: (index: number) => void
}

export interface HorizontalScrollerRef {
  scrollToIndex: (index: number) => void
}

const HorizontalScroller = forwardRef(
  (
    {
      children,
      itemWidth = 300,
      gap = 16,
      selectedIndex,
      onItemClick,
    }: HorizontalScrollerProps,
    ref: Ref<HorizontalScrollerRef>
  ) => {
    const containerRef = useRef<HTMLDivElement>(null)
    const wrapperRef = useRef<HTMLDivElement>(null)
    const dragInstance = useRef<Draggable | null>(null)
    const itemRefs = useRef<(HTMLDivElement | null)[]>([])
    const [currentIndex, setCurrentIndex] = useState(selectedIndex || 0)
    const [isFocused, setIsFocused] = useState(false)

    const scrollToIndex = useCallback(
      (index: number) => {
        if (!containerRef.current || !wrapperRef.current || index < 0 || index >= children.length) return

        const containerWidth = containerRef.current.offsetWidth
        let targetX = 0

        if (itemWidth === 'auto') {
          const itemElement = itemRefs.current[index]
          if (!itemElement) return

          const itemRect = itemElement.getBoundingClientRect()
          const wrapperRect = wrapperRef.current.getBoundingClientRect()
          targetX = -(itemElement.offsetLeft - (containerWidth - itemRect.width) / 2)
        } else {
          const numericWidth = typeof itemWidth === 'number' ? itemWidth : parseFloat(itemWidth)
          targetX = -(index * (numericWidth + gap) - (containerWidth - numericWidth) / 2)
        }

        const maxScroll = wrapperRef.current.scrollWidth - containerWidth
        targetX = Math.max(-maxScroll, Math.min(targetX, 0))

        gsap.to(wrapperRef.current, {
          x: targetX,
          duration: 0.6,
          ease: 'power3.out',
          onUpdate: () => {
            if (dragInstance.current?.update) {
              dragInstance.current.update()
            }
          },
        })

        setCurrentIndex(index)
      },
      [itemWidth, gap, children.length]
    )

    useEffect(() => {
      if (!wrapperRef.current || !containerRef.current) return

      const maxScroll =
        wrapperRef.current.scrollWidth - containerRef.current.offsetWidth

      dragInstance.current = Draggable.create(wrapperRef.current, {
        type: 'x',
        edgeResistance: 0.85,
        inertia: true,
        bounds: {
          minX: -maxScroll,
          maxX: 0,
        },
        onDrag: function () {
          gsap.to(wrapperRef.current!, {
            x: this.x,
            duration: 0.3,
            ease: 'power3.out',
          })
        },
      })[0]
    }, [])

    useEffect(() => {
      if (typeof selectedIndex === 'number') {
        scrollToIndex(selectedIndex)
      }
    }, [selectedIndex, scrollToIndex])

    useEffect(() => {
      const handleKeyDown = (e: KeyboardEvent) => {
        // 只在容器被聚焦时处理键盘事件
        if (!isFocused) return;

        if (e.key === 'ArrowLeft') {
          e.preventDefault()
          let newIndex = Math.max(0, currentIndex - 1)
          if (newIndex === 0 && currentIndex - 1 < 0) {
            newIndex = children.length - 1
          }
          onItemClick?.(newIndex)
        } else if (e.key === 'ArrowRight') {
          e.preventDefault()
          let newIndex = Math.min(children.length - 1, currentIndex + 1)
          if (newIndex === children.length - 1 && currentIndex + 1 > children.length - 1) {
            newIndex = 0
          }
          onItemClick?.(newIndex)
        }
      }

      window.addEventListener('keydown', handleKeyDown)
      return () => window.removeEventListener('keydown', handleKeyDown)
    }, [currentIndex, children.length, scrollToIndex, onItemClick, isFocused])

    useImperativeHandle(ref, () => ({
      scrollToIndex,
    }))

    return (
      <div
        ref={containerRef}
        tabIndex={0}
        className="relative w-full overflow-auto touch-none cursor-grab active:cursor-grabbing focus:outline-none"
        onFocus={() => setIsFocused(true)}
        onBlur={() => setIsFocused(false)}
      >
        <div
          ref={wrapperRef}
          className="flex select-none"
          style={{ gap: `${gap}px` }}
        >
          {React.Children.map(children, (child, index) => (
            <motion.div
              key={index}
              onClick={() => {
                onItemClick?.(index)
              }}
              ref={(el) => (itemRefs.current[index] = el)}
              style={{
                minWidth: itemWidth === 'auto' ? 'auto' : itemWidth,
                flexShrink: 0,
              }}
              className={`p-2 rounded-lg overflow-hidden cursor-pointer hover:scale-[1.03] transition-transform duration-300`}
            >
              {child}
            </motion.div>
          ))}
        </div>
      </div>
    )
  }
)

export default HorizontalScroller
