// frontend\src\components\ui\PreviewScrubber.tsx

'use client'

import * as React from 'react'

type Props = {
  imageCount: number
  activeIndex?: number
  onActiveIndexChange: (index: number | undefined) => void
  onIndexClick?: (index: number) => void
  className?: string
  stepSeconds?: number
}

function clamp(n: number, min: number, max: number) {
  return Math.max(min, Math.min(max, n))
}

function formatClock(totalSeconds: number) {
  const s = Math.max(0, Math.floor(totalSeconds))
  const m = Math.floor(s / 60)
  const sec = s % 60
  return `${m}:${String(sec).padStart(2, '0')}`
}

export default function PreviewScrubber({
  imageCount,
  activeIndex,
  onActiveIndexChange,
  onIndexClick,
  className,
  stepSeconds = 0,
}: Props) {
  const rootRef = React.useRef<HTMLDivElement | null>(null)

  const rafRef = React.useRef<number | null>(null)
  const pendingIndexRef = React.useRef<number | undefined>(undefined)

  const flushPending = React.useCallback(() => {
    rafRef.current = null
    onActiveIndexChange(pendingIndexRef.current)
  }, [onActiveIndexChange])

  const setIndexThrottled = React.useCallback(
    (index: number | undefined) => {
      pendingIndexRef.current = index
      if (rafRef.current != null) return
      rafRef.current = window.requestAnimationFrame(flushPending)
    },
    [flushPending]
  )

  React.useEffect(() => {
    return () => {
      if (rafRef.current != null) {
        window.cancelAnimationFrame(rafRef.current)
        rafRef.current = null
      }
    }
  }, [])

  const indexFromClientX = React.useCallback(
    (clientX: number) => {
      if (!rootRef.current || imageCount < 1) return undefined

      const rect = rootRef.current.getBoundingClientRect()
      if (rect.width <= 0) return undefined

      const x = clientX - rect.left
      const ratio = clamp(x / rect.width, 0, 0.999999)
      const idx = clamp(Math.floor(ratio * imageCount), 0, imageCount - 1)
      return idx
    },
    [imageCount]
  )

  const handlePointerMove = React.useCallback(
    (e: React.PointerEvent<HTMLDivElement>) => {
      const idx = indexFromClientX(e.clientX)
      setIndexThrottled(idx)
    },
    [indexFromClientX, setIndexThrottled]
  )

  const handlePointerEnter = React.useCallback(
    (e: React.PointerEvent<HTMLDivElement>) => {
      const idx = indexFromClientX(e.clientX)
      setIndexThrottled(idx)
    },
    [indexFromClientX, setIndexThrottled]
  )

  const handlePointerLeave = React.useCallback(() => {
    setIndexThrottled(undefined)
  }, [setIndexThrottled])

  const handlePointerDown = React.useCallback(
    (e: React.PointerEvent<HTMLDivElement>) => {
      e.stopPropagation()
      const idx = indexFromClientX(e.clientX)
      setIndexThrottled(idx)
      try {
        e.currentTarget.setPointerCapture?.(e.pointerId)
      } catch {}
    },
    [indexFromClientX, setIndexThrottled]
  )

  const handleClick = React.useCallback(
    (e: React.MouseEvent<HTMLDivElement>) => {
      e.stopPropagation()
      if (!onIndexClick) return
      const idx = indexFromClientX(e.clientX)
      if (typeof idx === 'number') onIndexClick(idx)
    },
    [indexFromClientX, onIndexClick]
  )

  if (!imageCount || imageCount < 1) return null

  const markerLeftPct =
    typeof activeIndex === 'number'
      ? ((activeIndex + 0.5) / imageCount) * 100
      : undefined

  const label =
    typeof activeIndex === 'number'
      ? stepSeconds > 0
        ? formatClock(activeIndex * stepSeconds)
        : `${activeIndex + 1}/${imageCount}`
      : ''

  const showLabel = typeof activeIndex === 'number'

  const labelLeftStyle =
    typeof markerLeftPct === 'number'
      ? {
          left: `clamp(24px, ${markerLeftPct}%, calc(100% - 24px))`,
          transform: 'translateX(-50%)',
        }
      : undefined

  return (
    <div
      ref={rootRef}
      className={[
        'relative h-7 w-full select-none touch-none cursor-col-resize',
        // standardmäßig versteckt, nur bei Hover/Focus auf dem Parent-Video sichtbar
        'opacity-0 transition-opacity duration-150',
        'pointer-events-none',
        'group-hover:opacity-100 group-focus-within:opacity-100',
        'group-hover:pointer-events-auto group-focus-within:pointer-events-auto',
        className,
      ]
        .filter(Boolean)
        .join(' ')}
      onPointerMove={handlePointerMove}
      onPointerEnter={handlePointerEnter}
      onPointerLeave={handlePointerLeave}
      onPointerDown={handlePointerDown}
      onMouseDown={(e) => e.stopPropagation()}
      onClick={handleClick}
      title={showLabel ? label : `Preview scrubber (${imageCount})`}
      role="slider"
      aria-label="Preview scrubber"
      aria-valuemin={1}
      aria-valuemax={imageCount}
      aria-valuenow={typeof activeIndex === 'number' ? activeIndex + 1 : undefined}
    >
      <div className="pointer-events-none absolute inset-x-0 bottom-0 h-4 bg-white/35 ring-1 ring-white/40 backdrop-blur-[1px]">
        {typeof markerLeftPct === 'number' ? (
          <div
            className="absolute inset-y-0 w-[2px] bg-white shadow-[0_0_0_1px_rgba(0,0,0,0.35)]"
            style={{
              left: `${markerLeftPct}%`,
              transform: 'translateX(-50%)',
            }}
          />
        ) : null}
      </div>
      
      <div
        className={[
          'pointer-events-none absolute bottom-[19px] z-10',
          'rounded bg-black/70 px-1.5 py-0.5',
          'text-[11px] leading-none text-white whitespace-nowrap',
          'transition-opacity duration-100',
          showLabel ? 'opacity-100' : 'opacity-0',
          '[text-shadow:_0_1px_2px_rgba(0,0,0,0.9)]',
        ].join(' ')}
        style={labelLeftStyle}
      >
        {label}
      </div>
    </div>
  )
}