// MatchReadyOverlay.tsx
'use client'

import { useCallback, useEffect, useMemo, useRef, useState } from 'react'
import { sound } from '@/app/lib/soundManager'
import { useSSEStore } from '@/app/lib/useSSEStore'
import { useSession } from 'next-auth/react'
import LoadingSpinner from './LoadingSpinner'
import { MAP_OPTIONS } from '../lib/mapOptions'
import type { MapOption } from '../lib/mapOptions'

type Props = {
  open: boolean
  matchId: string
  mapLabel: string
  mapBg: string
  onAccept: () => void | Promise<void>
  deadlineAt?: number
  onTimeout?: () => void
  forceGif?: boolean
  connectHref?: string
}

type Presence = 'online' | 'away' | 'offline'

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

export default function MatchReadyOverlay({
  open,
  matchId,
  mapLabel,
  mapBg,
  onAccept,
  deadlineAt,
  onTimeout,
  forceGif,
  connectHref = 'steam://connect/cs2.ironieopen.de:27015/ironie',
}: Props) {
  const { data: session } = useSession()
  const mySteamId = session?.user?.steamId
  const { lastEvent } = useSSEStore()

  const [now, setNow] = useState(() => Date.now())
  const [startedAt] = useState(() => Date.now())
  const fallbackDeadline = useMemo(() => startedAt + 20_000, [startedAt])
  const effectiveDeadline = deadlineAt ?? fallbackDeadline
  const rest = Math.max(0, effectiveDeadline - now)

  // UI-States
  const [accepted, setAccepted] = useState(false)
  const [finished, setFinished] = useState(false)
  const [showWaitHint, setShowWaitHint] = useState(false)
  const [connecting, setConnecting] = useState(false)
  const isVisible = open || accepted || showWaitHint

  const [showBackdrop, setShowBackdrop] = useState(false)
  const [showContent, setShowContent] = useState(false)

  // Ready-Listen-Status
  type Participant = { steamId: string; name: string; avatar: string; team: 'A' | 'B' | null }
  const [participants, setParticipants] = useState<Participant[]>([])
  const [readyMap, setReadyMap] = useState<Record<string, string>>({})
  const [total, setTotal] = useState(0)
  const [countReady, setCountReady] = useState(0)

  // Presence-Map (SSE)
  const [statusMap, setStatusMap] = useState<Record<string, Presence>>({})

  const prevCountReadyRef = useRef<number>(0)
  const ignoreNextIncreaseRef = useRef(false)

  // ----- AUDIO -----
  const beepsRef = useRef<ReturnType<typeof setInterval> | null>(null)
  const audioStartedRef = useRef(false)

  const stopBeeps = () => { if (beepsRef.current) { clearInterval(beepsRef.current); beepsRef.current = null } }

  const ensureAudioUnlocked = async () => {
    try {
      if (typeof (sound as any).ensureUnlocked === 'function') { await (sound as any).ensureUnlocked(); return true }
      if (typeof (sound as any).unlock === 'function') { await (sound as any).unlock(); return true }
      const ctx = (sound as any).ctx || (sound as any).audioContext
      if (ctx && typeof ctx.resume === 'function' && ctx.state !== 'running') await ctx.resume()
      return true
    } catch { return false }
  }

  const startBeeps = () => {
    try { sound.play('ready') } catch {}
    stopBeeps()
    beepsRef.current = setInterval(() => { try { sound.play('beep') } catch {} }, 1000)
  }

  const playMenuAccept = () => {
    try { (sound as any).play?.('menu_accept') } catch {}
    try { new Audio('/assets/sounds/menu_accept.wav').play() } catch {}
  }

  // NUR nach Acceptance laden/aktualisieren
  const loadReady = useCallback(async () => {
    try {
      const r = await fetch(`/api/matches/${matchId}/ready`, { cache: 'no-store' })
      if (!r.ok) return
      const j = await r.json()
      setParticipants(j.participants ?? [])
      setReadyMap(j.ready ?? {})
      setTotal(j.total ?? 0)
      setCountReady(j.countReady ?? 0)
    } catch {}
  }, [matchId])

  // ---- Accept-Handling ----
  const postingRef = useRef(false)

  const onAcceptClick = async () => {
    if (postingRef.current) return
    postingRef.current = true
    try {
      stopBeeps()
      playMenuAccept()

      const res = await fetch(`/api/matches/${matchId}/ready`, {
        method: 'POST',
        headers: { 'Content-Type': 'application/json', 'X-Ready-Accept': '1' },
        cache: 'no-store',
        body: JSON.stringify({ intent: 'accept' }),
      })
      if (!res.ok) return

      setAccepted(true)
      try { await onAccept() } catch {}
      await loadReady()
    } finally {
      postingRef.current = false
    }
  }

  // Backdrop zuerst faden, dann Content
  useEffect(() => {
    if (!isVisible) { setShowBackdrop(false); setShowContent(false); return }
    setShowBackdrop(true)
    const id = setTimeout(() => setShowContent(true), 2000)
    return () => clearTimeout(id)
  }, [isVisible])

  if (!isVisible) return null

  // Nach Accept ein kurzer Refresh
  useEffect(() => {
    if (!accepted) return
    const id = setTimeout(loadReady, 250)
    return () => clearTimeout(id)
  }, [accepted, loadReady])

  // SSE
  useEffect(() => {
    if (!lastEvent) return
    const type = (lastEvent as any).type ?? (lastEvent as any)?.payload?.type
    const payload = (lastEvent as any).payload?.payload ?? (lastEvent as any).payload ?? lastEvent

    if (type === 'ready-updated' && payload?.matchId === matchId) {
      if (accepted) {
        const otherSteamId = payload?.steamId as string | undefined
        if (otherSteamId && otherSteamId !== mySteamId) playMenuAccept()
      }
      loadReady()
      return
    }

    if (type === 'user-status-updated') {
      const steamId: string | undefined = payload?.steamId ?? payload?.user?.steamId
      const status = payload?.status as Presence | undefined
      if (steamId && (status === 'online' || status === 'away' || status === 'offline')) {
        setStatusMap(prev => (prev[steamId] === status ? prev : { ...prev, [steamId]: status }))
      }
    }
  }, [accepted, lastEvent, matchId, mySteamId, loadReady])

  // ----- simple mount animation flags -----
  const [fadeIn, setFadeIn] = useState(false)
  useEffect(() => {
    if (!isVisible) { setFadeIn(false); return }
    const id = requestAnimationFrame(() => setFadeIn(true))
    return () => cancelAnimationFrame(id)
  }, [isVisible])

  // ----- motion layer (video/gif) -----
  const prefersReducedMotion = useMemo(
    () => typeof window !== 'undefined' && window.matchMedia?.('(prefers-reduced-motion: reduce)').matches,
    []
  )
  const videoRef = useRef<HTMLVideoElement | null>(null)
  const [useGif, setUseGif] = useState<boolean>(() => !!forceGif || !!prefersReducedMotion)

  useEffect(() => {
    if (!isVisible) return
    if (forceGif || prefersReducedMotion) { setUseGif(true); return }
    const tryPlay = async () => {
      const v = videoRef.current
      if (!v) return
      try { await v.play(); setUseGif(false) }
      catch {
        setUseGif(true)
        const once = async () => {
          try { await v.play(); setUseGif(false) } catch {}
          window.removeEventListener('pointerdown', once)
          window.removeEventListener('keydown', once)
        }
        window.addEventListener('pointerdown', once, { once: true })
        window.addEventListener('keydown', once, { once: true })
      }
    }
    const id = setTimeout(tryPlay, 0)
    return () => clearTimeout(id)
  }, [isVisible, forceGif, prefersReducedMotion])

  useEffect(() => {
    if (isVisible) return
    const v = videoRef.current
    if (v) {
      try { v.pause() } catch {}
      v.removeAttribute('src')
      while (v.firstChild) v.removeChild(v.firstChild)
    }
  }, [isVisible])

  // ----- AUDIO: Beeps starten/stoppen -----
  useEffect(() => {
    if (!isVisible) { stopBeeps(); audioStartedRef.current = false; return }
    if (audioStartedRef.current) return
    let cleanup = () => {}
    ;(async () => {
      const ok = await ensureAudioUnlocked()
      if (ok) { audioStartedRef.current = true; startBeeps(); return }
      const onGesture = async () => {
        const ok2 = await ensureAudioUnlocked()
        if (ok2) { audioStartedRef.current = true; startBeeps() }
        window.removeEventListener('pointerdown', onGesture)
        window.removeEventListener('keydown', onGesture)
      }
      window.addEventListener('pointerdown', onGesture, { once: true })
      window.addEventListener('keydown', onGesture, { once: true })
      cleanup = () => {
        window.removeEventListener('pointerdown', onGesture)
        window.removeEventListener('keydown', onGesture)
      }
    })()
    return () => { cleanup(); stopBeeps() }
  }, [isVisible])

  // ----- countdown / timeout -----
  const rafRef = useRef<number | null>(null)
  useEffect(() => {
    if (!isVisible) return
    const step = () => {
      const t = Date.now()
      setNow(t)
      if (effectiveDeadline - t <= 0 && !finished) {
        stopBeeps()
        setFinished(true)

        if (accepted) {
          setConnecting(true)
          try { sound.play('loading') } catch {}

          const doConnect = () => {
            try { window.location.href = connectHref }
            catch {
              try {
                const a = document.createElement('a')
                a.href = connectHref
                document.body.appendChild(a)
                a.click()
                a.remove()
              } catch {}
            }
            try { onTimeout?.() } catch {}
          }
          setTimeout(doConnect, 2000)
        } else {
          setShowWaitHint(true)
        }
        return
      }
      rafRef.current = requestAnimationFrame(step)
    }
    rafRef.current = requestAnimationFrame(step)
    return () => { if (rafRef.current) cancelAnimationFrame(rafRef.current) }
  }, [isVisible, effectiveDeadline, accepted, finished, connectHref, onTimeout])

  // ---- Präsenz → Rahmenfarbe ----
  const borderByPresence = (s: Presence | undefined): string => {
    switch (s) {
      case 'online':  return 'border-[#2ecc71]'
      case 'away':    return 'border-yellow-400'
      case 'offline':
      default:        return 'border-white/20'
    }
  }

  // 🔎 Map-Icon aus MAP_OPTIONS ermitteln
  const mapIconUrl = useMemo(() => {
    const norm = (s?: string | null) => (s ?? '').trim().toLowerCase()
    const keyFromBg = /\/maps\/([^/]+)\//.exec(mapBg ?? '')?.[1]

    const byKey   = keyFromBg  ? MAP_OPTIONS.find(o => o.key === keyFromBg) : undefined
    const byLabel = mapLabel   ? MAP_OPTIONS.find(o => norm(o.label) === norm(mapLabel)) : undefined
    const byImage = mapBg      ? MAP_OPTIONS.find(o => o.images.includes(mapBg)) : undefined

    const opt = byKey ?? byLabel ?? byImage
    return opt?.icon ?? '/assets/img/mapicons/map_icon_lobby_mapveto.svg'
  }, [mapBg, mapLabel])

  // --- UI Helpers ---
  const ReadyRow = () => (
    <div className="absolute left-0 right-0 bottom-0 px-4 py-3">
      <div className="flex items-center gap-2 mb-1 justify-center">
        <div className="flex gap-2">
          {Array.from({ length: Math.max(total, 10) }, (_, i) => {
            const p = participants[i]
            const isReady = p ? !!readyMap[p.steamId] : false
            const presence: Presence = (p && statusMap[p.steamId]) || 'offline'
            const borderCls = borderByPresence(presence)

            return (
              <div
                key={i}
                className={[
                  'relative w-9 h-9 rounded-sm border overflow-hidden',
                  borderCls,
                  isReady ? 'bg-[#2ecc71]/85' : 'bg-white/10'
                ].join(' ')}
                title={p ? `${p.name} – ${isReady ? 'bereit' : 'nicht bereit'}` : ''}
              >
                {p ? (
                  <>
                    <img
                      src={p.avatar}
                      alt={p.name}
                      className={[
                        'w-full h-full object-cover rounded-[2px] transition-opacity',
                        isReady ? '' : 'opacity-40 filter grayscale'
                      ].join(' ')}
                    />
                    {!isReady && <div className="absolute inset-0 bg-black/30 pointer-events-none" />}
                  </>
                ) : (
                  <div className="w-full h-full grid place-items-center">
                    <svg viewBox="0 0 24 24" className="w-6 h-6 opacity-60" fill="currentColor">
                      <path d="M12 12a5 5 0 1 0-5-5 5 5 0 0 0 5 5Zm0 2c-5 0-9 2.5-9 5.5A1.5 1.5 0 0 0 4.5 21h15A1.5 1.5 0 0 0 21 19.5C21 16.5 17 14 12 14Z" />
                    </svg>
                  </div>
                )}
              </div>
            )
          })}
        </div>
      </div>
      <div className="text-center text-[14px] font-medium text-[#63d45d]">
        {countReady} / {total} Spieler bereit
      </div>
    </div>
  )

  return (
    <div className="fixed inset-0 z-[1000]">
      {/* Backdrop: 2s-Fade */}
      <div
        className={[
          'absolute inset-0 bg-black/60 transition-opacity duration-[2000ms] ease-out',
          showBackdrop ? 'opacity-100' : 'opacity-0'
        ].join(' ')}
      />

      {/* Content erst nach Backdrop-Delay */}
      {showContent && (
        <div
          className={[
            'absolute top-1/2 left-1/2 -translate-x-1/2 -translate-y-1/2',
            'w-[720px] h-[352px] max-w-[95vw]',
            'border-[6px] border-[#30c237] rounded-md overflow-hidden shadow-2xl relative',
            'transition-all duration-300 ease-out',
            fadeIn ? 'opacity-100 scale-100' : 'opacity-0 scale-[0.98]'
          ].join(' ')}
        >
          {/* Map */}
          <img src={mapBg} alt={mapLabel} className="absolute inset-0 w-full h-full object-cover brightness-90" />

          {/* Deko-Layer */}
          {useGif ? (
            <div className="absolute inset-0 opacity-50 pointer-events-none">
              <img src="/assets/vids/overlay_cs2_accept.gif" alt="" className="absolute inset-0 w-full h-full object-cover" decoding="async" loading="eager" />
              <div className="absolute inset-0 bg-[radial-gradient(circle_at_50%_20%,rgba(255,255,255,0.08),transparent_60%)]" />
            </div>
          ) : (
            <video
              ref={videoRef}
              className="absolute inset-0 w-full h-full object-cover opacity-50 pointer-events-none"
              autoPlay loop muted playsInline preload="auto"
            >
              <source src="/assets/vids/overlay_cs2_accept.webm" type="video/webm" />
            </video>
          )}

          {/* Inhalt */}
          <div className="relative z-10 h-full w-full flex flex-col items-center">
            <div className="mt-[28px] text-[30px] font-semibold text-[#6ae364]">
              DEIN SPIEL IST BEREIT!
              <span aria-hidden className="block h-px w-full bg-[#6ae364] shadow-[1px_1px_1px_#6ae3642c] rounded-sm" />
            </div>

            {/* ⬇️ Icon aus MAP_OPTIONS + Label */}
            <div className="mt-[10px] flex items-center justify-center text-[#8af784]">
              <img src={mapIconUrl} alt={`${mapLabel} Icon`} className="w-5 h-5 object-contain" />
              <span className="ml-2 text-[15px] [transform:scale(1,0.9)]">{mapLabel}</span>
            </div>

            {/* Accept / ReadyRow / WaitHint */}
            {accepted ? (
              <div className="mt-[18px] mb-[6px] h-[100px] w-full relative">
                <ReadyRow />
              </div>
            ) : showWaitHint ? (
              <div className="mt-[18px] mb-[6px] min-h-[100px] w-full flex flex-col items-center justify-center gap-2">
                <div className="px-3 py-1 rounded bg-yellow-100/90 text-yellow-900 text-[14px] font-semibold">
                  Dein Team wartet auf dich!
                </div>
                <a
                  href={connectHref}
                  className="px-4 py-2 rounded-md bg-[#61d365] hover:bg-[#4dc250] text-[#174d10] font-semibold text-lg shadow"
                >
                  Verbinden
                </a>
              </div>
            ) : (
              <button
                type="button"
                onClick={onAcceptClick}
                onMouseDown={(e) => e.preventDefault()}
                className="relative mt-[28px] w-[227px] h-[90px] bg-[#61d365] hover:bg-[#4dc250] text-[#277018] text-[40px] font-bold leading-[90px] rounded-md shadow-md active:scale-[0.99] transition-transform select-none"
              >
                Akzeptieren
              </button>
            )}

            {/* Countdown oder Verbinde-Status */}
            <div className="mt-[6px] text-[#63d45d] font-bold text-[20px]">
              {connecting ? (
                <span
                  className="inline-flex items-center gap-2 px-3 py-1 rounded-md bg-black/45 backdrop-blur-sm ring-1 ring-white/10"
                  role="status"
                  aria-live="polite"
                >
                  <LoadingSpinner />
                  <span>Verbinde…</span>
                </span>
              ) : (
                <span>{fmt(rest)}</span>
              )}
            </div>
          </div>
        </div>
      )}
    </div>
  )
}
