import { useState } from "react"
import { useQuery } from "@tanstack/react-query"
import {
  Brain,
  Filter,
  Headphones,
  Image as ImageIcon,
  ListMusic,
  Minus,
  Music,
  Play,
  Plus,
  Shuffle,
  Trash2,
  type LucideIcon,
} from "lucide-react"
import { SiYoutube } from "@icons-pack/react-simple-icons"
import { fetchCategories } from "@/lib/categories"
import { fetchHistory } from "@/lib/history"
import type {
  BlindtestMode,
  GameType,
  MixMode,
  RoomSnapshot,
  RoundConfig,
} from "@nerdware/shared"

const MIX_LABELS: Record<MixMode, string> = {
  quiz: "Quiz",
  image: "Images",
  blindtest: "Blindtest",
}
import { Button } from "@workspace/ui/components/button"
import { useRoomStore } from "@/store/room"
import { Avatar } from "@/components/avatar"

const MAX_TRACKS = 10
const GAME_TYPES: {
  value: GameType
  label: string
  Icon: LucideIcon
  needsThree: boolean
}[] = [
  { value: "mixed", label: "Mixte", Icon: Shuffle, needsThree: false },
  { value: "quiz", label: "Quiz", Icon: Brain, needsThree: false },
  { value: "image", label: "Images", Icon: ImageIcon, needsThree: false },
  { value: "blindtest", label: "Blindtest", Icon: Headphones, needsThree: true },
]
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 Stepper({
  value,
  min = 1,
  max = MAX_TRACKS,
  onChange,
}: {
  value: number
  min?: number
  max?: number
  onChange: (v: number) => void
}) {
  const clamp = (v: number) => Math.max(min, Math.min(max, v))
  return (
    <div className="flex items-center gap-1">
      <Button
        size="icon-sm"
        variant="secondary"
        disabled={value <= min}
        onClick={() => onChange(clamp(value - 1))}
      >
        <Minus />
      </Button>
      <input
        type="number"
        min={min}
        max={max}
        value={value}
        onChange={(e) => {
          const n = parseInt(e.target.value, 10)
          if (!Number.isNaN(n)) {
            onChange(clamp(n))
          }
        }}
        className="border-input bg-background h-8 w-14 rounded-md border text-center text-sm [appearance:textfield] focus-visible:outline-none [&::-webkit-inner-spin-button]:appearance-none"
      />
      <Button
        size="icon-sm"
        variant="secondary"
        disabled={value >= max}
        onClick={() => onChange(clamp(value + 1))}
      >
        <Plus />
      </Button>
    </div>
  )
}

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 (chaque manche quiz porte son sous-pool). */
function buildRounds(opts: {
  quiz: number
  image: number
  tracks: number
  shuffleOrder: boolean
}): RoundConfig[] {
  const rounds: RoundConfig[] = [
    ...Array.from({ length: opts.quiz }, () => ({
      type: "quiz" as const,
      pool: "quiz" as const,
    })),
    ...Array.from({ length: opts.image }, () => ({
      type: "quiz" as const,
      pool: "image" as const,
    })),
    ...Array.from({ length: opts.tracks }, () => ({ type: "blindtest" as const })),
  ]
  return opts.shuffleOrder ? shuffle(rounds) : 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, mixedModes, blindtestMode, tracksPerPlayer, categories } =
    snapshot.settings
  const allCategories =
    useQuery({ queryKey: ["categories"], queryFn: fetchCategories }).data ?? []
  const history =
    useQuery({
      queryKey: ["history", snapshot.code],
      queryFn: () => fetchHistory(snapshot.code),
    }).data ?? []

  const [quizCount, setQuizCount] = useState(5)
  const [imageCount, setImageCount] = 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
  // Seul le blindtest "seul" retombe sur du quiz à <3 ; le mixte reste mixte
  // (son sous-mode blindtest est juste désactivé tant qu'on n'est pas 3).
  const effectiveType: GameType =
    gameType === "blindtest" && !blindtestAvailable ? "quiz" : gameType
  const isMixed = effectiveType === "mixed"

  // Sous-modes effectivement actifs (un réglage par sous-mode).
  const showQuiz =
    effectiveType === "quiz" || (isMixed && mixedModes.includes("quiz"))
  const showImage =
    effectiveType === "image" || (isMixed && mixedModes.includes("image"))
  const showBlindtest =
    effectiveType === "blindtest" ||
    (isMixed && mixedModes.includes("blindtest") && blindtestAvailable)

  const rounds = buildRounds({
    quiz: showQuiz ? quizCount : 0,
    image: showImage ? imageCount : 0,
    tracks: showBlindtest ? totalTracks : 0,
    shuffleOrder: isMixed,
  })
  // Blindtest : tout le monde doit avoir soumis son quota de titres.
  const allSubmitted =
    !showBlindtest ||
    (snapshot.submissions.length > 0 &&
      snapshot.submissions.every((s) => s.count >= tracksPerPlayer))
  const canStart = rounds.length > 0 && allSubmitted

  function toggleMix(mode: MixMode) {
    const set = new Set(mixedModes)
    if (set.has(mode)) {
      set.delete(mode)
    } else {
      set.add(mode)
    }
    updateSettings({ mixedModes: [...set] })
  }

  function toggleCategory(name: string) {
    const set = new Set(categories)
    if (set.has(name)) {
      set.delete(name)
    } else {
      set.add(name)
    }
    updateSettings({ categories: [...set] })
  }

  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="grid w-full gap-6 md:grid-cols-2 md:items-start">
      <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>

      <div className="flex flex-col gap-6">
      {isHost && (
        <section className="flex flex-col gap-4 rounded-xl border p-4">
          <h2 className="text-muted-foreground text-xs font-medium uppercase tracking-wide">
            Réglages de la partie
          </h2>

          {/* Mode de jeu */}
          <div className="flex flex-col gap-2">
            <span className="text-sm font-medium">Mode de jeu</span>
            <div className="grid grid-cols-4 gap-2">
              {GAME_TYPES.map(({ value, label, Icon, needsThree }) => {
                const locked = needsThree && !blindtestAvailable
                const active = effectiveType === value
                return (
                  <button
                    key={value}
                    disabled={locked}
                    title={locked ? "3 joueurs minimum" : undefined}
                    onClick={() => updateSettings({ gameType: value })}
                    className={`flex flex-col items-center gap-1.5 rounded-lg border p-2.5 text-xs font-medium transition-colors disabled:opacity-40 ${
                      active
                        ? "border-primary bg-primary/10"
                        : "border-input hover:bg-muted/60"
                    }`}
                  >
                    <Icon className="size-5" />
                    {label}
                  </button>
                )
              })}
            </div>
            {!blindtestAvailable && (
              <p className="text-muted-foreground text-xs">
                Le blindtest se débloque à 3 joueurs.
              </p>
            )}
          </div>

          {/* Sous-modes du mixte (toggles) */}
          {isMixed && (
            <div className="flex flex-col gap-2">
              <span className="text-sm font-medium">Sous-modes inclus</span>
              <div className="flex gap-2">
                {(["quiz", "image", "blindtest"] as const).map((m) => {
                  const locked = m === "blindtest" && !blindtestAvailable
                  const on = mixedModes.includes(m) && !locked
                  return (
                    <button
                      key={m}
                      disabled={locked}
                      title={locked ? "3 joueurs minimum" : undefined}
                      onClick={() => toggleMix(m)}
                      className={`flex-1 rounded-lg border px-2 py-1.5 text-xs font-medium transition-colors disabled:opacity-40 ${
                        on
                          ? "border-primary bg-primary/10"
                          : "border-input hover:bg-muted/60"
                      }`}
                    >
                      {MIX_LABELS[m]}
                    </button>
                  )
                })}
              </div>
            </div>
          )}

          {/* Nombre de questions de quiz */}
          {showQuiz && (
            <div className="flex items-center justify-between">
              <span className="flex items-center gap-1.5 text-sm font-medium">
                <Brain className="size-4" /> Questions de quiz
              </span>
              <Stepper value={quizCount} min={1} max={20} onChange={setQuizCount} />
            </div>
          )}

          {/* Nombre d'images */}
          {showImage && (
            <div className="flex flex-col gap-1">
              <div className="flex items-center justify-between">
                <span className="flex items-center gap-1.5 text-sm font-medium">
                  <ImageIcon className="size-4" /> Images à deviner
                </span>
                <Stepper
                  value={imageCount}
                  min={1}
                  max={20}
                  onChange={setImageCount}
                />
              </div>
              <p className="text-muted-foreground text-xs">
                Nécessite des questions « Image » créées dans le back-office.
              </p>
            </div>
          )}

          {/* Filtre de catégories (quiz / images) */}
          {(showQuiz || showImage) && allCategories.length > 0 && (
            <div className="flex flex-col gap-1.5">
              <span className="flex items-center gap-1.5 text-sm font-medium">
                <Filter className="size-4" /> Catégories
              </span>
              <div className="flex flex-wrap gap-1.5">
                <button
                  onClick={() => updateSettings({ categories: [] })}
                  className={`rounded-full border px-2.5 py-1 text-xs transition-colors ${
                    categories.length === 0
                      ? "border-primary bg-primary/10"
                      : "border-input hover:bg-muted/60"
                  }`}
                >
                  Toutes
                </button>
                {allCategories.map((c) => (
                  <button
                    key={c}
                    onClick={() => toggleCategory(c)}
                    className={`rounded-full border px-2.5 py-1 text-xs transition-colors ${
                      categories.includes(c)
                        ? "border-primary bg-primary/10"
                        : "border-input hover:bg-muted/60"
                    }`}
                  >
                    {c}
                  </button>
                ))}
              </div>
            </div>
          )}

          {/* Réglages blindtest */}
          {showBlindtest && (
            <div className="flex flex-col gap-3 border-t pt-3">
              <div className="flex flex-col gap-1.5">
                <span className="flex items-center gap-1.5 text-sm font-medium">
                  <Music className="size-4" /> 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="flex items-center gap-1.5 text-sm font-medium">
                  <ListMusic className="size-4" /> Titres par joueur
                </span>
                <Stepper
                  value={tracksPerPlayer}
                  onChange={(v) => updateSettings({ tracksPerPlayer: v })}
                />
              </div>
            </div>
          )}
        </section>
      )}

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

      {isHost ? (
        <div className="flex flex-col gap-1">
          <Button disabled={busy || !canStart} onClick={start}>
            <Play /> {busy ? "Lancement…" : `Lancer (${rounds.length} manches)`}
          </Button>
          {showBlindtest && !allSubmitted && (
            <p className="text-muted-foreground text-center text-xs">
              En attente que tout le monde ait soumis ses {tracksPerPlayer}{" "}
              titre(s).
            </p>
          )}
        </div>
      ) : (
        <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>}

      {history.length > 0 && (
        <details className="rounded-xl border text-left">
          <summary className="text-muted-foreground cursor-pointer p-3 text-sm font-medium select-none">
            Parties précédentes ({history.length})
          </summary>
          <ul className="flex flex-col gap-2 p-3 pt-0">
            {history.map((g) => {
              const top = [...g.results].sort((a, b) => b.score - a.score)
              return (
                <li key={g.id} className="bg-muted/40 rounded-lg p-2 text-xs">
                  <p className="text-muted-foreground text-[10px] uppercase">
                    {new Date(g.playedAt).toLocaleString("fr-FR", {
                      dateStyle: "short",
                      timeStyle: "short",
                    })}
                    {" · "}
                    {g.modes.join(", ")}
                  </p>
                  <p>
                    🏆 {top[0]?.name ?? "?"}
                    <span className="text-muted-foreground">
                      {" "}
                      — {top.map((r) => `${r.name} ${r.score}`).join(" · ")}
                    </span>
                  </p>
                </li>
              )
            })}
          </ul>
        </details>
      )}
      </div>
    </div>
  )
}

interface MyTrack {
  trackId: string
  title: string
  youtubeId: string
}

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

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

  async function remove(trackId: string) {
    const ok = await removeTrack(trackId)
    if (ok) {
      setTracks((t) => t.filter((x) => x.trackId !== trackId))
    }
  }

  return (
    <div className="flex flex-col gap-2">
      <span className="text-sm font-medium">
        Tes titres ({myCount}/{tracksPerPlayer})
      </span>

      {tracks.length > 0 && (
        <ul className="flex flex-col gap-2">
          {tracks.map((t) => (
            <li
              key={t.trackId}
              className="bg-muted/40 flex items-center gap-3 rounded-lg p-2"
            >
              <img
                src={`https://img.youtube.com/vi/${t.youtubeId}/mqdefault.jpg`}
                alt=""
                className="h-10 w-16 shrink-0 rounded object-cover"
              />
              <span className="line-clamp-2 flex-1 text-xs">{t.title}</span>
              <a
                href={`https://www.youtube.com/watch?v=${t.youtubeId}`}
                target="_blank"
                rel="noreferrer"
                title="Ouvrir sur YouTube"
              >
                <Button size="icon-sm" variant="secondary">
                  <SiYoutube color="default" />
                </Button>
              </a>
              <Button
                size="icon-sm"
                variant="secondary"
                onClick={() => remove(t.trackId)}
                title="Supprimer"
              >
                <Trash2 />
              </Button>
            </li>
          ))}
        </ul>
      )}

      {!quotaReached && (
        <div className="flex gap-2">
          <input
            className={inputClass}
            placeholder="Lien YouTube"
            value={url}
            disabled={submitting}
            onChange={(e) => setUrl(e.target.value)}
            onKeyDown={(e) => e.key === "Enter" && submit()}
          />
          <Button
            variant="secondary"
            disabled={submitting || !url.trim()}
            onClick={submit}
          >
            <SiYoutube color="default" /> Ajouter
          </Button>
        </div>
      )}
      {feedback && <p className="text-destructive text-xs">{feedback}</p>}
    </div>
  )
}
