import { useEffect, useState } from "react"
import { motion } from "framer-motion"
import { Disc3, Pause, Play, Rewind } from "lucide-react"
import type {
  BlindtestAnswer,
  BlindtestMode,
  BlindtestPerPlayerResult,
  BlindtestRevealTruth,
  BlindtestRoundPayload,
  RoomSnapshot,
} from "@nerdware/shared"
import { Button } from "@workspace/ui/components/button"
import { useRoomStore } from "@/store/room"
import { useYoutube, type YoutubeApi } from "@/lib/youtube"
import { Countdown } from "@/components/countdown"
import { Avatar } from "@/components/avatar"

const inputClass =
  "border-input bg-background h-10 w-full rounded-md border px-3 py-2 text-sm focus-visible:ring-ring focus-visible:ring-2 focus-visible:outline-none disabled:opacity-50"

function fmt(s: number): string {
  const m = Math.floor(s / 60)
  const sec = Math.floor(s % 60)
  return `${m}:${sec.toString().padStart(2, "0")}`
}

export function BlindtestView({ snapshot }: { snapshot: RoomSnapshot }) {
  const round = useRoomStore((s) => s.round)
  const reveal = useRoomStore((s) => s.reveal)
  const mediaSync = useRoomStore((s) => s.mediaSync)
  const playerId = useRoomStore((s) => s.playerId)
  const hasVoted = useRoomStore((s) => s.hasVoted)
  const voteBlindtest = useRoomStore((s) => s.voteBlindtest)
  const mediaControl = useRoomStore((s) => s.mediaControl)

  const track = round?.payload as BlindtestRoundPayload | undefined
  const { hostRef, ready, api } = useYoutube(track?.youtubeId ?? "")

  const isDj = !!playerId && round?.djId === playerId
  const truth = reveal ? (reveal.truth as BlindtestRevealTruth) : null
  const showReveal = truth !== null

  // Non-DJ : on suit le DJ via media:sync (avec compensation de latence).
  useEffect(() => {
    if (isDj || !ready || !mediaSync) {
      return
    }
    const elapsed = (Date.now() - mediaSync.atServerTs) / 1000
    if (mediaSync.action === "play") {
      api.seek(mediaSync.positionSec + Math.max(0, elapsed))
      api.play()
    } else if (mediaSync.action === "pause") {
      api.seek(mediaSync.positionSec)
      api.pause()
    } else {
      api.seek(mediaSync.positionSec)
    }
  }, [mediaSync, isDj, ready, api])

  // Au reveal, on coupe le son.
  useEffect(() => {
    if (showReveal && ready) {
      api.pause()
    }
  }, [showReveal, ready, api])

  return (
    <div className="flex w-full max-w-md flex-col gap-5">
      <header className="flex items-center justify-between">
        <span className="text-muted-foreground text-xs uppercase">
          Blindtest {snapshot.currentRound + 1} / {snapshot.totalRounds}
        </span>
        {!showReveal && round && (
          <Countdown
            key={round.endsAt}
            startsAt={round.startsAt}
            endsAt={round.endsAt}
          />
        )}
      </header>

      {/* Cadre 16:9 : le lecteur YouTube est caché derrière le disque pendant la
          manche (son seulement), puis révélé (bannière visible) au reveal. */}
      <div className="bg-card relative aspect-video w-full overflow-hidden rounded-2xl">
        <div
          ref={hostRef}
          className="absolute inset-0 [&>iframe]:absolute [&>iframe]:inset-0 [&>iframe]:size-full"
        />
        {!showReveal && (
          <div className="bg-card absolute inset-0 flex items-center justify-center">
            <motion.div
              animate={{ rotate: 360 }}
              transition={{ duration: 4, repeat: Infinity, ease: "linear" }}
            >
              <Disc3 className="text-muted-foreground size-24" />
            </motion.div>
          </div>
        )}
      </div>

      {isDj && !showReveal && (
        <DjControls ready={ready} api={api} mediaControl={mediaControl} />
      )}

      {!isDj && !showReveal && (
        <VoteForm
          mode={snapshot.settings.blindtestMode}
          snapshot={snapshot}
          playerId={playerId}
          disabled={hasVoted}
          onVote={voteBlindtest}
        />
      )}

      {showReveal && truth && (
        <RevealCard
          truth={truth}
          isDj={isDj}
          result={
            (reveal?.perPlayerResult as BlindtestPerPlayerResult)[playerId ?? ""]
          }
        />
      )}
    </div>
  )
}

function DjControls({
  ready,
  api,
  mediaControl,
}: {
  ready: boolean
  api: YoutubeApi
  mediaControl: (action: "play" | "pause" | "seek", positionSec: number) => void
}) {
  const [pos, setPos] = useState(0)
  const [dur, setDur] = useState(0)

  useEffect(() => {
    if (!ready) {
      return
    }
    const id = setInterval(() => {
      setPos(api.time())
      setDur(api.duration())
    }, 400)
    return () => clearInterval(id)
  }, [ready, api])

  return (
    <div className="flex flex-col gap-3">
      <span className="text-muted-foreground text-center text-xs uppercase">
        Tu es le DJ 🎧 — c'est ton titre, fais-le deviner 🤫
      </span>
      <div className="flex justify-center gap-2">
        <Button
          size="sm"
          disabled={!ready}
          onClick={() => {
            api.play()
            mediaControl("play", api.time())
          }}
        >
          <Play /> Play
        </Button>
        <Button
          size="sm"
          variant="secondary"
          disabled={!ready}
          onClick={() => {
            api.pause()
            mediaControl("pause", api.time())
          }}
        >
          <Pause /> Pause
        </Button>
        <Button
          size="sm"
          variant="secondary"
          disabled={!ready}
          onClick={() => {
            api.seek(0)
            setPos(0)
            mediaControl("seek", 0)
          }}
        >
          <Rewind /> Début
        </Button>
      </div>
      <div className="flex items-center gap-2 text-xs tabular-nums">
        <span className="text-muted-foreground w-9 text-right">{fmt(pos)}</span>
        <input
          type="range"
          min={0}
          max={Math.max(dur, 1)}
          step="any"
          value={Math.min(pos, dur || 0)}
          disabled={!ready}
          onChange={(e) => {
            const v = Number(e.target.value)
            setPos(v)
            api.seek(v)
            mediaControl("seek", v)
          }}
          className="accent-primary flex-1"
        />
        <span className="text-muted-foreground w-9">{fmt(dur)}</span>
      </div>
    </div>
  )
}

function VoteForm({
  mode,
  snapshot,
  playerId,
  disabled,
  onVote,
}: {
  mode: BlindtestMode
  snapshot: RoomSnapshot
  playerId: string | null
  disabled: boolean
  onVote: (answer: BlindtestAnswer) => void
}) {
  const [title, setTitle] = useState("")
  const [artist, setArtist] = useState("")
  const [guessed, setGuessed] = useState<string | null>(null)

  const needsText = mode === "title_artist" || mode === "mixed"
  const needsWho = mode === "who_added" || mode === "mixed"
  const canSubmit =
    !disabled &&
    (!needsText || title.trim().length > 0) &&
    (!needsWho || guessed !== null)

  function submit() {
    const answer: {
      title?: string
      artist?: string
      guessedPlayerId?: string
    } = {}
    if (needsText) {
      answer.title = title.trim()
      answer.artist = artist.trim()
    }
    if (needsWho && guessed) {
      answer.guessedPlayerId = guessed
    }
    onVote(answer as BlindtestAnswer)
  }

  if (disabled) {
    return (
      <p className="text-muted-foreground text-center text-xs">
        Réponse envoyée — en attente des autres
      </p>
    )
  }

  return (
    <div className="flex flex-col gap-3">
      {needsText && (
        <>
          <input
            className={inputClass}
            placeholder="Titre"
            value={title}
            onChange={(e) => setTitle(e.target.value)}
          />
          <input
            className={inputClass}
            placeholder="Artiste"
            value={artist}
            onChange={(e) => setArtist(e.target.value)}
          />
        </>
      )}
      {needsWho && (
        <div className="flex flex-wrap justify-center gap-2">
          {snapshot.players.map((p) => (
            <button
              key={p.id}
              onClick={() => setGuessed(p.id)}
              className={`flex items-center gap-1.5 rounded-full border px-2.5 py-1 text-sm ${
                guessed === p.id
                  ? "border-primary bg-primary/10"
                  : "border-input hover:bg-muted/60"
              }`}
            >
              <Avatar seed={p.name} className="size-5" />
              {p.name}
              {p.id === playerId && (
                <span className="text-muted-foreground">(toi)</span>
              )}
            </button>
          ))}
        </div>
      )}
      <Button disabled={!canSubmit} onClick={submit}>
        Valider ma réponse
      </Button>
    </div>
  )
}

function RevealCard({
  truth,
  isDj,
  result,
}: {
  truth: BlindtestRevealTruth
  isDj: boolean
  result?: BlindtestPerPlayerResult[string]
}) {
  return (
    <div className="flex flex-col items-center gap-2 text-center">
      <p className="font-heading text-lg font-bold text-balance">{truth.title}</p>
      <p className="text-muted-foreground text-sm">{truth.artist}</p>
      <p className="flex items-center gap-2 text-sm">
        <span className="text-muted-foreground">Ajouté par</span>
        <Avatar seed={truth.submittedByName} className="size-6" />
        <span className="font-medium">{truth.submittedByName}</span>
      </p>
      {result && (result.points > 0 || !isDj) && (
        <p
          className={`text-sm font-medium ${result.points > 0 ? "text-green-500" : "text-red-500"}`}
        >
          {result.points > 0
            ? `+${result.points} points ${isDj ? "🤫" : "🎉"}`
            : "Raté 💥"}
        </p>
      )}
    </div>
  )
}
