'use client';

import { useState, useEffect, useRef, useCallback } from 'react';
import { useRouter } from 'next/navigation';
import { useSession } from 'next-auth/react';
import Image from 'next/image';
import { Photo, Person } from '@prisma/client';
import { ChevronLeft, ChevronRight, X, Play, Pause, ZoomIn, ZoomOut, RotateCcw, Flag, Heart, Download } from 'lucide-react';
import { Button } from '@/components/ui/button';
import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from '@/components/ui/select';
import {
  Dialog,
  DialogContent,
  DialogDescription,
  DialogFooter,
  DialogHeader,
  DialogTitle,
} from '@/components/ui/dialog';
import { parseFaceLocation, isPointInFaceWithFit } from '@/lib/face-utils';
import { isUrl, isVideo, getImageSrc, getVideoSrc } from '@/lib/photo-utils';
import { IdentifyFaceDialog } from '@/components/IdentifyFaceDialog';
import { LoginDialog } from '@/components/LoginDialog';
import { RegisterDialog } from '@/components/RegisterDialog';

interface FaceWithLocation {
  id: number;
  personId: number | null;
  location: string;
  person: Person | null;
}

interface PhotoWithDetails extends Photo {
  faces?: FaceWithLocation[];
  photoTags?: Array<{
    tag: {
      tagName: string;
    };
  }>;
}

interface PhotoViewerClientProps {
  initialPhoto: PhotoWithDetails;
  allPhotos: PhotoWithDetails[];
  currentIndex: number;
  onClose?: () => void;
  autoPlay?: boolean;
  slideInterval?: number; // in milliseconds
}

const REPORT_COMMENT_MAX_LENGTH = 300;

const getPhotoFilename = (photo: Photo) => {
  if (photo?.filename) {
    return photo.filename;
  }

  if (photo?.path) {
    const segments = photo.path.split(/[/\\]/);
    const lastSegment = segments.pop();
    if (lastSegment) {
      return lastSegment;
    }
  }

  return `photo-${photo?.id ?? 'download'}.jpg`;
};

const getPhotoDownloadUrl = (
  photo: Photo,
  options?: { forceProxy?: boolean; watermark?: boolean }
) => {
  const path = photo.path || '';
  const isExternal = path.startsWith('http://') || path.startsWith('https://');

  if (isExternal && !options?.forceProxy) {
    return path;
  }

  const params = new URLSearchParams();
  if (options?.watermark) {
    params.set('watermark', 'true');
  }
  const query = params.toString();

  return `/api/photos/${photo.id}/image${query ? `?${query}` : ''}`;
};


export function PhotoViewerClient({
  initialPhoto,
  allPhotos,
  currentIndex,
  onClose,
  autoPlay = false,
  slideInterval = 5000, // 5 seconds default
}: PhotoViewerClientProps) {
  const router = useRouter();
  const { data: session, update } = useSession();
  const isLoggedIn = Boolean(session);
  
  // Check if user has write access
  const hasWriteAccess = session?.user?.hasWriteAccess === true;
  
  // Debug logging
  useEffect(() => {
    if (session) {
      console.log('[PhotoViewerClient] Session:', {
        email: session.user?.email,
        hasWriteAccess: session.user?.hasWriteAccess,
        isAdmin: session.user?.isAdmin,
        computedHasWriteAccess: hasWriteAccess,
      });
    }
  }, [session, hasWriteAccess]);
  // Normalize photo data: ensure faces is always available (handle Face vs faces)
  const normalizePhoto = (photo: PhotoWithDetails): PhotoWithDetails => {
    const normalized = { ...photo };
    // If photo has Face (capital F) but no faces (lowercase), convert it
    if (!normalized.faces && (normalized as any).Face) {
      normalized.faces = (normalized as any).Face.map((face: any) => ({
        id: face.id,
        personId: face.person_id || face.personId,
        location: face.location,
        person: face.Person ? {
          id: face.Person.id,
          firstName: face.Person.first_name,
          lastName: face.Person.last_name,
          middleName: face.Person.middle_name,
          maidenName: face.Person.maiden_name,
          dateOfBirth: face.Person.date_of_birth,
        } : null,
      }));
    }
    return normalized;
  };

  const [currentPhoto, setCurrentPhoto] = useState<PhotoWithDetails>(normalizePhoto(initialPhoto));
  const [currentIdx, setCurrentIdx] = useState(currentIndex);
  const [imageLoading, setImageLoading] = useState(false);
  const [isPlaying, setIsPlaying] = useState(autoPlay);
  const [currentInterval, setCurrentInterval] = useState(slideInterval);
  const slideTimerRef = useRef<NodeJS.Timeout | null>(null);
  const [zoom, setZoom] = useState(1);
  const [panX, setPanX] = useState(0);
  const [panY, setPanY] = useState(0);
  const [isDragging, setIsDragging] = useState(false);
  const [dragStart, setDragStart] = useState({ x: 0, y: 0 });
  const [hoveredFace, setHoveredFace] = useState<{
    faceId: number;
    personId: number | null;
    personName: string | null;
    mouseX: number;
    mouseY: number;
  } | null>(null);
  const [clickedFace, setClickedFace] = useState<{
    faceId: number;
    person: Person | null;
  } | null>(null);
  const [isDialogOpen, setIsDialogOpen] = useState(false);
  const [reportingPhotoId, setReportingPhotoId] = useState<number | null>(null);
  const [isReported, setIsReported] = useState<boolean>(false);
  const [reportStatus, setReportStatus] = useState<string | null>(null);
  const [reportDialogPhotoId, setReportDialogPhotoId] = useState<number | null>(null);
  const [reportDialogComment, setReportDialogComment] = useState('');
  const [reportDialogError, setReportDialogError] = useState<string | null>(null);
  const [favoritingPhotoId, setFavoritingPhotoId] = useState<number | null>(null);
  const [isFavorited, setIsFavorited] = useState<boolean>(false);
  const [showSignInRequiredDialog, setShowSignInRequiredDialog] = useState(false);
  const [loginDialogOpen, setLoginDialogOpen] = useState(false);
  const [registerDialogOpen, setRegisterDialogOpen] = useState(false);
  const [showRegisteredMessage, setShowRegisteredMessage] = useState(false);
  const imageRef = useRef<HTMLImageElement | null>(null);
  const videoRef = useRef<HTMLVideoElement | null>(null);
  const [isVideoPlaying, setIsVideoPlaying] = useState(false);
  const videoAutoPlayAttemptedRef = useRef<number | null>(null);
  const containerRef = useRef<HTMLDivElement | null>(null);
  const hoveredFaceTooltip = hoveredFace
    ? hoveredFace.personName
      ? (isLoggedIn ? hoveredFace.personName : null)
      : (!session || hasWriteAccess ? 'Identify' : null)
    : null;

  // Debug: Log hoveredFace state changes
  useEffect(() => {
    console.log('[PhotoViewerClient] hoveredFace state changed:', {
      hoveredFace,
      hasHoveredFace: !!hoveredFace,
      tooltip: hoveredFaceTooltip,
    });
  }, [hoveredFace, hoveredFaceTooltip]);

  // Debug: Log tooltip calculation
  useEffect(() => {
    if (hoveredFace) {
      console.log('[PhotoViewerClient] Tooltip calculation:', {
        hoveredFace,
        hasPersonName: !!hoveredFace.personName,
        personName: hoveredFace.personName,
        isLoggedIn,
        hasSession: !!session,
        hasWriteAccess,
        tooltip: hoveredFaceTooltip,
        tooltipLogic: hoveredFace.personName
          ? `personName exists, isLoggedIn=${isLoggedIn} → ${isLoggedIn ? hoveredFace.personName : 'null'}`
          : `no personName, !session=${!session} || hasWriteAccess=${hasWriteAccess} → ${(!session || hasWriteAccess) ? 'Identify' : 'null'}`,
      });
    }
  }, [hoveredFace, hoveredFaceTooltip, isLoggedIn, session, hasWriteAccess]);

  // Update current photo when index changes (client-side navigation)
  useEffect(() => {
    if (allPhotos.length > 0 && currentIdx >= 0 && currentIdx < allPhotos.length) {
      const newPhoto = allPhotos[currentIdx];
      if (newPhoto && newPhoto.id !== currentPhoto.id) {
        setImageLoading(true);
        const normalizedPhoto = normalizePhoto(newPhoto);
        setCurrentPhoto(normalizedPhoto);
        setHoveredFace(null); // Reset face detection when photo changes
        imageRef.current = null; // Reset image ref
        // Reset video state when photo changes
        setIsVideoPlaying(false);
        videoAutoPlayAttemptedRef.current = null;
        if (videoRef.current) {
          videoRef.current.pause();
          videoRef.current.currentTime = 0;
        }
        // Reset zoom and pan when photo changes
        setZoom(1);
        setPanX(0);
        setPanY(0);
      }
    }
  }, [currentIdx, allPhotos, currentPhoto.id]);

  // Debug: Log photo data structure when currentPhoto changes
  useEffect(() => {
    console.log('[PhotoViewerClient] Current photo changed:', {
      photoId: currentPhoto.id,
      filename: currentPhoto.filename,
      hasFaces: !!currentPhoto.faces,
      facesCount: currentPhoto.faces?.length || 0,
      faces: currentPhoto.faces,
      facesStructure: currentPhoto.faces?.map((face, idx) => {
        const person = face.person as any; // Use any to check both camelCase and snake_case
        return {
          index: idx,
          id: face.id,
          personId: face.personId,
          hasLocation: !!face.location,
          location: face.location,
          hasPerson: !!face.person,
          person: face.person ? {
            id: person.id,
            // Check both camelCase and snake_case
            firstName: person.firstName || person.first_name,
            lastName: person.lastName || person.last_name,
            // Show raw person object to see actual structure
            rawPerson: person,
          } : null,
        };
      }),
    });
  }, [currentPhoto.id, currentPhoto.faces]);

  // Auto-play videos when navigated to (only once per photo)
  useEffect(() => {
    if (isVideo(currentPhoto) && videoRef.current && videoAutoPlayAttemptedRef.current !== currentPhoto.id) {
      // Mark that we've attempted auto-play for this photo
      videoAutoPlayAttemptedRef.current = currentPhoto.id;
      // Ensure controls are enabled
      if (videoRef.current) {
        videoRef.current.controls = true;
      }
      // Small delay to ensure video element is ready
      const timer = setTimeout(() => {
        if (videoRef.current && videoAutoPlayAttemptedRef.current === currentPhoto.id) {
          videoRef.current.play().catch((error) => {
            // Autoplay may fail due to browser policies, that's okay
            console.log('Video autoplay prevented:', error);
          });
        }
      }, 100);
      return () => clearTimeout(timer);
    }
  }, [currentPhoto]);

  // Check report status when photo changes or session changes
  useEffect(() => {
    const checkReportStatus = async () => {
      if (!session?.user?.id || !currentPhoto) {
        setIsReported(false);
        setReportStatus(null);
        return;
      }

      try {
        const response = await fetch(`/api/photos/${currentPhoto.id}/report`);
        if (response.ok) {
          const data = await response.json();
          if (data.reported && data.status === 'pending') {
            setIsReported(true);
            setReportStatus(data.status);
          } else {
            setIsReported(false);
            setReportStatus(data.status || null);
          }
        } else {
          setIsReported(false);
          setReportStatus(null);
        }
      } catch (error) {
        console.error('Error checking report status:', error);
        setIsReported(false);
        setReportStatus(null);
      }
    };

    checkReportStatus();
  }, [currentPhoto.id, session?.user?.id]);

  // Check favorite status when photo changes or session changes
  useEffect(() => {
    const checkFavoriteStatus = async () => {
      if (!session?.user?.id || !currentPhoto) {
        setIsFavorited(false);
        return;
      }

      try {
        const response = await fetch(`/api/photos/${currentPhoto.id}/favorite`);
        if (response.ok) {
          const data = await response.json();
          setIsFavorited(data.favorited || false);
        } else {
          setIsFavorited(false);
        }
      } catch (error) {
        console.error('Error checking favorite status:', error);
        setIsFavorited(false);
      }
    };

    checkFavoriteStatus();
  }, [currentPhoto.id, session?.user?.id]);

  // Keyboard navigation
  useEffect(() => {
    const handleKeyDown = (e: KeyboardEvent) => {
      if (e.key === 'ArrowLeft') {
        handlePrevious();
      } else if (e.key === 'ArrowRight') {
        handleNext(false);
      } else if (e.key === 'Escape') {
        handleClose();
      } else if (e.key === '+' || e.key === '=') {
        if (e.ctrlKey || e.metaKey) {
          e.preventDefault();
          handleZoomIn();
        }
      } else if (e.key === '-' || e.key === '_') {
        if (e.ctrlKey || e.metaKey) {
          e.preventDefault();
          handleZoomOut();
        }
      } else if (e.key === '0' && (e.ctrlKey || e.metaKey)) {
        e.preventDefault();
        handleResetZoom();
      }
    };

    window.addEventListener('keydown', handleKeyDown);
    return () => window.removeEventListener('keydown', handleKeyDown);
  }, [currentIdx, allPhotos.length]);

  const handlePrevious = () => {
    // Stop slideshow when user manually navigates
    if (isPlaying) {
      setIsPlaying(false);
    }
    
    if (allPhotos.length > 0 && currentIdx > 0) {
      const newIdx = currentIdx - 1;
      setCurrentIdx(newIdx);
      
      // Update URL if in modal mode (onClose is provided)
      if (onClose && allPhotos[newIdx]) {
        const photoIds = allPhotos.map((p) => p.id).join(',');
        // Preserve existing query params (filters, etc.)
        const params = new URLSearchParams(window.location.search);
        params.set('photo', allPhotos[newIdx].id.toString());
        params.set('photos', photoIds);
        params.set('index', newIdx.toString());
        router.replace(`/?${params.toString()}`, { scroll: false });
      }
    }
  };

  const handleNext = (fromSlideshow = false) => {
    // Stop slideshow when user manually navigates (unless it's from the slideshow itself)
    if (!fromSlideshow && isPlaying) {
      setIsPlaying(false);
    }
    
    if (allPhotos.length > 0 && currentIdx < allPhotos.length - 1) {
      // Find next non-video photo for slideshow
      let newIdx = currentIdx + 1;
      if (fromSlideshow) {
        // Skip videos in slideshow mode
        while (newIdx < allPhotos.length && isVideo(allPhotos[newIdx])) {
          newIdx++;
        }
        // If we've reached the end (only videos remaining), stop slideshow
        if (newIdx >= allPhotos.length) {
          setIsPlaying(false);
          return;
        }
      }
      
      setCurrentIdx(newIdx);
      
      // Update URL if in modal mode (onClose is provided)
      if (onClose && allPhotos[newIdx]) {
        const photoIds = allPhotos.map((p) => p.id).join(',');
        // Preserve existing query params (filters, etc.)
        const params = new URLSearchParams(window.location.search);
        params.set('photo', allPhotos[newIdx].id.toString());
        params.set('photos', photoIds);
        params.set('index', newIdx.toString());
        router.replace(`/?${params.toString()}`, { scroll: false });
      }
    } else if (allPhotos.length > 0 && currentIdx === allPhotos.length - 1 && isPlaying) {
      // If at the end and playing, stop the slideshow
      setIsPlaying(false);
    }
  };

  // Auto-advance slideshow
  useEffect(() => {
    // If slideshow is playing and current photo is a video, skip to next non-video immediately
    if (isPlaying && isVideo(currentPhoto) && allPhotos.length > 0) {
      // Find next non-video photo
      let nextIdx = currentIdx + 1;
      while (nextIdx < allPhotos.length && isVideo(allPhotos[nextIdx])) {
        nextIdx++;
      }
      // If we found a non-video photo, advance to it
      if (nextIdx < allPhotos.length) {
        setCurrentIdx(nextIdx);
        if (onClose && allPhotos[nextIdx]) {
          const photoIds = allPhotos.map((p) => p.id).join(',');
          const params = new URLSearchParams(window.location.search);
          params.set('photo', allPhotos[nextIdx].id.toString());
          params.set('photos', photoIds);
          params.set('index', nextIdx.toString());
          router.replace(`/?${params.toString()}`, { scroll: false });
        }
        return;
      } else {
        // No more non-video photos, stop slideshow
        setIsPlaying(false);
        return;
      }
    }
    
    if (isPlaying && !imageLoading && allPhotos.length > 0 && currentIdx < allPhotos.length - 1 && !isVideo(currentPhoto)) {
      slideTimerRef.current = setTimeout(() => {
        handleNext(true); // Pass true to indicate this is from slideshow
      }, currentInterval);
    } else {
      if (slideTimerRef.current) {
        clearTimeout(slideTimerRef.current);
        slideTimerRef.current = null;
      }
    }

    return () => {
      if (slideTimerRef.current) {
        clearTimeout(slideTimerRef.current);
      }
    };
  }, [isPlaying, currentIdx, imageLoading, allPhotos, currentInterval, currentPhoto, onClose, router]);

  const toggleSlideshow = () => {
    setIsPlaying(!isPlaying);
  };

  // Zoom functions
  const handleZoomIn = (e?: React.MouseEvent) => {
    if (e) {
      e.stopPropagation();
      e.preventDefault();
    }
    // Skip zoom for videos
    if (isVideo(currentPhoto)) {
      return;
    }
    // Pause slideshow when user zooms
    if (isPlaying) {
      setIsPlaying(false);
    }
    setZoom((prev) => {
      const newZoom = Math.min(prev + 0.25, 5); // Max zoom 5x
      console.log('Zoom in:', newZoom);
      return newZoom;
    });
  };

  const handleZoomOut = (e?: React.MouseEvent) => {
    if (e) {
      e.stopPropagation();
      e.preventDefault();
    }
    // Skip zoom for videos
    if (isVideo(currentPhoto)) {
      return;
    }
    // Pause slideshow when user zooms
    if (isPlaying) {
      setIsPlaying(false);
    }
    setZoom((prev) => {
      const newZoom = Math.max(prev - 0.25, 0.5); // Min zoom 0.5x
      console.log('Zoom out:', newZoom);
      if (newZoom === 1) {
        // Reset pan when zoom returns to 1
        setPanX(0);
        setPanY(0);
      }
      return newZoom;
    });
  };

  const handleResetZoom = (e?: React.MouseEvent) => {
    if (e) {
      e.stopPropagation();
      e.preventDefault();
    }
    // Skip zoom for videos
    if (isVideo(currentPhoto)) {
      return;
    }
    console.log('Reset zoom');
    setZoom(1);
    setPanX(0);
    setPanY(0);
  };

  // Mouse wheel zoom
  useEffect(() => {
    const handleWheel = (e: WheelEvent) => {
      // Skip zoom for videos
      if (isVideo(currentPhoto)) {
        return;
      }
      if (e.ctrlKey || e.metaKey) {
        e.preventDefault();
        if (e.deltaY < 0) {
          handleZoomIn();
        } else {
          handleZoomOut();
        }
      }
    };

    const container = containerRef.current;
    if (container) {
      container.addEventListener('wheel', handleWheel, { passive: false });
      return () => container.removeEventListener('wheel', handleWheel);
    }
  }, [currentPhoto]);

  // Pan when zoomed
  const handleMouseMovePan = useCallback((e: React.MouseEvent) => {
    if (isDragging && zoom > 1) {
      setPanX(e.clientX - dragStart.x);
      setPanY(e.clientY - dragStart.y);
    }
  }, [isDragging, zoom, dragStart]);

  const handleMouseDown = (e: React.MouseEvent) => {
    if (zoom > 1 && e.button === 0) {
      e.preventDefault();
      setIsDragging(true);
      setDragStart({ x: e.clientX - panX, y: e.clientY - panY });
    }
  };

  const handleMouseUp = useCallback(() => {
    setIsDragging(false);
  }, []);

  // Global mouse up handler for dragging
  useEffect(() => {
    if (isDragging) {
      const handleGlobalMouseUp = () => {
        setIsDragging(false);
      };
      window.addEventListener('mouseup', handleGlobalMouseUp);
      return () => window.removeEventListener('mouseup', handleGlobalMouseUp);
    }
  }, [isDragging]);

  // Update interval handler
  const handleIntervalChange = (value: string) => {
    const newInterval = parseInt(value, 10) * 1000; // Convert seconds to milliseconds
    setCurrentInterval(newInterval);
  };

  const handleClose = () => {
    // Stop slideshow when closing
    setIsPlaying(false);
    if (slideTimerRef.current) {
      clearTimeout(slideTimerRef.current);
      slideTimerRef.current = null;
    }
    
    if (onClose) {
      // Use provided callback (for modal mode)
      onClose();
    } else {
      // Fallback to router.back() for route-based navigation
      router.back();
    }
  };

  const handleImageLoad = (e: React.SyntheticEvent<HTMLImageElement>) => {
    setImageLoading(false);
    imageRef.current = e.currentTarget;
    console.log('[PhotoViewerClient] Image loaded, imageRef set:', {
      hasImageRef: !!imageRef.current,
      naturalWidth: imageRef.current?.naturalWidth,
      naturalHeight: imageRef.current?.naturalHeight,
      src: imageRef.current?.src,
      currentPhotoId: currentPhoto.id,
    });
  };

  const handleImageError = () => {
    setImageLoading(false);
  };

  const handleDownloadPhoto = useCallback(() => {
    const link = document.createElement('a');
    link.href = getPhotoDownloadUrl(currentPhoto, { watermark: !isLoggedIn });
    link.download = getPhotoFilename(currentPhoto);
    document.body.appendChild(link);
    link.click();
    document.body.removeChild(link);
  }, [currentPhoto, isLoggedIn]);

  const findFaceAtPoint = useCallback((x: number, y: number) => {
    console.log('[PhotoViewerClient] findFaceAtPoint called:', {
      x,
      y,
      hasFaces: !!currentPhoto.faces,
      facesCount: currentPhoto.faces?.length || 0,
      hasImageRef: !!imageRef.current,
      hasContainerRef: !!containerRef.current,
    });

    if (!currentPhoto.faces || currentPhoto.faces.length === 0) {
      console.log('[PhotoViewerClient] findFaceAtPoint: No faces in photo');
      return null;
    }

    if (!imageRef.current || !containerRef.current) {
      console.log('[PhotoViewerClient] findFaceAtPoint: Missing refs', {
        imageRef: !!imageRef.current,
        containerRef: !!containerRef.current,
      });
      return null;
    }

    const container = containerRef.current;
    const rect = container.getBoundingClientRect();
    const mouseX = x - rect.left;
    const mouseY = y - rect.top;

    const img = imageRef.current;
    const naturalWidth = img.naturalWidth;
    const naturalHeight = img.naturalHeight;
    const containerWidth = rect.width;
    const containerHeight = rect.height;

    console.log('[PhotoViewerClient] findFaceAtPoint: Image dimensions:', {
      naturalWidth,
      naturalHeight,
      containerWidth,
      containerHeight,
      mouseX,
      mouseY,
    });

    if (!naturalWidth || !naturalHeight) {
      console.log('[PhotoViewerClient] findFaceAtPoint: Invalid image dimensions');
      return null;
    }

    // Check each face to see if point is over it
    for (const face of currentPhoto.faces) {
      if (!face.location) {
        console.log('[PhotoViewerClient] findFaceAtPoint: Face missing location', { faceId: face.id });
        continue;
      }
      
      const location = parseFaceLocation(face.location);
      if (!location) {
        console.log('[PhotoViewerClient] findFaceAtPoint: Failed to parse location', { 
          faceId: face.id, 
          location: face.location 
        });
        continue;
      }

      const isInFace = isPointInFaceWithFit(
        mouseX,
        mouseY,
        location,
        naturalWidth,
        naturalHeight,
        containerWidth,
        containerHeight,
        'contain' // PhotoViewer uses object-contain
      );

      if (isInFace) {
        const person = face.person as any; // Use any to check both camelCase and snake_case
        const firstName = person?.firstName || person?.first_name;
        const lastName = person?.lastName || person?.last_name;
        const personName = firstName && lastName ? `${firstName} ${lastName}` : null;
        console.log('[PhotoViewerClient] findFaceAtPoint: Face found!', {
          faceId: face.id,
          personId: face.personId,
          hasPerson: !!face.person,
          personName,
          personRaw: person, // Show raw person to see actual structure
        });
        return face;
      }
    }

    console.log('[PhotoViewerClient] findFaceAtPoint: No face found at point');
    return null;
  }, [currentPhoto.faces]);

  const handleMouseMove = useCallback((e: React.MouseEvent<HTMLDivElement>) => {
    // Skip face detection for videos
    if (isVideo(currentPhoto)) {
      return;
    }
    
    // Handle pan if dragging and zoomed
    if (isDragging && zoom > 1) {
      handleMouseMovePan(e);
      return;
    }
    
    const face = findFaceAtPoint(e.clientX, e.clientY);
    
    if (face) {
      const person = face.person as any;
      const firstName = person?.first_name || person?.firstName;
      const lastName = person?.last_name || person?.lastName;
      const personName = firstName && lastName ? `${firstName} ${lastName}`.trim() : null;
      
      console.log('[PhotoViewerClient] handleMouseMove: Face detected on hover', {
        faceId: face.id,
        personId: face.personId,
        personName,
        mouseX: e.clientX,
        mouseY: e.clientY,
      });
      
      // Update hovered face (or set if different face)
      setHoveredFace((prev) => {
        // If same face, just update position
        if (prev && prev.faceId === face.id) {
          return {
            ...prev,
            mouseX: e.clientX,
            mouseY: e.clientY,
          };
        }
        // New face detected
        return {
          faceId: face.id,
          personId: face.personId,
          personName,
          mouseX: e.clientX,
          mouseY: e.clientY,
        };
      });
    } else {
      // Only log when clearing hoveredFace to avoid spam
      if (hoveredFace) {
        console.log('[PhotoViewerClient] handleMouseMove: No face detected, clearing hoveredFace');
      }
      setHoveredFace(null);
    }
  }, [findFaceAtPoint, isDragging, zoom, currentPhoto, hoveredFace]);

  const handleClick = useCallback((e: React.MouseEvent<HTMLDivElement>) => {
    console.log('[PhotoViewerClient] handleClick called:', {
      isVideo: isVideo(currentPhoto),
      clientX: e.clientX,
      clientY: e.clientY,
      hasSession: !!session,
      hasWriteAccess,
      isDragging,
      zoom,
    });

    // Handle video play/pause on click
    if (isVideo(currentPhoto)) {
      if (videoRef.current) {
        if (isVideoPlaying) {
          videoRef.current.pause();
          setIsVideoPlaying(false);
        } else {
          videoRef.current.play();
          setIsVideoPlaying(true);
        }
      }
      return;
    }
    
    const face = findFaceAtPoint(e.clientX, e.clientY);
    
    // Only allow clicking on unidentified faces (when tooltip shows "Identify")
    // Click is allowed if: face exists, face is NOT identified, and user has write access (or is not signed in)
    const isUnidentified = face && !face.person;
    const canClick = isUnidentified && (!session || hasWriteAccess);
    
    console.log('[PhotoViewerClient] handleClick: Face detection result:', {
      foundFace: !!face,
      faceId: face?.id,
      facePersonId: face?.personId,
      faceHasPerson: !!face?.person,
      isUnidentified,
      session: !!session,
      hasWriteAccess,
      canClick,
      conditionBreakdown: face ? {
        'face exists': !!face,
        'face.person (identified)': !!face.person,
        'isUnidentified': isUnidentified,
        '!session': !session,
        'hasWriteAccess': hasWriteAccess,
        'canClick': canClick,
      } : null,
    });
    
    if (canClick) {
      console.log('[PhotoViewerClient] handleClick: Opening identify dialog', {
        faceId: face.id,
        person: face.person,
      });
      setClickedFace({
        faceId: face.id,
        person: face.person,
      });
      setIsDialogOpen(true);
    } else {
      console.log('[PhotoViewerClient] handleClick: Click blocked', {
        reason: !face ? 'no face found' : face?.person ? 'face already identified' : 'insufficient permissions',
      });
    }
  }, [findFaceAtPoint, session, hasWriteAccess, currentPhoto, isVideoPlaying, isDragging, zoom]);

  const handleSaveFace = async (data: {
    personId?: number;
    firstName?: string;
    lastName?: string;
    middleName?: string;
    maidenName?: string;
    dateOfBirth?: Date;
  }) => {
    if (!clickedFace) return;

    const response = await fetch(`/api/faces/${clickedFace.faceId}/identify`, {
      method: 'POST',
      headers: {
        'Content-Type': 'application/json',
      },
      body: JSON.stringify(data),
    });

    if (!response.ok) {
      const error = await response.json();
      if (response.status === 401) {
        // Authentication error - the dialog should handle this
        throw new Error('Please sign in to identify faces');
      }
      throw new Error(error.error || 'Failed to save face identification');
    }

    const result = await response.json();
    // Success - identification is pending approval
    // Note: We don't refresh the photo data since it's pending approval
    // The face won't show the identification until approved by admin
  };

  const resetReportDialog = () => {
    setReportDialogPhotoId(null);
    setReportDialogComment('');
    setReportDialogError(null);
  };

  const handleUndoReport = async (photoId: number) => {
    if (reportingPhotoId === photoId) {
      return;
    }

    setReportingPhotoId(photoId);

    try {
      const response = await fetch(`/api/photos/${photoId}/report`, {
        method: 'DELETE',
        headers: {
          'Content-Type': 'application/json',
        },
      });

      if (!response.ok) {
        const error = await response.json();
        if (response.status === 401) {
          alert('Please sign in to report photos');
        } else if (response.status === 403) {
          alert('Cannot undo report that has already been reviewed');
        } else if (response.status === 404) {
          alert('Report not found');
        } else {
          alert(error.error || 'Failed to undo report');
        }
        return;
      }

      setIsReported(false);
      setReportStatus(null);
      alert('Report undone successfully.');
    } catch (error) {
      console.error('Error undoing report:', error);
      alert('Failed to undo report. Please try again.');
    } finally {
      setReportingPhotoId(null);
    }
  };

  const handleReportPhoto = async () => {
    // Check if user is logged in
    if (!session) {
      setShowSignInRequiredDialog(true);
      return;
    }

    if (reportingPhotoId === currentPhoto.id) return; // Already processing

    const isPending = isReported && reportStatus === 'pending';
    const isDismissed = isReported && reportStatus === 'dismissed';

    if (isDismissed) {
      alert('This report was dismissed by an administrator and cannot be resubmitted.');
      return;
    }

    if (isPending) {
      await handleUndoReport(currentPhoto.id);
      return;
    }

    // Open dialog to enter comment
    setReportDialogPhotoId(currentPhoto.id);
    setReportDialogComment('');
    setReportDialogError(null);
  };

  const handleSubmitReport = async () => {
    if (reportDialogPhotoId === null) {
      return;
    }

    const trimmedComment = reportDialogComment.trim();
    if (trimmedComment.length > REPORT_COMMENT_MAX_LENGTH) {
      setReportDialogError(`Comment must be ${REPORT_COMMENT_MAX_LENGTH} characters or less.`);
      return;
    }

    setReportDialogError(null);
    setReportingPhotoId(reportDialogPhotoId);

    try {
      const response = await fetch(`/api/photos/${reportDialogPhotoId}/report`, {
        method: 'POST',
        headers: {
          'Content-Type': 'application/json',
        },
        body: JSON.stringify({
          comment: trimmedComment.length > 0 ? trimmedComment : null,
        }),
      });

      if (!response.ok) {
        const error = await response.json().catch(() => null);
        if (response.status === 401) {
          setShowSignInRequiredDialog(true);
        } else if (response.status === 403) {
          alert(error?.error || 'Cannot re-report this photo.');
        } else if (response.status === 409) {
          alert('You have already reported this photo');
        } else if (response.status === 400) {
          setReportDialogError(error?.error || 'Invalid comment');
          return;
        } else {
          alert(error?.error || 'Failed to report photo. Please try again.');
        }
        return;
      }

      setIsReported(true);
      setReportStatus('pending');

      const wasReReported = isReported && reportStatus === 'reviewed';
      alert(
        wasReReported
          ? 'Photo re-reported successfully. Thank you for your report.'
          : 'Photo reported successfully. Thank you for your report.'
      );
      resetReportDialog();
    } catch (error) {
      console.error('Error reporting photo:', error);
      alert('Failed to create report. Please try again.');
    } finally {
      setReportingPhotoId(null);
    }
  };

  const handleToggleFavorite = async () => {
    // Check if user is logged in
    if (!session) {
      setShowSignInRequiredDialog(true);
      return;
    }

    if (favoritingPhotoId === currentPhoto.id) return; // Already processing
    
    setFavoritingPhotoId(currentPhoto.id);
    
    try {
      const response = await fetch(`/api/photos/${currentPhoto.id}/favorite`, {
        method: 'POST',
        headers: {
          'Content-Type': 'application/json',
        },
      });

      if (!response.ok) {
        const error = await response.json();
        if (response.status === 401) {
          setShowSignInRequiredDialog(true);
        } else {
          alert(error.error || 'Failed to toggle favorite');
        }
        return;
      }

      const data = await response.json();
      setIsFavorited(data.favorited);
    } catch (error) {
      console.error('Error toggling favorite:', error);
      alert('Failed to toggle favorite. Please try again.');
    } finally {
      setFavoritingPhotoId(null);
    }
  };

  const peopleNames = (currentPhoto as any).faces
    ?.map((face: any) => face.Person)
    .filter((person: any): person is Person => person != null)
    .map((person: Person) => `${person.first_name} ${person.last_name}`.trim()) || [];

  const tags = (currentPhoto as any).PhotoTagLinkage?.map((pt: any) => pt.Tag.tag_name) || [];

  const hasPrevious = allPhotos.length > 0 && currentIdx > 0;
  const hasNext = allPhotos.length > 0 && currentIdx < allPhotos.length - 1;

  return (
    <div className="fixed inset-0 z-50 flex items-center justify-center bg-black">
      {/* Close Button */}
      <Button
        variant="ghost"
        size="icon"
        className="absolute top-4 right-4 z-10 text-white hover:bg-white/20"
        onClick={handleClose}
        aria-label="Close"
      >
        <X className="h-6 w-6" />
      </Button>

      {/* Play/Pause Button and Interval Selector */}
      {allPhotos.length > 1 && (
        <div className="absolute top-4 left-4 z-10 flex items-center gap-2">
          <Button
            variant="ghost"
            size="icon"
            className="text-white hover:bg-white/20 h-12 w-12"
            onClick={toggleSlideshow}
            aria-label={isPlaying ? 'Pause slideshow' : 'Play slideshow'}
          >
            {isPlaying ? (
              <Pause className="h-8 w-8" />
            ) : (
              <Play className="h-8 w-8" />
            )}
          </Button>
          <Select
            value={Math.round(currentInterval / 1000).toString()}
            onValueChange={handleIntervalChange}
          >
            <SelectTrigger className="w-24 h-9 bg-black/50 border-white/20 text-white hover:bg-white/20">
              <SelectValue />
            </SelectTrigger>
            <SelectContent>
              <SelectItem value="1">1s</SelectItem>
              <SelectItem value="2">2s</SelectItem>
              <SelectItem value="3">3s</SelectItem>
              <SelectItem value="5">5s</SelectItem>
              <SelectItem value="7">7s</SelectItem>
              <SelectItem value="10">10s</SelectItem>
              <SelectItem value="15">15s</SelectItem>
              <SelectItem value="20">20s</SelectItem>
              <SelectItem value="30">30s</SelectItem>
              <SelectItem value="60">60s</SelectItem>
            </SelectContent>
          </Select>
        </div>
      )}

      {/* Zoom Controls - Hide for videos */}
      {!isVideo(currentPhoto) && (
      <div 
        className="absolute bottom-4 left-1/2 transform -translate-x-1/2 z-30 flex items-center gap-2 bg-black/50 rounded-lg p-2 pointer-events-auto"
        onClick={(e) => e.stopPropagation()}
        onMouseDown={(e) => e.stopPropagation()}
        onMouseUp={(e) => e.stopPropagation()}
      >
        <Button
          variant="ghost"
          size="icon"
          className="text-white hover:bg-white/20 pointer-events-auto"
          onClick={(e) => {
            console.log('Zoom out button clicked');
            handleZoomOut(e);
          }}
          disabled={zoom <= 0.5}
          aria-label="Zoom out"
          type="button"
        >
          <ZoomOut className="h-5 w-5 pointer-events-none" />
        </Button>
        <span className="text-white text-sm min-w-[60px] text-center pointer-events-none">
          {Math.round(zoom * 100)}%
        </span>
        <Button
          variant="ghost"
          size="icon"
          className="text-white hover:bg-white/20 pointer-events-auto"
          onClick={(e) => {
            console.log('Zoom in button clicked');
            handleZoomIn(e);
          }}
          disabled={zoom >= 5}
          aria-label="Zoom in"
          type="button"
        >
          <ZoomIn className="h-5 w-5 pointer-events-none" />
        </Button>
        {zoom !== 1 && (
          <Button
            variant="ghost"
            size="icon"
            className="text-white hover:bg-white/20 ml-2 pointer-events-auto"
            onClick={(e) => {
              console.log('Reset zoom button clicked');
              handleResetZoom(e);
            }}
            aria-label="Reset zoom"
            type="button"
          >
            <RotateCcw className="h-5 w-5 pointer-events-none" />
          </Button>
        )}
      </div>
      )}

      {/* Previous Button */}
      {hasPrevious && (
        <Button
          variant="ghost"
          size="icon"
          className="absolute left-4 z-10 text-white hover:bg-white/20 disabled:opacity-30"
          onClick={handlePrevious}
          disabled={imageLoading}
          aria-label="Previous photo"
        >
          <ChevronLeft className="h-8 w-8" />
        </Button>
      )}

      {/* Next Button */}
      {hasNext && (
        <Button
          variant="ghost"
          size="icon"
          className="absolute right-4 z-10 text-white hover:bg-white/20 disabled:opacity-30"
          onClick={() => handleNext(false)}
          disabled={imageLoading}
          aria-label="Next photo"
        >
          <ChevronRight className="h-8 w-8" />
        </Button>
      )}

      {/* Photo Container */}
      <div className="relative h-full w-full flex items-center justify-center p-4" style={{ overflow: isVideo(currentPhoto) ? 'visible' : 'hidden' }}>
        {isVideo(currentPhoto) ? (
          // For videos, render in a completely isolated container with no event handlers
          <div
            className="relative h-full w-full max-h-[calc(90vh-80px)] max-w-full"
            style={{
              display: 'flex',
              alignItems: 'center',
              justifyContent: 'center',
            }}
          >
            <video
              ref={videoRef}
              key={currentPhoto.id}
              src={getVideoSrc(currentPhoto)}
              className="object-contain w-full h-full"
              controls={true}
              controlsList="nodownload"
              style={{ 
                display: 'block', 
                width: '100%', 
                height: '100%',
                maxWidth: '100%',
                maxHeight: '100%',
              }}
              onLoadedData={() => {
                setImageLoading(false);
                if (videoRef.current) {
                  videoRef.current.controls = true;
                }
              }}
              onError={() => {
                setImageLoading(false);
              }}
              onPlay={() => setIsVideoPlaying(true)}
              onPause={() => setIsVideoPlaying(false)}
              onEnded={() => setIsVideoPlaying(false)}
            />
          </div>
        ) : (
        <div
          ref={containerRef}
          className={`relative h-full w-full max-h-[90vh] max-w-full ${hoveredFace && !hoveredFace.personName && (!session || hasWriteAccess) ? 'cursor-pointer' : ''} ${zoom > 1 ? 'cursor-grab active:cursor-grabbing' : ''}`}
          style={{
            transform: zoom > 1 ? `translate(${panX}px, ${panY}px)` : undefined,
            transition: zoom === 1 ? 'transform 0.2s' : undefined,
          }}
          onMouseMove={handleMouseMove}
          onMouseLeave={() => {
            console.log('[PhotoViewerClient] Mouse left container, clearing hoveredFace');
            setHoveredFace(null);
            setIsDragging(false);
          }}
          onMouseDown={handleMouseDown}
          onMouseUp={handleMouseUp}
          onClick={(e) => {
            // Don't handle click if it's on a button or zoom controls
            const target = e.target as HTMLElement;
            const isButton = target.closest('button');
            const isZoomControl = target.closest('[aria-label*="Zoom"]') || target.closest('[aria-label*="Reset zoom"]');
            
            console.log('[PhotoViewerClient] Container onClick:', {
              isButton: !!isButton,
              isZoomControl: !!isZoomControl,
              isDragging,
              zoom,
              willHandleClick: !isButton && !isZoomControl && (!isDragging || zoom === 1),
            });
            
            if (isButton || isZoomControl) {
              return;
            }
            // For images, only handle click if not dragging
            if (!isDragging || zoom === 1) {
              handleClick(e);
            } else {
              console.log('[PhotoViewerClient] Click ignored due to dragging/zoom state');
            }
          }}
        >
          {imageLoading && (
            <div className="absolute inset-0 flex items-center justify-center text-white z-10">
              Loading...
            </div>
          )}
          <div
            style={{
              transform: `scale(${zoom})`,
              transformOrigin: 'center center',
              transition: zoom === 1 ? 'transform 0.2s' : undefined,
            }}
            className="relative h-full w-full"
          >
            <Image
              key={currentPhoto.id}
              src={getImageSrc(currentPhoto, { watermark: !isLoggedIn })}
              alt={currentPhoto.filename}
              fill
              className="object-contain"
              priority
              unoptimized={!isUrl(currentPhoto.path)}
              sizes="100vw"
              onLoad={handleImageLoad}
              onError={handleImageError}
            />
          </div>
        </div>
        )}
      </div>

      {/* Face Tooltip - Show for identified faces, or for unidentified faces if not signed in or has write access */}
      {hoveredFace && hoveredFaceTooltip && (
        <div
          className="fixed z-[100] pointer-events-none"
          style={{
            left: `${hoveredFace.mouseX}px`,
            top: `${hoveredFace.mouseY - 40}px`,
            transform: 'translateX(-50%)',
          }}
        >
          <div className="bg-white text-secondary rounded-md px-3 py-1.5 shadow-lg border border-gray-200">
            <p className="text-sm font-medium whitespace-nowrap">
              {hoveredFaceTooltip}
            </p>
          </div>
        </div>
      )}

      {/* Report Button - Left Bottom Corner - Aligned with filename, above video controls */}
      {(() => {
        // Position based on whether it's a video (to align with filename above controls)
        // For videos: position above the controls area (controls are ~60-70px, plus padding)
        const bottomPosition = isVideo(currentPhoto) ? '160px' : '96px'; // 160px for videos to be well above controls, 96px (bottom-24) for images
        
        if (!session) {
          // Not logged in - show basic report button
          return (
            <Button
              variant="ghost"
              size="icon"
              className="absolute left-4 z-20 text-white hover:bg-white/20 bg-black/50"
              style={{ bottom: bottomPosition }}
              onClick={handleReportPhoto}
              aria-label="Report inappropriate photo"
              title="Report inappropriate photo"
            >
              <Flag className="h-5 w-5" />
            </Button>
          );
        }

        // Logged in - show button with status
        const isPending = isReported && reportStatus === 'pending';
        const isReviewed = isReported && reportStatus === 'reviewed';
        const isDismissed = isReported && reportStatus === 'dismissed';
        
        let tooltipText: string;
        let buttonClass: string;
        
        if (isPending) {
          tooltipText = 'Reported as inappropriate. Click to undo';
          buttonClass = 'bg-red-600/70 hover:bg-red-600/90';
        } else if (isReviewed) {
          tooltipText = 'Report reviewed and kept. Click to report again';
          buttonClass = 'bg-green-600/70 hover:bg-green-600/90';
        } else if (isDismissed) {
          tooltipText = 'Report dismissed';
          buttonClass = 'bg-gray-600/70 hover:bg-gray-600/90';
        } else {
          tooltipText = 'Report inappropriate photo';
          buttonClass = 'bg-black/50';
        }
        
        return (
          <Button
            variant="ghost"
            size="icon"
            className={`absolute left-4 z-20 text-white hover:bg-white/20 ${buttonClass}`}
            style={{ bottom: bottomPosition }}
            onClick={handleReportPhoto}
            disabled={reportingPhotoId === currentPhoto.id || isDismissed}
            aria-label={tooltipText}
            title={tooltipText}
          >
            <Flag className={`h-5 w-5 ${isPending || isReviewed ? 'fill-current' : ''}`} />
          </Button>
        );
      })()}

      {/* Download Button - Right Bottom Corner (next to favorite), above controls */}
      {(() => {
        const bottomPosition = isVideo(currentPhoto) ? '160px' : '96px';
        return (
          <Button
            variant="ghost"
            size="icon"
            className="absolute right-16 z-20 text-white hover:bg-white/20 bg-black/50"
            style={{ bottom: bottomPosition }}
            onClick={handleDownloadPhoto}
            aria-label="Download photo"
            title="Download photo"
          >
            <Download className="h-5 w-5" />
          </Button>
        );
      })()}

      {/* Favorite Button - Right Bottom Corner - Aligned with filename, above video controls */}
      {(() => {
        // Position based on whether it's a video (to align with filename above controls)
        const bottomPosition = isVideo(currentPhoto) ? '160px' : '96px';
        
        if (!session) {
          // Not logged in - show basic favorite button
          return (
            <Button
              variant="ghost"
              size="icon"
              className="absolute right-4 z-20 text-white hover:bg-white/20 bg-black/50"
              style={{ bottom: bottomPosition }}
              onClick={handleToggleFavorite}
              aria-label="Add to favorites"
              title="Add to favorites (sign in required)"
            >
              <Heart className="h-5 w-5" />
            </Button>
          );
        }

        // Logged in - show button with favorite status
        return (
          <Button
            variant="ghost"
            size="icon"
            className={`absolute right-4 z-20 text-white hover:bg-white/20 ${
              isFavorited 
                ? 'bg-red-600/70 hover:bg-red-600/90' 
                : 'bg-black/50'
            }`}
            style={{ bottom: bottomPosition }}
            onClick={handleToggleFavorite}
            disabled={favoritingPhotoId === currentPhoto.id}
            aria-label={isFavorited ? 'Remove from favorites' : 'Add to favorites'}
            title={isFavorited ? 'Remove from favorites' : 'Add to favorites'}
          >
            <Heart className={`h-5 w-5 ${isFavorited ? 'fill-current' : ''}`} />
          </Button>
        );
      })()}

      {/* Photo Info Overlay - Only covers text area, not video controls */}
      <div 
        className="absolute left-0 right-0 text-white pointer-events-none"
        style={{
          bottom: isVideo(currentPhoto) ? '80px' : '0px', // Leave more space for video controls (controls bar is ~60-70px)
          background: 'linear-gradient(to top, rgba(0,0,0,0.8) 0%, rgba(0,0,0,0.8) 40%, transparent 100%)',
          zIndex: isVideo(currentPhoto) ? 1 : 10, // Lower z-index for videos so controls are on top
        }}
      >
        <div className="container mx-auto p-6 pointer-events-auto">
          <h2 className="text-xl font-semibold mb-2">{currentPhoto.filename}</h2>
          {currentPhoto.date_taken && (
            <p className="text-sm text-gray-300 mb-2">
              {new Date(currentPhoto.date_taken).toLocaleDateString('en-US', {
                year: 'numeric',
                month: 'long',
                day: 'numeric',
              })}
            </p>
          )}
          {peopleNames.length > 0 && (
            <p className="text-sm text-gray-300 mb-1">
              <span className="font-medium">People: </span>
              {peopleNames.join(', ')}
            </p>
          )}
          {tags.length > 0 && (
            <p className="text-sm text-gray-300">
              <span className="font-medium">Tags: </span>
              {tags.join(', ')}
            </p>
          )}
          {allPhotos.length > 0 && (
            <p className="text-sm text-gray-400 mt-2">
              {currentIdx + 1} of {allPhotos.length}
            </p>
          )}
        </div>
      </div>

      {/* Identify Face Dialog */}
      {clickedFace && (
        <IdentifyFaceDialog
          open={isDialogOpen}
          onOpenChange={(open) => {
            setIsDialogOpen(open);
            if (!open) {
              setClickedFace(null);
            }
          }}
          faceId={clickedFace.faceId}
          existingPerson={clickedFace.person ? {
            firstName: (clickedFace.person as any).first_name || (clickedFace.person as any).firstName,
            lastName: (clickedFace.person as any).last_name || (clickedFace.person as any).lastName,
            middleName: (clickedFace.person as any).middle_name || (clickedFace.person as any).middleName,
            maidenName: (clickedFace.person as any).maiden_name || (clickedFace.person as any).maidenName,
            dateOfBirth: (clickedFace.person as any).date_of_birth || (clickedFace.person as any).dateOfBirth,
          } : null}
          onSave={handleSaveFace}
        />
      )}

      {/* Report Comment Dialog */}
      <Dialog
        open={reportDialogPhotoId !== null}
        onOpenChange={(open) => {
          if (!open) {
            resetReportDialog();
          }
        }}
      >
        <DialogContent className="sm:max-w-[500px]">
          <DialogHeader>
            <DialogTitle>Report Photo</DialogTitle>
            <DialogDescription>
              Optionally include a short comment to help administrators understand the issue.
            </DialogDescription>
          </DialogHeader>
          <div className="py-4">
            <label htmlFor="report-comment" className="text-sm font-medium text-secondary">
              Comment (optional)
            </label>
            <textarea
              id="report-comment"
              value={reportDialogComment}
              onChange={(event) => setReportDialogComment(event.target.value)}
              maxLength={REPORT_COMMENT_MAX_LENGTH}
              className="mt-2 w-full rounded-md border border-gray-300 bg-white px-3 py-2 text-sm shadow-sm focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-gray-900 dark:bg-gray-800 dark:border-gray-600 dark:text-white"
              rows={4}
              placeholder="Add a short note about why this photo should be reviewed..."
            />
            <div className="mt-1 flex justify-between text-xs text-gray-500">
              <span>{`${reportDialogComment.length}/${REPORT_COMMENT_MAX_LENGTH} characters`}</span>
              {reportDialogError && <span className="text-red-600">{reportDialogError}</span>}
            </div>
          </div>
          <DialogFooter className="gap-2 sm:gap-0">
            <Button
              variant="outline"
              onClick={() => {
                resetReportDialog();
              }}
            >
              Cancel
            </Button>
            <Button
              onClick={handleSubmitReport}
              disabled={
                reportDialogPhotoId === null || reportingPhotoId === reportDialogPhotoId
              }
            >
              {reportDialogPhotoId !== null && reportingPhotoId === reportDialogPhotoId
                ? 'Reporting...'
                : 'Report photo'}
            </Button>
          </DialogFooter>
        </DialogContent>
      </Dialog>

      {/* Sign In Required Dialog for Report */}
      <Dialog open={showSignInRequiredDialog} onOpenChange={setShowSignInRequiredDialog}>
        <DialogContent className="sm:max-w-[500px]">
          <DialogHeader>
            <DialogTitle>Sign In Required</DialogTitle>
            <DialogDescription>
              You need to be signed in to report photos. Your reports will be reviewed by administrators.
            </DialogDescription>
          </DialogHeader>
          <div className="py-4">
            <p className="text-sm text-gray-600 mb-4">
              Please sign in or create an account to continue.
            </p>
            <div className="flex gap-2">
              <Button
                onClick={() => {
                  setLoginDialogOpen(true);
                }}
                className="flex-1"
              >
                Sign in
              </Button>
              <Button
                variant="outline"
                onClick={() => {
                  setRegisterDialogOpen(true);
                }}
                className="flex-1"
              >
                Register
              </Button>
            </div>
          </div>
          <DialogFooter>
            <Button variant="outline" onClick={() => setShowSignInRequiredDialog(false)}>
              Cancel
            </Button>
          </DialogFooter>
        </DialogContent>
      </Dialog>

      {/* Login Dialog */}
      <LoginDialog
        open={loginDialogOpen}
        onOpenChange={(open) => {
          setLoginDialogOpen(open);
          if (!open) {
            setShowRegisteredMessage(false);
          }
        }}
        onSuccess={async () => {
          await update();
          router.refresh();
          setShowSignInRequiredDialog(false);
        }}
        onOpenRegister={() => {
          setLoginDialogOpen(false);
          setRegisterDialogOpen(true);
        }}
        registered={showRegisteredMessage}
        callbackUrl={typeof window !== 'undefined' ? window.location.pathname + window.location.search : '/'}
      />

      {/* Register Dialog */}
      <RegisterDialog
        open={registerDialogOpen}
        onOpenChange={(open) => {
          setRegisterDialogOpen(open);
          if (!open) {
            setShowRegisteredMessage(false);
          }
        }}
        onSuccess={async () => {
          await update();
          router.refresh();
          setShowSignInRequiredDialog(false);
        }}
        onOpenLogin={() => {
          setShowRegisteredMessage(true);
          setRegisterDialogOpen(false);
          setLoginDialogOpen(true);
        }}
        callbackUrl={typeof window !== 'undefined' ? window.location.pathname + window.location.search : '/'}
      />
    </div>
  );
}

