import React, { useRef, useCallback, useState, ReactNode, KeyboardEvent, TouchEvent } from 'react';

interface CarouselProps {
  children: ReactNode;
  activeIndex: number;
  setActiveIndex: (index: number) => void;
  labels?: string[];
  showLabels?: boolean;
  className?: string;
}

function Carousel({ 
  children, 
  activeIndex, 
  setActiveIndex, 
  labels = [],
  showLabels = true,
  className = ''
}: CarouselProps) {
  const touchStartX = useRef<number | null>(null);
  const touchStartY = useRef<number | null>(null);
  const trackRef = useRef<HTMLDivElement | null>(null);
  const [isDragging, setIsDragging] = useState(false);
  const [dragOffset, setDragOffset] = useState(0);
  const itemCount = React.Children.count(children);
  
  // Threshold for swipe detection
  const SWIPE_THRESHOLD = 50;
  const VELOCITY_THRESHOLD = 0.3;
  
  const handleTouchStart = useCallback((e: TouchEvent<HTMLDivElement>) => {
    touchStartX.current = e.touches[0].clientX;
    touchStartY.current = e.touches[0].clientY;
    setIsDragging(true);
    setDragOffset(0);
  }, []);

  const handleTouchMove = useCallback((e: TouchEvent<HTMLDivElement>) => {
    if (!touchStartX.current || !isDragging) return;
    
    const currentX = e.touches[0].clientX;
    const currentY = e.touches[0].clientY;
    const diffX = currentX - touchStartX.current;
    const diffY = currentY - (touchStartY.current || 0);
    
    // Only handle horizontal swipes
    if (Math.abs(diffX) > Math.abs(diffY)) {
      e.preventDefault();
      // Add resistance at edges
      let offset = diffX;
      if ((activeIndex === 0 && diffX > 0) || (activeIndex === itemCount - 1 && diffX < 0)) {
        offset = diffX * 0.3; // Rubber band effect
      }
      setDragOffset(offset);
    }
  }, [isDragging, activeIndex, itemCount]);

  const handleTouchEnd = useCallback((e: TouchEvent<HTMLDivElement>) => {
    if (!touchStartX.current || !isDragging) return;
    
    const endX = e.changedTouches[0].clientX;
    const diff = touchStartX.current - endX;
    const velocity = Math.abs(diff) / 200; // Rough velocity calc
    
    // Determine if we should change slide
    if (Math.abs(diff) > SWIPE_THRESHOLD || velocity > VELOCITY_THRESHOLD) {
      if (diff > 0 && activeIndex < itemCount - 1) {
        setActiveIndex(activeIndex + 1);
      } else if (diff < 0 && activeIndex > 0) {
        setActiveIndex(activeIndex - 1);
      }
    }
    
    // Reset
    touchStartX.current = null;
    touchStartY.current = null;
    setIsDragging(false);
    setDragOffset(0);
  }, [isDragging, activeIndex, setActiveIndex, itemCount]);

  const handleKeyDown = useCallback((e: KeyboardEvent<HTMLDivElement>) => {
    if (e.key === 'ArrowLeft' && activeIndex > 0) {
      setActiveIndex(activeIndex - 1);
    } else if (e.key === 'ArrowRight' && activeIndex < itemCount - 1) {
      setActiveIndex(activeIndex + 1);
    }
  }, [activeIndex, setActiveIndex, itemCount]);

  // Calculate transform
  const baseTransform = -(activeIndex * 100);
  const dragPercentage = trackRef.current ? (dragOffset / trackRef.current.offsetWidth) * 100 : 0;
  const transform = baseTransform + dragPercentage;

  return (
    <div 
      className={`carousel ${className}`} 
      onKeyDown={handleKeyDown} 
      tabIndex={0}
      role="region"
      aria-label="Carousel"
    >
      <div className="carousel-container">
        <div className="carousel-viewport">
          <div 
            ref={trackRef}
            className="carousel-track"
            style={{ 
              transform: `translateX(${transform}%)`,
              transition: isDragging ? 'none' : 'transform 400ms cubic-bezier(0.25, 0.46, 0.45, 0.94)'
            }}
            onTouchStart={handleTouchStart}
            onTouchMove={handleTouchMove}
            onTouchEnd={handleTouchEnd}
          >
            {React.Children.map(children, (child, i) => (
              <div 
                className="carousel-slide" 
                key={i}
                role="tabpanel"
                aria-hidden={activeIndex !== i}
                aria-label={labels[i] || `Slide ${i + 1}`}
              >
                {child}
              </div>
            ))}
          </div>
        </div>
      </div>
      
      <div className={`carousel-dots ${showLabels ? 'labeled' : ''}`} role="tablist">
        {Array.from({ length: itemCount }).map((_, i) => (
          <button
            key={i}
            className={`carousel-dot ${activeIndex === i ? 'active' : ''}`}
            onClick={() => setActiveIndex(i)}
            role="tab"
            aria-selected={activeIndex === i}
            aria-label={labels[i] || `Slide ${i + 1}`}
            aria-controls={`slide-${i}`}
          >
            {showLabels && labels[i] && (
              <span className="dot-label">{labels[i]}</span>
            )}
          </button>
        ))}
      </div>
    </div>
  );
}

export default Carousel;
