// frontend/src/components/ui/ModelPreview.tsx
'use client'

import { useEffect, useMemo, useRef, useState } from 'react'
import HoverPopover from './HoverPopover'
import LiveVideo from './LiveVideo'
import {
  XMarkIcon,
  SpeakerXMarkIcon,
  SpeakerWaveIcon,
} from '@heroicons/react/24/outline'
import LoadingSpinner from './LoadingSpinner'

type Props = {
  jobId: string
  modelKey?: string
  live?: boolean
  thumbTick?: number
  autoTickMs?: number
  blur?: boolean
  className?: string
  fit?: 'cover' | 'contain'
  roomStatus?: string
  fallbackSrc?: string
}

function buildChaturbateCookieHeader(): string {
  try {
    const raw = window.localStorage.getItem('record_cookies')
    if (!raw) return ''

    const obj = JSON.parse(raw) as Record<string, string>
    return Object.entries(obj ?? {})
      .map(([k, v]) => [String(k ?? '').trim(), String(v ?? '').trim()] as const)
      .filter(([k, v]) => k && v)
      .map(([k, v]) => `${k}=${v}`)
      .join('; ')
  } catch {
    return ''
  }
}

export default function ModelPreview({
  jobId,
  live = false,
  thumbTick,
  autoTickMs = 10_000,
  blur = false,
  className,
  fit = 'cover',
  roomStatus,
  fallbackSrc,
}: Props) {
  const rootRef = useRef<HTMLDivElement | null>(null)
  const [inView, setInView] = useState(false)
  const [pageVisible, setPageVisible] = useState(!document.hidden)
  const [localTick, setLocalTick] = useState(0)
  const [imgError, setImgError] = useState(false)
  const [liveSrc, setLiveSrc] = useState('')
  const [hoverOpen, setHoverOpen] = useState(false)

  const [livePreparing, setLivePreparing] = useState(false)
  const [liveReady, setLiveReady] = useState(false)

  const [popupMuted, setPopupMuted] = useState(true)
  const [popupVolume, setPopupVolume] = useState(1)

  const blurCls = blur ? 'blur-md' : ''
  const objectFitCls = fit === 'contain' ? 'object-contain' : 'object-cover'

  const normalizedRoomStatus = String(roomStatus ?? '').trim().toLowerCase()
  const showLiveBadge = normalizedRoomStatus !== '' && normalizedRoomStatus !== 'offline'
  
  const tick = live
    ? (typeof thumbTick === 'number' ? thumbTick : localTick)
    : 0

  const previewSrc = useMemo(() => {
    // Nur bereits vorhandenes preview.jpg anfordern, niemals on-the-fly generieren
    return `/api/preview?id=${encodeURIComponent(jobId)}&file=preview.jpg&v=${tick}`
  }, [jobId, tick])

  const fallbackImgSrc = useMemo(() => {
    const s = String(fallbackSrc ?? '').trim()
    if (s) return s
    return `/api/preview?id=${encodeURIComponent(jobId)}&fallbackOnly=1`
  }, [fallbackSrc, jobId])

  const liveStreamSrc = useMemo(
    () => `/api/preview/live?id=${encodeURIComponent(jobId)}&hover=1`,
    [jobId]
  )

  useEffect(() => {
    const onVis = () => setPageVisible(!document.hidden)
    document.addEventListener('visibilitychange', onVis)
    return () => document.removeEventListener('visibilitychange', onVis)
  }, [])

  useEffect(() => {
    const ac = new AbortController()

    const loadLive = async () => {
      if (!hoverOpen) {
        setLiveSrc('')
        setLivePreparing(false)
        setLiveReady(false)
        return
      }

      setLivePreparing(true)
      setLiveReady(false)

      const cookieHeader = buildChaturbateCookieHeader()

      try {
        // ✅ HLS-Refresh jetzt direkt über /api/preview/live
        const prepareRes = await fetch(
          `/api/preview/live?id=${encodeURIComponent(jobId)}&hover=1&prepare=1`,
          {
            method: 'GET',
            cache: 'no-store',
            signal: ac.signal,
            headers: cookieHeader
              ? { 'X-Chaturbate-Cookie': cookieHeader }
              : undefined,
          }
        )

        if (ac.signal.aborted) return

        // Auch wenn prepare fehlschlägt:
        // best effort -> Stream-Endpunkt trotzdem versuchen
        await prepareRes.json().catch(() => null)

        if (ac.signal.aborted) return

        setLiveSrc(`${liveStreamSrc}&ts=${Date.now()}`)
      } catch {
        if (ac.signal.aborted) return

        setLiveSrc(`${liveStreamSrc}&ts=${Date.now()}`)
      } finally {
        if (!ac.signal.aborted) {
          setLivePreparing(false)
        }
      }
    }

    void loadLive()

    return () => {
      ac.abort()
    }
  }, [hoverOpen, jobId, liveStreamSrc])

  useEffect(() => {
    const el = rootRef.current
    if (!el) return

    const obs = new IntersectionObserver(
      (entries) => {
        const entry = entries[0]
        setInView(Boolean(entry?.isIntersecting || entry?.intersectionRatio > 0))
      },
      {
        root: null,
        threshold: 0.01,
      }
    )

    obs.observe(el)
    return () => obs.disconnect()
  }, [])

  useEffect(() => {
    setImgError(false)
  }, [jobId])

  useEffect(() => {
    setImgError(false)
  }, [previewSrc])

  useEffect(() => {
    if (!live) return
    if (typeof thumbTick === 'number') return
    if (!inView) return
    if (!pageVisible) return

    const id = window.setInterval(() => {
      setLocalTick((x) => x + 1)
      setImgError(false)
    }, autoTickMs)

    return () => window.clearInterval(id)
  }, [live, thumbTick, inView, pageVisible, autoTickMs])

  return (
    <HoverPopover
      onOpenChange={(open) => {
        setHoverOpen(open)
        if (!open) {
          setLiveSrc('')
          setLivePreparing(false)
          setLiveReady(false)
        }
      }}
      content={(open, { close }) =>
        open && (
          <div className="w-[420px] max-w-[calc(100vw-1.5rem)]">
            <div
              className="relative rounded-lg overflow-hidden bg-black"
              style={{ paddingBottom: '56.25%' }}
            >
              <div className="absolute inset-0">
                <LiveVideo
                  src={liveSrc}
                  muted={popupMuted}
                  volume={popupVolume}
                  roomStatus={roomStatus}
                  onLoadingStart={() => {
                    setLiveReady(false)
                  }}
                  onReady={() => {
                    setLiveReady(true)
                  }}
                  onVolumeChange={(nextVolume, nextMuted) => {
                    setPopupVolume(nextVolume)
                    setPopupMuted(nextMuted)
                  }}
                  className="w-full h-full object-contain object-center relative z-0"
                />

                {livePreparing || !liveReady ? (
                  <div className="absolute inset-0 z-10 flex flex-col items-center justify-center gap-3 bg-black/85 text-white">
                    <LoadingSpinner />
                    <div className="text-sm font-medium">
                      {livePreparing ? 'Live-Vorschau wird vorbereitet…' : 'Live-Stream wird geladen…'}
                    </div>
                  </div>
                ) : null}

                {showLiveBadge ? (
                  <div className="absolute left-2 top-2 z-[20] inline-flex items-center gap-1.5 rounded-full bg-red-600/90 px-2 py-1 text-[11px] font-semibold text-white shadow-sm">
                    <span className="inline-block size-1.5 rounded-full bg-white animate-pulse" />
                    Live
                  </div>
                ) : null}

                <div className="absolute right-2 bottom-2 z-[60]">
                  <button
                    type="button"
                    className="pointer-events-auto inline-flex items-center justify-center rounded-full bg-white/90 px-2.5 py-1.5 text-gray-900 shadow-sm ring-1 ring-black/10 hover:bg-white focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-gray-500/70 dark:bg-black/55 dark:text-white dark:ring-white/10 dark:hover:bg-black/70 dark:focus-visible:outline-white/70"
                    title={popupMuted ? 'Ton an' : 'Stumm'}
                    aria-label={popupMuted ? 'Ton an' : 'Stumm'}
                    onClick={(e) => {
                      e.preventDefault()
                      e.stopPropagation()

                      if (popupMuted) {
                        setPopupMuted(false)
                        if (popupVolume <= 0) setPopupVolume(1)
                      } else {
                        setPopupMuted(true)
                      }
                    }}
                  >
                    {popupMuted ? (
                      <SpeakerXMarkIcon className="h-4 w-4" />
                    ) : (
                      <SpeakerWaveIcon className="h-4 w-4" />
                    )}
                  </button>
                </div>

                <button
                  type="button"
                  className="absolute right-2 top-2 z-20 inline-flex items-center justify-center rounded-md p-1.5 focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-white/70 bg-white/75 text-gray-900 ring-1 ring-black/10 hover:bg-white/90 dark:bg-black/40 dark:text-white dark:ring-white/10 dark:hover:bg-black/55"
                  aria-label="Live-Vorschau schließen"
                  title="Vorschau schließen"
                  onClick={(e) => {
                    e.preventDefault()
                    e.stopPropagation()
                    close()
                  }}
                >
                  <XMarkIcon className="h-4 w-4" />
                </button>
              </div>
            </div>
          </div>
        )
      }
    >
      <div
        ref={rootRef}
        className={[
          'block relative rounded bg-gray-100 dark:bg-white/5 overflow-hidden',
          className || 'w-full h-full',
        ].join(' ')}
        onClick={(e) => e.stopPropagation()}
        onMouseDown={(e) => e.stopPropagation()}
        onTouchStart={(e) => e.stopPropagation()}
        onPointerDown={(e) => e.stopPropagation()}
      >
        {inView ? (
          !imgError ? (
            <img
              src={previewSrc}
              loading="lazy"
              decoding="async"
              alt=""
              className={['block w-full h-full', objectFitCls, 'object-center', blurCls].filter(Boolean).join(' ')}
              onLoad={() => setImgError(false)}
              onError={() => setImgError(true)}
            />
          ) : (
            <img
              src={fallbackImgSrc}
              loading="lazy"
              decoding="async"
              alt=""
              className={['block w-full h-full', objectFitCls, 'object-center', blurCls].filter(Boolean).join(' ')}
            />
          )
        ) : (
          <div className={['block w-full h-full bg-gray-100 dark:bg-white/5', blurCls].filter(Boolean).join(' ')} />
        )}
      </div>
    </HoverPopover>
  )
}