import React from 'react'
import type { ExamplesData } from './Examples'
import { groupByNameAndVariant } from './galleryUtils'
import ExampleMetadata from './ExampleMetadata'
import ExampleDetailsSection from './ExampleDetailsSection'
import ExampleVariantSelector from './ExampleVariantSelector'

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

const ImageGallery: React.FC<GalleryProps> = ({ selectedModel, selectedAttack, examples }) => {
  const exampleItems = examples[selectedModel][selectedAttack]

  // Group by image name (name after removing variant prefix), and for each, map variant to metrics
  const grouped = groupByNameAndVariant(exampleItems)

  const imageNames = Object.keys(grouped)
  const [selectedImage, setSelectedImage] = React.useState(imageNames[0] || '')
  const variants = grouped[selectedImage] || {}
  const variantKeys = Object.keys(variants)
  const [selectedVariant, setSelectedVariant] = React.useState(variantKeys[0] || '')

  const [zoom, setZoom] = React.useState<{ x: number; y: number } | null>(null)
  const [imgDims, setImgDims] = React.useState<{ width: number; height: number }>({
    width: 0,
    height: 0,
  })
  const imgRef = React.useRef<HTMLImageElement | null>(null)

  // Set a fixed zoom box size for all variants
  const ZOOM_BOX_SIZE = 300
  const [zoomLevel, setZoomLevel] = React.useState(2) // 2x default zoom

  // Calculate the minimum width and height across all variants for the selected image
  const variantImages = variantKeys.map((v) => variants[v]?.image_url).filter(Boolean)
  const [naturalDims, setNaturalDims] = React.useState<{ width: number; height: number } | null>(
    null
  )

  React.useEffect(() => {
    let isMounted = true
    if (variantImages.length > 0) {
      Promise.all(
        variantImages.map(
          (src) =>
            new Promise<{ width: number; height: number }>((resolve) => {
              const img = new window.Image()
              img.onload = () => resolve({ width: img.naturalWidth, height: img.naturalHeight })
              img.src = src!
            })
        )
      ).then((dimsArr) => {
        if (!isMounted) return
        const first = dimsArr[0]
        const allSame = dimsArr.every((d) => d.width === first.width && d.height === first.height)
        if (!allSame) {
          setNaturalDims(null)
        } else {
          setNaturalDims(first)
        }
      })
    }
    return () => {
      isMounted = false
    }
  }, [variantImages.join(','), selectedImage])

  // Place the zoom level slider outside of the zoom hover logic
  const zoomSlider = (
    <div className="flex flex-col items-center mb-4 w-full">
      <label className="font-semibold text-xs mb-1">Zoom Level: {zoomLevel}x</label>
      <input
        type="range"
        min={2}
        max={6}
        step={0.1}
        value={zoomLevel}
        onChange={(e) => setZoomLevel(Number(e.target.value))}
        className="range range-xs w-48"
      />
    </div>
  )

  // If no image is selected, show a message
  if (!variantImages.length) {
    return (
      <div className="w-full mt-12 flex items-center justify-center">
        <div className="text-gray-500">
          No images available. Please select another model and attack.
        </div>
      </div>
    )
  }

  // Ensure the main container allows scrolling and images retain their natural size
  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">Image</legend>
            <select
              className="select select-bordered"
              value={selectedImage || ''}
              onChange={(e) => {
                setSelectedImage(e.target.value || '')
                const newVariants = grouped[e.target.value] || {}
                const newVariantKeys = Object.keys(newVariants)
                setSelectedVariant(newVariantKeys[0] || '')
              }}
            >
              {imageNames.map((name) => (
                <option key={name} value={name}>
                  {name}
                </option>
              ))}
            </select>
          </fieldset>
        </div>
        {selectedImage && selectedVariant && variants[selectedVariant] && (
          <>
            <ExampleVariantSelector
              variantKeys={variantKeys}
              selectedVariant={selectedVariant}
              setSelectedVariant={setSelectedVariant}
            />
            <ExampleMetadata metadata={variants[selectedVariant].metadata || {}} />

            <ExampleDetailsSection>
              {zoomSlider}
              <div
                style={{
                  width: '100%',
                  display: 'flex',
                  flexDirection: 'row',
                  justifyContent: 'center',
                }}
              >
                <div style={{ position: 'relative', flex: 'none', display: 'inline-block' }}>
                  {/* Original image and overlay */}
                  {naturalDims ? (
                    <img
                      ref={imgRef}
                      src={variants[selectedVariant].image_url as string}
                      alt={selectedImage}
                      width={naturalDims.width}
                      height={naturalDims.height}
                      style={{ display: 'block', cursor: 'zoom-in' }}
                      onMouseMove={(e) => {
                        const rect = (e.target as HTMLImageElement).getBoundingClientRect()
                        const x = e.clientX - rect.left
                        const y = e.clientY - rect.top
                        setZoom({ x, y })
                      }}
                      onMouseLeave={() => setZoom(null)}
                    />
                  ) : (
                    <div className="text-red-500 font-bold">
                      Image sizes do not match across variants!
                    </div>
                  )}
                  {/* Zoomed box - now overlays on top of the cursor position */}
                  {zoom &&
                    naturalDims &&
                    (() => {
                      const { width, height } = naturalDims
                      const halfBox = ZOOM_BOX_SIZE / (2 * zoomLevel)
                      let centerX = zoom.x
                      let centerY = zoom.y
                      centerX = Math.max(halfBox, Math.min(width - halfBox, centerX))
                      centerY = Math.max(halfBox, Math.min(height - halfBox, centerY))
                      const bgX = centerX * zoomLevel - ZOOM_BOX_SIZE / 2
                      const bgY = centerY * zoomLevel - ZOOM_BOX_SIZE / 2
                      return (
                        <div
                          style={{
                            position: 'absolute',
                            left: zoom.x - ZOOM_BOX_SIZE / 2, // use raw cursor position for overlay
                            top: zoom.y - ZOOM_BOX_SIZE / 2,
                            width: ZOOM_BOX_SIZE,
                            height: ZOOM_BOX_SIZE,
                            boxSizing: 'border-box',
                            backgroundImage: `url(${variants[selectedVariant]?.image_url})`,
                            backgroundPosition: `-${bgX}px -${bgY}px`,
                            backgroundSize: `${width * zoomLevel}px ${height * zoomLevel}px`,
                            backgroundRepeat: 'no-repeat',
                            zIndex: 10,
                            pointerEvents: 'none',
                            cursor: 'zoom-in',
                          }}
                        />
                      )
                    })()}
                </div>
              </div>
            </ExampleDetailsSection>
          </>
        )}
      </div>
    </div>
  )
}

export default ImageGallery
