import { useState } from "react"
import type {
  BlindtestMode,
  GameType,
  RoomSnapshot,
  RoundConfig,
} from "@nerdware/shared"
import { Button } from "@workspace/ui/components/button"
import { useRoomStore } from "@/store/room"
import { Avatar } from "@/components/avatar"

const QUESTION_OPTIONS = [3, 5, 10]
const TRACKS_OPTIONS = [1, 2, 3]
const GAME_TYPES: { value: GameType; label: string }[] = [
  { value: "mixed", label: "Mixte" },
  { value: "quiz", label: "Quiz" },
  { value: "blindtest", label: "Blindtest" },
]
const MODE_LABELS: Record<BlindtestMode, string> = {
  title_artist: "Titre & artiste",
  who_added: "Qui l'a ajouté ?",
  mixed: "Mixte",
}

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 shuffle<T>(items: T[]): T[] {
  const arr = [...items]
  for (let i = arr.length - 1; i > 0; i--) {
    const j = Math.floor(Math.random() * (i + 1))
    ;[arr[i], arr[j]] = [arr[j], arr[i]]
  }
  return arr
}

/** Construit la séquence de manches selon le type de partie. */
function buildRounds(
  gameType: GameType,
  quizCount: number,
  totalTracks: number
): RoundConfig[] {
  if (gameType === "quiz") {
    return Array.from({ length: quizCount }, () => ({ type: "quiz" }))
  }
  if (gameType === "blindtest") {
    return Array.from({ length: totalTracks }, () => ({ type: "blindtest" }))
  }
  // Mixte : ordre mélangé pour qu'on ne sache pas ce qui vient ensuite.
  const rounds: RoundConfig[] = [
    ...Array.from({ length: quizCount }, () => ({ type: "quiz" as const })),
    ...Array.from({ length: totalTracks }, () => ({ type: "blindtest" as const })),
  ]
  return shuffle(rounds)
}

export function LobbyView({ snapshot }: { snapshot: RoomSnapshot }) {
  const playerId = useRoomStore((s) => s.playerId)
  const updateSettings = useRoomStore((s) => s.updateSettings)
  const startGame = useRoomStore((s) => s.startGame)
  const isHost = snapshot.hostId === playerId
  const { gameType, blindtestMode, tracksPerPlayer } = snapshot.settings

  const [count, setCount] = useState(5)
  const [busy, setBusy] = useState(false)
  const [error, setError] = useState<string | null>(null)

  const totalTracks = snapshot.submissions.reduce((n, s) => n + s.count, 0)
  const myCount =
    snapshot.submissions.find((s) => s.playerId === playerId)?.count ?? 0

  // Le blindtest exige au moins 3 joueurs connectés (DJ + 2 devineurs).
  const connectedCount = snapshot.players.filter((p) => p.connected).length
  const blindtestAvailable = connectedCount >= 3
  // Tant que le blindtest est indisponible, on retombe sur du quiz (sans
  // toucher au réglage stocké) : repasse en mixte automatiquement à 3 joueurs.
  const effectiveType: GameType = blindtestAvailable ? gameType : "quiz"
  const showQuiz = effectiveType === "quiz" || effectiveType === "mixed"
  const showBlindtest =
    effectiveType === "blindtest" || effectiveType === "mixed"

  const rounds = buildRounds(effectiveType, showQuiz ? count : 0, totalTracks)
  const canStart = rounds.length > 0

  async function start() {
    setError(null)
    setBusy(true)
    try {
      await startGame(rounds)
    } catch (err) {
      setError((err as { message?: string }).message ?? "Erreur")
    } finally {
      setBusy(false)
    }
  }

  return (
    <div className="flex w-full max-w-md flex-col gap-6">
      <section className="flex flex-col gap-2">
        <h2 className="text-muted-foreground text-sm font-medium">
          Joueurs ({snapshot.players.length})
        </h2>
        <ul className="flex flex-col gap-1">
          {snapshot.players.map((p) => (
            <li
              key={p.id}
              className="bg-muted/40 flex items-center justify-between rounded-md px-3 py-2 text-sm"
            >
              <span
                className={`flex items-center gap-2 ${p.connected ? "" : "opacity-40"}`}
              >
                <Avatar seed={p.name} className="size-11" />
                {p.name}
                {p.id === playerId && (
                  <span className="text-muted-foreground"> (toi)</span>
                )}
              </span>
              <span className="text-muted-foreground text-xs">
                {p.id === snapshot.hostId ? "Hôte" : ""}
                {!p.connected && " · hors ligne"}
              </span>
            </li>
          ))}
        </ul>
      </section>

      {isHost && (
        <div className="flex flex-col gap-1">
          <div className="flex gap-2">
            {GAME_TYPES.map((t) => {
              const needsThree = t.value !== "quiz" && !blindtestAvailable
              return (
                <Button
                  key={t.value}
                  className="flex-1"
                  variant={effectiveType === t.value ? "default" : "secondary"}
                  disabled={needsThree}
                  title={needsThree ? "Blindtest : 3 joueurs minimum" : undefined}
                  onClick={() => updateSettings({ gameType: t.value })}
                >
                  {t.label}
                </Button>
              )
            })}
          </div>
          {!blindtestAvailable && (
            <p className="text-muted-foreground text-center text-xs">
              Le blindtest se débloque à 3 joueurs.
            </p>
          )}
        </div>
      )}

      {isHost && showQuiz && (
        <div className="flex items-center justify-between">
          <span className="text-sm font-medium">Questions de quiz</span>
          <div className="flex gap-1">
            {QUESTION_OPTIONS.map((n) => (
              <Button
                key={n}
                size="sm"
                variant={count === n ? "default" : "secondary"}
                onClick={() => setCount(n)}
              >
                {n}
              </Button>
            ))}
          </div>
        </div>
      )}

      {isHost && showBlindtest && (
        <div className="flex flex-col gap-3">
          <div className="flex flex-col gap-1.5">
            <span className="text-sm font-medium">Mode blindtest</span>
            <div className="flex gap-1">
              {(["title_artist", "who_added", "mixed"] as const).map((m) => (
                <Button
                  key={m}
                  size="sm"
                  className="flex-1"
                  variant={blindtestMode === m ? "default" : "secondary"}
                  onClick={() => updateSettings({ blindtestMode: m })}
                >
                  {MODE_LABELS[m]}
                </Button>
              ))}
            </div>
          </div>
          <div className="flex items-center justify-between">
            <span className="text-sm font-medium">Titres par joueur</span>
            <div className="flex gap-1">
              {TRACKS_OPTIONS.map((n) => (
                <Button
                  key={n}
                  size="sm"
                  variant={tracksPerPlayer === n ? "default" : "secondary"}
                  onClick={() => updateSettings({ tracksPerPlayer: n })}
                >
                  {n}
                </Button>
              ))}
            </div>
          </div>
        </div>
      )}

      {showBlindtest && (
        <TrackSubmission tracksPerPlayer={tracksPerPlayer} myCount={myCount} />
      )}

      {isHost ? (
        <Button disabled={busy || !canStart} onClick={start}>
          {busy ? "Lancement…" : `Lancer (${rounds.length} manches)`}
        </Button>
      ) : (
        <p className="text-muted-foreground text-center text-xs">
          En attente du lancement par l'hôte…
          {showBlindtest && ` (${totalTracks} titres soumis)`}
        </p>
      )}

      {error && <p className="text-destructive text-center text-sm">{error}</p>}
    </div>
  )
}

function TrackSubmission({
  tracksPerPlayer,
  myCount,
}: {
  tracksPerPlayer: number
  myCount: number
}) {
  const submitTrack = useRoomStore((s) => s.submitTrack)
  const [url, setUrl] = useState("")
  const [submitting, setSubmitting] = useState(false)
  const [feedback, setFeedback] = useState<string | null>(null)
  const [accepted, setAccepted] = useState<string[]>([])
  const quotaReached = myCount >= tracksPerPlayer

  async function submit() {
    if (!url.trim()) {
      return
    }
    setSubmitting(true)
    setFeedback(null)
    const res = await submitTrack(url.trim())
    if (res.accepted) {
      setAccepted((a) => [...a, res.title ?? url.trim()])
      setUrl("")
    } else {
      setFeedback(res.reason ?? "Refusé")
    }
    setSubmitting(false)
  }

  return (
    <div className="flex flex-col gap-2">
      <span className="text-sm font-medium">
        Tes titres ({myCount}/{tracksPerPlayer})
      </span>
      <div className="flex gap-2">
        <input
          className={inputClass}
          placeholder="Lien YouTube"
          value={url}
          disabled={quotaReached || submitting}
          onChange={(e) => setUrl(e.target.value)}
          onKeyDown={(e) => e.key === "Enter" && submit()}
        />
        <Button
          variant="secondary"
          disabled={quotaReached || submitting || !url.trim()}
          onClick={submit}
        >
          Ajouter
        </Button>
      </div>
      {feedback && <p className="text-destructive text-xs">{feedback}</p>}
      {accepted.length > 0 && (
        <ul className="text-muted-foreground flex flex-col gap-0.5 text-xs">
          {accepted.map((t, i) => (
            <li key={i} className="truncate">
              ✓ {t}
            </li>
          ))}
        </ul>
      )}
    </div>
  )
}
