import React from 'react'
import type { ExamplesData } from './Examples'
import { groupByNameAndVariant, VARIANT_NAME_MAP } from './galleryUtils'
import ExampleVariantMetricsTables from './ExampleVariantMetricsTable'
import ExampleDetailsSection from './ExampleDetailsSection'
import ExampleVariantSelector from './ExampleVariantSelector'
import ExampleVariantToggle from './ExampleVariantToggle'
import API from '../API'

interface GalleryProps {
  selectedModel: string
  selectedAttack: string
  examples: {
    [model: string]: {
      [attack: string]: ExamplesData[]
    }
  }
}

const VideoGallery: React.FC<GalleryProps> = ({ selectedModel, selectedAttack, examples }) => {
  const exampleItems = examples[selectedModel][selectedAttack]
  const grouped = groupByNameAndVariant(exampleItems)
  const videoNames = Object.keys(grouped)
  const [selectedVideo, setSelectedVideo] = React.useState(videoNames[0] || '')
  const variants = grouped[selectedVideo] || {}
  const variantKeys = Object.keys(variants)

  const originalVariant = 'original'
  // Comparison variant (watermarked or attacked)
  const [comparisonVariant, setComparisonVariant] = React.useState<string>('attacked')

  // Slider position (0 = all original, 100 = all comparison)
  const [sliderPosition, setSliderPosition] = React.useState(50)

  // State for video scale
  const [videoScale, setVideoScale] = React.useState(1)

  // Playback time ref for syncing position
  const playbackTimeRef = React.useRef(0)
  // Refs for all video elements
  const videoRefs = React.useMemo(() => {
    const refs: Record<string, React.RefObject<HTMLVideoElement>> = {}
    variantKeys.forEach((v) => {
      refs[v] = React.createRef<HTMLVideoElement>()
    })
    return refs
  }, [variantKeys.join(',')])

  // Track if videos are playing and data loading
  const [isPlaying, setIsPlaying] = React.useState(false)
  const [isDataLoaded, setIsDataLoaded] = React.useState(false)

  // Track if video was playing before seeking
  const [wasPlayingBeforeSeeking, setWasPlayingBeforeSeeking] = React.useState(false)

  // Toggle playback of all videos
  const togglePlayback = () => {
    if (isPlaying) {
      // Pause all videos
      variantKeys.forEach((v) => {
        if (videoRefs[v]?.current) {
          videoRefs[v]?.current?.pause()
        }
      })
      setIsPlaying(false)
    } else {
      // Play all videos
      variantKeys.forEach((v) => {
        if (videoRefs[v]?.current) {
          videoRefs[v]?.current?.play()
        }
      })
      setIsPlaying(true)
    }
  }

  // When the video plays or pauses, update isPlaying state
  const handlePlay = () => {
    setIsPlaying(true)
  }

  const handlePause = () => {
    setIsPlaying(false)
  }

  // When any video time updates, sync all others
  const handleTimeUpdate = (sourceVariant: string) => {
    const sourceRef = videoRefs[sourceVariant]?.current
    if (sourceRef) {
      playbackTimeRef.current = sourceRef.currentTime

      // Only sync other videos, time display is handled by requestAnimationFrame
      // for smoother updates
      variantKeys.forEach((v) => {
        if (v !== sourceVariant && videoRefs[v]?.current) {
          const targetRef = videoRefs[v].current
          // Use a smaller threshold for more precise sync (0.05s instead of 0.1s)
          if (Math.abs(targetRef.currentTime - playbackTimeRef.current) > 0.05) {
            targetRef.currentTime = playbackTimeRef.current
          }
        }
      })
    }
  }

  // Format time in MM:SS.ms format
  const formatTime = (timeInSeconds: number): string => {
    if (isNaN(timeInSeconds)) return '00:00.00'
    const minutes = Math.floor(timeInSeconds / 60)
    const seconds = Math.floor(timeInSeconds % 60)
    const milliseconds = Math.floor((timeInSeconds % 1) * 100)
    return `${minutes.toString().padStart(2, '0')}:${seconds.toString().padStart(2, '0')}.${milliseconds.toString().padStart(2, '0')}`
  }

  // Video container dimensions state
  const [videoDimensions, setVideoDimensions] = React.useState({ width: 0, height: 0 })

  // Handle video loaded metadata to get dimensions
  const handleLoadedMetadata = (e: React.SyntheticEvent<HTMLVideoElement>) => {
    const video = e.currentTarget
    setVideoDimensions({
      width: video.videoWidth,
      height: video.videoHeight,
    })
    setIsDataLoaded(true)
  }

  // Variable to track current time and duration
  const [videoTime, setVideoTime] = React.useState({ current: 0, duration: 0 })

  // Update time display when time updates
  const handleTimeDisplayUpdate = () => {
    if (videoRefs[originalVariant]?.current) {
      const video = videoRefs[originalVariant].current
      // Store the time with full precision (up to milliseconds)
      setVideoTime({
        current: video.currentTime,
        duration: video.duration || 0,
      })
    }
  }

  // Memoized formatted times
  const formattedCurrentTime = React.useMemo(
    () => formatTime(videoTime.current),
    [videoTime.current]
  )
  const formattedDuration = React.useMemo(
    () => formatTime(videoTime.duration),
    [videoTime.duration]
  )

  // Add a requestAnimationFrame-based timer for smoother time updates
  const animationFrameRef = React.useRef<number | null>(null)

  // Effect to continuously update the time for smoother display
  React.useEffect(() => {
    const updateTimeLoop = () => {
      if (videoRefs[originalVariant]?.current) {
        const video = videoRefs[originalVariant].current
        // Always update the time, regardless of playing state
        setVideoTime((prev) => ({
          ...prev,
          current: video.currentTime,
          duration: video.duration || 0,
        }))
      }
      // Continue the loop
      animationFrameRef.current = requestAnimationFrame(updateTimeLoop)
    }

    // Start the loop - always run to ensure slider stays in sync
    animationFrameRef.current = requestAnimationFrame(updateTimeLoop)

    // Clean up on unmount
    return () => {
      if (animationFrameRef.current !== null) {
        cancelAnimationFrame(animationFrameRef.current)
        animationFrameRef.current = null
      }
    }
  }, [originalVariant])

  if (!videoNames.length) {
    return (
      <div className="w-full mt-12 flex items-center justify-center">
        <div className="text-gray-500">
          No video examples available. Please select another model and attack.
        </div>
      </div>
    )
  }

  // Calculate clip path for original and comparison videos
  const originalClipPath = `inset(0 ${100 - sliderPosition}% 0 0)` // Left side (original)
  const comparisonClipPath = `inset(0 0 0 ${sliderPosition}%)` // Right side (comparison/variant)

  return (
    <div className="w-full overflow-auto" style={{ minHeight: '100vh' }}>
      <div className="example-display">
        <div className="mb-4">
          <fieldset className="fieldset">
            <legend className="fieldset-legend">Video</legend>
            <select
              className="select select-bordered"
              value={selectedVideo || ''}
              onChange={(e) => {
                setSelectedVideo(e.target.value || '')
              }}
            >
              {videoNames.map((name) => (
                <option key={name} value={name}>
                  {name}
                </option>
              ))}
            </select>
          </fieldset>
        </div>
        {selectedVideo && variants[originalVariant] && variants[comparisonVariant] && (
          <>
            <ExampleVariantMetricsTables
              variantMetadatas={Object.fromEntries(
                variantKeys.map((v) => [v, variants[v]?.metadata || {}])
              )}
            />
            <ExampleDetailsSection>
              <div className="flex flex-col gap-4">
                <div className="flex items-center gap-4 mt-2">
                  <label htmlFor="comparison-variant" className="font-mono text-xs">
                    Right Side:
                  </label>
                  <select
                    id="comparison-variant"
                    className="select select-bordered select-xs"
                    value={comparisonVariant}
                    onChange={(e) => setComparisonVariant(e.target.value)}
                  >
                    {variantKeys
                      .filter((v) => v !== originalVariant)
                      .map((v) => (
                        <option key={v} value={v}>
                          {VARIANT_NAME_MAP[v]}
                        </option>
                      ))}
                  </select>

                  <button onClick={togglePlayback} className="btn btn-xs btn-primary ml-4">
                    {isPlaying ? 'Pause' : 'Play'}
                  </button>

                  <label htmlFor="video-scale" className="font-mono text-xs ml-4">
                    Scale:
                  </label>
                  <input
                    id="video-scale"
                    type="range"
                    min={0.3}
                    max={1}
                    step={0.01}
                    value={videoScale}
                    onChange={(e) => setVideoScale(Number(e.target.value))}
                    className="range range-xs"
                    style={{
                      verticalAlign: 'middle',
                      width: '120px', // Make slider smaller
                      accentColor: '#3b82f6', // Match playback slider color
                    }}
                  />
                  <span className="ml-2 font-mono text-xs">{(videoScale * 100).toFixed(0)}%</span>
                </div>

                {/* Labels for comparison */}
                <div className="mb-2">
                  <div className="flex justify-between text-xs font-mono">
                    <span className="font-bold">Left: {VARIANT_NAME_MAP[originalVariant]}</span>
                    <span className="font-bold">Right: {VARIANT_NAME_MAP[comparisonVariant]}</span>
                  </div>
                </div>

                {/* Video comparison container */}
                <div
                  className="relative w-full"
                  style={{ width: `${videoScale * 100}%`, margin: '0 auto', minHeight: '300px' }}
                >
                  {/* Reference video for dimensions (invisible) */}
                  <video
                    className="w-full h-auto opacity-0"
                    src={API.getProxiedUrl(variants[originalVariant].video_url || '')}
                  />

                  {/* Original video */}
                  {variants[originalVariant]?.video_url && (
                    <div
                      className="absolute top-0 left-0 w-full h-full"
                      style={{ clipPath: originalClipPath }}
                    >
                      <video
                        ref={videoRefs[originalVariant]}
                        controls={false}
                        src={API.getProxiedUrl(variants[originalVariant].video_url)}
                        className="w-full h-auto"
                        onTimeUpdate={() => handleTimeUpdate(originalVariant)}
                        onDurationChange={handleTimeDisplayUpdate}
                        onPlay={handlePlay}
                        onPause={handlePause}
                        onLoadedMetadata={handleLoadedMetadata}
                      />
                    </div>
                  )}

                  {/* Comparison video */}
                  {variants[comparisonVariant]?.video_url && (
                    <div
                      className="absolute top-0 left-0 w-full h-full"
                      style={{ clipPath: comparisonClipPath }}
                    >
                      <video
                        ref={videoRefs[comparisonVariant]}
                        controls={false}
                        src={API.getProxiedUrl(variants[comparisonVariant].video_url)}
                        className="w-full h-auto"
                        onTimeUpdate={() => handleTimeUpdate(comparisonVariant)}
                        onDurationChange={handleTimeDisplayUpdate}
                        onPlay={handlePlay}
                        onPause={handlePause}
                        onLoadedMetadata={handleLoadedMetadata}
                      />
                    </div>
                  )}

                  {/* Slider handle indicator */}
                  <div
                    className="absolute top-0 bottom-0 z-10 pointer-events-none"
                    style={{
                      left: `${sliderPosition}%`,
                      height: '100%',
                      width: '4px',
                      display: 'flex',
                      flexDirection: 'column',
                      justifyContent: 'center',
                      alignItems: 'center',
                    }}
                  >
                    <div className="bg-white h-full w-1 opacity-80"></div>
                    <div
                      className="absolute bg-white rounded-full p-1.5 opacity-90 shadow-md"
                      style={{
                        transform: 'translate(-50%, 0)',
                        left: '50%',
                      }}
                    >
                      <svg
                        width="20"
                        height="20"
                        viewBox="0 0 24 24"
                        fill="none"
                        xmlns="http://www.w3.org/2000/svg"
                      >
                        <path
                          d="M8 7L4 12L8 17M16 7L20 12L16 17"
                          stroke="black"
                          strokeWidth="2.5"
                          strokeLinecap="round"
                          strokeLinejoin="round"
                        />
                      </svg>
                    </div>
                  </div>

                  {/* Transparent controls overlay */}
                  <div
                    className="absolute top-0 left-0 w-full h-full z-20"
                    style={{
                      background: 'transparent',
                      display: 'flex',
                      flexDirection: 'column',
                      justifyContent: 'flex-end',
                    }}
                  >
                    {/* Slider directly on video */}
                    <input
                      type="range"
                      min={0}
                      max={100}
                      value={sliderPosition}
                      onChange={(e) => setSliderPosition(Number(e.target.value))}
                      className="range range-xs w-full absolute top-1/2 left-0 right-0 z-30"
                      style={{
                        transform: 'translateY(-50%)',
                        margin: '0 auto',
                        width: '100%', // Full width
                        opacity: 0,
                        cursor: 'ew-resize',
                        height: '50px', // Taller hit area for easier interaction
                      }}
                    />

                    {/* Click area for play/pause - covers entire video */}
                    <div className="w-full h-full" onClick={togglePlayback}></div>
                  </div>

                  {/* Play/pause icon overlay */}
                  {!isPlaying && (
                    <div
                      className="absolute top-1/2 left-1/2 transform -translate-x-1/2 -translate-y-1/2
                                bg-black bg-opacity-60 rounded-full p-4 cursor-pointer z-40"
                      onClick={togglePlayback}
                    >
                      <svg
                        width="30"
                        height="30"
                        viewBox="0 0 24 24"
                        fill="none"
                        xmlns="http://www.w3.org/2000/svg"
                      >
                        <path d="M8 5V19L19 12L8 5Z" fill="white" />
                      </svg>
                    </div>
                  )}
                </div>

                {/* Playback position slider */}
                <div className="w-full mt-2 flex flex-col gap-1" style={{ width: '100%' }}>
                  <input
                    type="range"
                    min={0}
                    max={videoTime.duration || 100}
                    step={0.01} /* More granular step size for smoother scrubbing */
                    value={videoTime.current || 0}
                    onMouseDown={() => {
                      // Store current playing state
                      setWasPlayingBeforeSeeking(isPlaying)
                      if (isPlaying) {
                        // Pause videos while seeking
                        variantKeys.forEach((v) => {
                          if (videoRefs[v]?.current) {
                            videoRefs[v].current.pause()
                          }
                        })
                        setIsPlaying(false)
                      }
                    }}
                    onChange={(e) => {
                      const newTime = parseFloat(e.target.value)
                      // Only update time display immediately for responsive UI
                      setVideoTime((prev) => ({ ...prev, current: newTime }))
                    }}
                    onInput={(e) => {
                      // Update videos as user drags (more responsive than just onChange)
                      const newTime = parseFloat((e.target as HTMLInputElement).value)
                      variantKeys.forEach((v) => {
                        if (videoRefs[v]?.current) {
                          videoRefs[v].current.currentTime = newTime
                        }
                      })
                    }}
                    onMouseUp={(e) => {
                      // Final time setting to ensure perfect sync on release
                      const newTime = parseFloat((e.target as HTMLInputElement).value)
                      variantKeys.forEach((v) => {
                        if (videoRefs[v]?.current) {
                          videoRefs[v].current.currentTime = newTime
                        }
                      })

                      // If it was playing before seeking, resume playback
                      if (document.activeElement === e.target) {
                        // Remove focus from the slider
                        ;(e.target as HTMLInputElement).blur()

                        // Small delay to ensure the time has been updated
                        setTimeout(() => {
                          // Resume playback if it was playing before
                          if (wasPlayingBeforeSeeking) {
                            variantKeys.forEach((v) => {
                              if (videoRefs[v]?.current) {
                                videoRefs[v].current.play()
                              }
                            })
                            setIsPlaying(true)
                          }
                        }, 100)
                      }
                    }}
                    className="range range-xs w-full"
                    style={{
                      width: '100%' /* Ensure full width */,
                      height: '14px',
                      borderRadius: '7px' /* More rounded corners - half the height */,
                      accentColor: '#3b82f6' /* Match scale slider color */,
                      outline: 'none',
                      cursor: 'pointer',
                      appearance: 'none',
                      WebkitAppearance: 'none',
                      padding: '0',
                      margin: '0',
                      background: '#e5e7eb' /* Light gray background */,
                    }}
                  />

                  {/* Playback time display */}
                  <div className="flex justify-between text-xs font-mono">
                    <span>{formattedCurrentTime}</span>
                    <span>{formattedDuration}</span>
                  </div>
                </div>
              </div>
            </ExampleDetailsSection>
          </>
        )}
      </div>
    </div>
  )
}

export default VideoGallery
