import React, { useRef, useState, useCallback, useEffect } from 'react';

interface Props {
  src: string;
  alt: string;
  className?: string;
}

interface Transform {
  scale: number;
  translateX: number;
  translateY: number;
}

export const GestureImageViewer: React.FC<Props> = ({ src, alt, className = '' }) => {
  const imageRef = useRef<HTMLImageElement>(null);
  const containerRef = useRef<HTMLDivElement>(null);

  const [transform, setTransform] = useState<Transform>({
    scale: 1,
    translateX: 0,
    translateY: 0,
  });

  const [isGestureActive, setIsGestureActive] = useState(false);
  const lastTouchRef = useRef<{ touches: React.TouchList; time: number } | null>(null);
  const initialTransformRef = useRef<Transform>({ scale: 1, translateX: 0, translateY: 0 });
  const initialDistanceRef = useRef<number>(0);
  const initialCenterRef = useRef<{ x: number; y: number }>({ x: 0, y: 0 });

  // Calculate distance between two touch points
  const getDistance = useCallback((touches: React.TouchList): number => {
    if (touches.length < 2) return 0;
    const dx = touches[0].clientX - touches[1].clientX;
    const dy = touches[0].clientY - touches[1].clientY;
    return Math.sqrt(dx * dx + dy * dy);
  }, []);

  // Calculate center point between two touches
  const getCenter = useCallback((touches: React.TouchList): { x: number; y: number } => {
    if (touches.length === 1) {
      return { x: touches[0].clientX, y: touches[0].clientY };
    }
    if (touches.length >= 2) {
      return {
        x: (touches[0].clientX + touches[1].clientX) / 2,
        y: (touches[0].clientY + touches[1].clientY) / 2,
      };
    }
    return { x: 0, y: 0 };
  }, []);

  // Get bounding box relative coordinates
  const getRelativeCoordinates = useCallback((clientX: number, clientY: number) => {
    if (!containerRef.current) return { x: 0, y: 0 };
    const rect = containerRef.current.getBoundingClientRect();
    return {
      x: clientX - rect.left,
      y: clientY - rect.top,
    };
  }, []);

  // Constrain transform to prevent image from moving too far out of bounds
  const constrainTransform = useCallback((newTransform: Transform): Transform => {
    if (!containerRef.current || !imageRef.current) return newTransform;

    const containerRect = containerRef.current.getBoundingClientRect();
    const imageRect = imageRef.current.getBoundingClientRect();

    const scaledWidth = imageRect.width * newTransform.scale;
    const scaledHeight = imageRect.height * newTransform.scale;

    // Calculate maximum allowed translation
    const maxTranslateX = Math.max(0, (scaledWidth - containerRect.width) / 2);
    const maxTranslateY = Math.max(0, (scaledHeight - containerRect.height) / 2);

    return {
      scale: Math.max(0.5, Math.min(5, newTransform.scale)), // Constrain scale between 0.5x and 5x
      translateX: Math.max(-maxTranslateX, Math.min(maxTranslateX, newTransform.translateX)),
      translateY: Math.max(-maxTranslateY, Math.min(maxTranslateY, newTransform.translateY)),
    };
  }, []);

  // Handle touch start
  const handleTouchStart = useCallback((e: React.TouchEvent) => {
    e.preventDefault();
    setIsGestureActive(true);

    const touches = e.touches;
    initialTransformRef.current = transform;

    if (touches.length === 2) {
      // Pinch gesture
      initialDistanceRef.current = getDistance(touches);
      const center = getCenter(touches);
      initialCenterRef.current = getRelativeCoordinates(center.x, center.y);
    } else if (touches.length === 1) {
      // Pan gesture or tap
      const center = getCenter(touches);
      initialCenterRef.current = getRelativeCoordinates(center.x, center.y);

      // Track for double-tap detection
      const now = Date.now();
      const lastTouch = lastTouchRef.current;

      if (lastTouch && now - lastTouch.time < 300 && touches.length === 1) {
        // Double tap - toggle zoom
        const isZoomedIn = transform.scale > 1.1;
        const newScale = isZoomedIn ? 1 : 2;

        if (isZoomedIn) {
          // Reset to original
          setTransform({ scale: 1, translateX: 0, translateY: 0 });
        } else {
          // Zoom to double-tap location
          const center = getRelativeCoordinates(touches[0].clientX, touches[0].clientY);
          setTransform({
            scale: newScale,
            translateX: (containerRef.current!.clientWidth / 2 - center.x) * (newScale - 1),
            translateY: (containerRef.current!.clientHeight / 2 - center.y) * (newScale - 1),
          });
        }
        lastTouchRef.current = null;
        return;
      }

      lastTouchRef.current = { touches, time: now };
    }
  }, [transform, getDistance, getCenter, getRelativeCoordinates]);

  // Handle touch move
  const handleTouchMove = useCallback((e: React.TouchEvent) => {
    if (!isGestureActive) return;
    e.preventDefault();

    const touches = e.touches;

    if (touches.length === 2) {
      // Pinch zoom
      const currentDistance = getDistance(touches);
      const center = getCenter(touches);
      const currentCenter = getRelativeCoordinates(center.x, center.y);

      if (initialDistanceRef.current > 0) {
        const scaleChange = currentDistance / initialDistanceRef.current;
        const newScale = initialTransformRef.current.scale * scaleChange;

        // Calculate translation to keep zoom centered on pinch point
        const scaleDiff = newScale - initialTransformRef.current.scale;
        const centerOffsetX = currentCenter.x - containerRef.current!.clientWidth / 2;
        const centerOffsetY = currentCenter.y - containerRef.current!.clientHeight / 2;

        const newTransform: Transform = {
          scale: newScale,
          translateX: initialTransformRef.current.translateX - centerOffsetX * scaleDiff,
          translateY: initialTransformRef.current.translateY - centerOffsetY * scaleDiff,
        };

        setTransform(constrainTransform(newTransform));
      }
    } else if (touches.length === 1 && transform.scale > 1) {
      // Pan when zoomed in
      const currentCenter = getRelativeCoordinates(touches[0].clientX, touches[0].clientY);
      const deltaX = currentCenter.x - initialCenterRef.current.x;
      const deltaY = currentCenter.y - initialCenterRef.current.y;

      const newTransform: Transform = {
        scale: transform.scale,
        translateX: initialTransformRef.current.translateX + deltaX,
        translateY: initialTransformRef.current.translateY + deltaY,
      };

      setTransform(constrainTransform(newTransform));
    }
  }, [isGestureActive, transform.scale, getDistance, getCenter, getRelativeCoordinates, constrainTransform]);

  // Handle touch end
  const handleTouchEnd = useCallback((e: React.TouchEvent) => {
    if (e.touches.length === 0) {
      setIsGestureActive(false);
    }
  }, []);

  // Handle wheel zoom for desktop
  const handleWheel = useCallback((e: React.WheelEvent) => {
    e.preventDefault();

    const delta = e.deltaY > 0 ? 0.9 : 1.1;
    const rect = containerRef.current?.getBoundingClientRect();
    if (!rect) return;

    const centerX = e.clientX - rect.left;
    const centerY = e.clientY - rect.top;

    const newScale = transform.scale * delta;
    const scaleDiff = newScale - transform.scale;
    const centerOffsetX = centerX - rect.width / 2;
    const centerOffsetY = centerY - rect.height / 2;

    const newTransform: Transform = {
      scale: newScale,
      translateX: transform.translateX - centerOffsetX * scaleDiff,
      translateY: transform.translateY - centerOffsetY * scaleDiff,
    };

    setTransform(constrainTransform(newTransform));
  }, [transform, constrainTransform]);

  // Reset transform when image changes
  useEffect(() => {
    setTransform({ scale: 1, translateX: 0, translateY: 0 });
  }, [src]);

  // Set appropriate touch-action CSS to manage touch behavior
  useEffect(() => {
    const container = containerRef.current;
    if (!container) return;

    // Use CSS touch-action instead of global preventDefault
    // This allows normal scrolling when not actively gesturing
    if (isGestureActive) {
      container.style.touchAction = 'none';
    } else {
      container.style.touchAction = 'manipulation';
    }

    return () => {
      if (container) {
        container.style.touchAction = '';
      }
    };
  }, [isGestureActive]);

  const transformStyle = {
    transform: `scale(${transform.scale}) translate(${transform.translateX}px, ${transform.translateY}px)`,
    transformOrigin: 'center center',
    transition: isGestureActive ? 'none' : 'transform 0.2s ease-out',
  };

  return (
    <div
      ref={containerRef}
      className={`relative overflow-hidden touch-none select-none ${className}`}
      onTouchStart={handleTouchStart}
      onTouchMove={handleTouchMove}
      onTouchEnd={handleTouchEnd}
      onWheel={handleWheel}
      style={{
        WebkitUserSelect: 'none',
        WebkitTouchCallout: 'none',
        touchAction: isGestureActive ? 'none' : 'manipulation',
      }}
    >
      <img
        ref={imageRef}
        src={src}
        alt={alt}
        style={transformStyle}
        className="w-full h-auto object-contain pointer-events-none"
        draggable={false}
      />

      {/* Reset button for zoomed images */}
      {transform.scale > 1.1 && (
        <button
          onClick={() => setTransform({ scale: 1, translateX: 0, translateY: 0 })}
          className="absolute top-4 right-4 bg-black bg-opacity-50 text-white px-3 py-1 rounded-full text-sm font-medium backdrop-blur-sm hover:bg-opacity-70 transition-colors"
          aria-label="Reset zoom"
        >
          Reset
        </button>
      )}

      {/* Instructions overlay for first-time users */}
      {transform.scale === 1 && (
        <div className="absolute bottom-4 left-1/2 transform -translate-x-1/2 bg-black bg-opacity-50 text-white px-3 py-1 rounded-full text-xs backdrop-blur-sm pointer-events-none">
          Pinch to zoom • Double-tap to zoom • Drag to pan
        </div>
      )}
    </div>
  );
};