"use client"

import type React from "react"
import { useEffect, useMemo, useState } from "react"
import Link from "next/link"
import {
  ArrowLeft,
  ArrowLeftRight,
  Check,
  Copy,
  Flag,
  KeyRound,
  MessageCircle,
  MoreVertical,
  Pencil,
  Plus,
  Star,
  Trash2,
  UserPlus,
  Users,
  X,
} from "lucide-react"
import { Button } from "@/components/ui/button"
import { Input } from "@/components/ui/input"
import { Label } from "@/components/ui/label"
import {
  DropdownMenu,
  DropdownMenuContent,
  DropdownMenuItem,
  DropdownMenuTrigger,
} from "@/components/ui/dropdown-menu"
import { TournamentStatusPicker, type TournamentStatus } from "@/components/tournament-status-badge"
import { cn } from "@/lib/utils"

// --- Types (matcher API-kontrakten i app/routers/tournaments.py/players.py) -

type ApiPlayer = {
  id: string
  display_name: string
  handicap_index: number | null
  gender: "m" | "f" | "x" | null
}

type ApiRosterEntry = {
  id: string
  player_id: string
  display_name: string
  handicap_index_snapshot: number | null
  is_captain: boolean
}

type Team = {
  id: string
  name: string
  color: string
  roster: ApiRosterEntry[]
}

// Team colors er DATA brukt på scorekort senere -- bevisst atskilt fra
// app-ens merkevare-grønn/oransje.
const TEAM_COLORS: { value: string; label: string }[] = [
  { value: "#2563eb", label: "Blå" },
  { value: "#dc2626", label: "Rød" },
  { value: "#7c3aed", label: "Lilla" },
  { value: "#0891b2", label: "Turkis" },
  { value: "#db2777", label: "Rosa" },
  { value: "#475569", label: "Skifer" },
]

// --- Component -------------------------------------------------------------

export function TournamentDetail({
  organizationId,
  tournamentId,
  tournamentName,
}: {
  organizationId: string
  tournamentId: string
  tournamentName: string
}) {
  const [teams, setTeams] = useState<[Team | null, Team | null]>([null, null])
  const [pool, setPool] = useState<ApiPlayer[]>([])
  const [joinCode, setJoinCode] = useState<string | null>(null)
  const [status, setStatus] = useState<TournamentStatus | null>(null)
  const [loading, setLoading] = useState(true)
  const [error, setError] = useState<string | null>(null)

  useEffect(() => {
    let cancelled = false
    async function load() {
      try {
        const [teamsRes, poolRes, tournamentsRes] = await Promise.all([
          fetch(`/orgs/${organizationId}/tournaments/${tournamentId}/teams`, {
            credentials: "include",
          }),
          fetch(`/orgs/${organizationId}/players`, { credentials: "include" }),
          fetch(`/orgs/${organizationId}/tournaments`, { credentials: "include" }),
        ])
        if (!teamsRes.ok || !poolRes.ok) throw new Error("load failed")
        const teamsData: { id: string; name: string; color: string | null }[] =
          await teamsRes.json()
        const poolData: ApiPlayer[] = await poolRes.json()
        // Ingen enkelt-turnering-GET finnes ennå -- listen bærer allerede
        // join_code (ADR-020), så vi finner raden herfra i stedet for å
        // legge til et nytt endepunkt kun for dette.
        if (tournamentsRes.ok) {
          const tournamentsData: { id: string; join_code: string; status: TournamentStatus }[] =
            await tournamentsRes.json()
          const mine = tournamentsData.find((t) => t.id === tournamentId)
          if (mine) {
            setJoinCode(mine.join_code)
            setStatus(mine.status)
          }
        }

        const withRosters = await Promise.all(
          teamsData.map(async (t) => {
            const rosterRes = await fetch(`/orgs/${organizationId}/teams/${t.id}/roster`, {
              credentials: "include",
            })
            const roster: ApiRosterEntry[] = rosterRes.ok ? await rosterRes.json() : []
            return { id: t.id, name: t.name, color: t.color ?? TEAM_COLORS[0].value, roster }
          }),
        )
        if (cancelled) return
        setTeams([withRosters[0] ?? null, withRosters[1] ?? null])
        setPool(poolData)
      } catch {
        if (!cancelled) setError("Klarte ikke å laste lag og spillere. Prøv å laste siden på nytt.")
      } finally {
        if (!cancelled) setLoading(false)
      }
    }
    void load()
    return () => {
      cancelled = true
    }
  }, [organizationId, tournamentId])

  async function createTeam(slot: 0 | 1, name: string, color: string) {
    setError(null)
    try {
      const res = await fetch(`/orgs/${organizationId}/tournaments/${tournamentId}/teams`, {
        method: "POST",
        headers: { "Content-Type": "application/json" },
        credentials: "include",
        body: JSON.stringify({ name, color }),
      })
      if (!res.ok) throw new Error(`create team: ${res.status}`)
      const created: { id: string; name: string; color: string | null } = await res.json()
      setTeams((prev) => {
        const next: [Team | null, Team | null] = [prev[0], prev[1]]
        next[slot] = { id: created.id, name: created.name, color: created.color ?? color, roster: [] }
        return next
      })
    } catch {
      setError("Klarte ikke å opprette laget. Prøv igjen.")
    }
  }

  async function addExistingPlayer(teamId: string, playerId: string) {
    setError(null)
    try {
      const res = await fetch(`/orgs/${organizationId}/teams/${teamId}/roster`, {
        method: "POST",
        headers: { "Content-Type": "application/json" },
        credentials: "include",
        body: JSON.stringify({ player_id: playerId, is_captain: false }),
      })
      if (!res.ok) throw new Error(`add roster: ${res.status}`)
      const entry: ApiRosterEntry = await res.json()
      setTeams((prev) =>
        prev.map((t) => (t && t.id === teamId ? { ...t, roster: [...t.roster, entry] } : t)) as [
          Team | null,
          Team | null,
        ],
      )
    } catch {
      setError("Klarte ikke å legge til spilleren. Prøv igjen.")
    }
  }

  async function addNewPlayer(teamId: string, name: string, handicap?: number) {
    setError(null)
    try {
      const playerRes = await fetch(`/orgs/${organizationId}/players`, {
        method: "POST",
        headers: { "Content-Type": "application/json" },
        credentials: "include",
        body: JSON.stringify({ display_name: name, handicap_index: handicap ?? null }),
      })
      if (!playerRes.ok) throw new Error(`create player: ${playerRes.status}`)
      const player: ApiPlayer = await playerRes.json()
      setPool((prev) => [...prev, player])
      await addExistingPlayer(teamId, player.id)
    } catch {
      setError("Klarte ikke å opprette spilleren. Prøv igjen.")
    }
  }

  // Redigerer spillerpoolen (`player`), IKKE et lags frosne
  // handicap_index_snapshot (ADR-007) -- se PlayerUpdate sin docstring i
  // app/routers/players.py. Slår derfor ikke automatisk inn på tallet som
  // allerede vises på et lag denne spilleren er rostret på.
  async function updatePlayer(
    playerId: string,
    updates: { display_name?: string; handicap_index?: number | null; gender?: string | null },
  ) {
    setError(null)
    try {
      const res = await fetch(`/orgs/${organizationId}/players/${playerId}`, {
        method: "PATCH",
        headers: { "Content-Type": "application/json" },
        credentials: "include",
        body: JSON.stringify(updates),
      })
      if (!res.ok) throw new Error(`update player: ${res.status}`)
      const updated: ApiPlayer = await res.json()
      setPool((prev) => prev.map((p) => (p.id === updated.id ? updated : p)))
    } catch {
      setError("Klarte ikke å oppdatere spilleren. Prøv igjen.")
    }
  }

  async function toggleCaptain(teamId: string, rosterId: string, current: boolean) {
    setError(null)
    try {
      const res = await fetch(`/orgs/${organizationId}/teams/${teamId}/roster/${rosterId}`, {
        method: "PATCH",
        headers: { "Content-Type": "application/json" },
        credentials: "include",
        body: JSON.stringify({ is_captain: !current }),
      })
      if (!res.ok) throw new Error(`toggle captain: ${res.status}`)
      const updated: ApiRosterEntry = await res.json()
      setTeams((prev) =>
        prev.map((t) =>
          t && t.id === teamId
            ? { ...t, roster: t.roster.map((r) => (r.id === updated.id ? updated : r)) }
            : t,
        ) as [Team | null, Team | null],
      )
    } catch {
      setError("Klarte ikke å endre kaptein. Prøv igjen.")
    }
  }

  async function removePlayer(teamId: string, rosterId: string) {
    setError(null)
    try {
      const res = await fetch(`/orgs/${organizationId}/teams/${teamId}/roster/${rosterId}`, {
        method: "DELETE",
        credentials: "include",
      })
      if (!res.ok && res.status !== 204) throw new Error(`remove roster: ${res.status}`)
      setTeams((prev) =>
        prev.map((t) =>
          t && t.id === teamId ? { ...t, roster: t.roster.filter((r) => r.id !== rosterId) } : t,
        ) as [Team | null, Team | null],
      )
    } catch {
      setError("Klarte ikke å fjerne spilleren. Prøv igjen.")
    }
  }

  async function movePlayer(teamId: string, rosterId: string, targetTeamId: string) {
    setError(null)
    try {
      const res = await fetch(
        `/orgs/${organizationId}/teams/${teamId}/roster/${rosterId}/move`,
        {
          method: "POST",
          headers: { "Content-Type": "application/json" },
          credentials: "include",
          body: JSON.stringify({ target_team_id: targetTeamId }),
        },
      )
      if (!res.ok) {
        const body = await res.json().catch(() => null)
        throw new Error(body?.detail?.message ?? `move roster: ${res.status}`)
      }
      const moved: ApiRosterEntry = await res.json()
      setTeams(
        (prev) =>
          prev.map((t) => {
            if (!t) return t
            if (t.id === teamId) return { ...t, roster: t.roster.filter((r) => r.id !== rosterId) }
            if (t.id === targetTeamId) return { ...t, roster: [...t.roster, moved] }
            return t
          }) as [Team | null, Team | null],
      )
    } catch (err) {
      setError(err instanceof Error ? err.message : "Klarte ikke å flytte spilleren. Prøv igjen.")
    }
  }

  async function updateStatus(newStatus: TournamentStatus) {
    setError(null)
    const previous = status
    setStatus(newStatus) // optimistisk -- rulles tilbake under ved feil
    try {
      const res = await fetch(`/orgs/${organizationId}/tournaments/${tournamentId}`, {
        method: "PATCH",
        headers: { "Content-Type": "application/json" },
        credentials: "include",
        body: JSON.stringify({ status: newStatus }),
      })
      if (!res.ok) throw new Error(`update status: ${res.status}`)
    } catch {
      setStatus(previous)
      setError("Klarte ikke å endre turnering-status. Prøv igjen.")
    }
  }

  // Walkover/konsesjon på turnering-nivå (ADR-024): gir opp ALLE
  // ikke-avgjorte matcher laget har i turneringen, i én operasjon. Kun
  // kaptein for laget som gir seg (eller org-admin) får lov -- backend
  // håndhever dette, en 403 vises bare som vanlig feiltekst.
  async function concedeTournament(teamId: string): Promise<string | null> {
    setError(null)
    try {
      const res = await fetch(`/orgs/${organizationId}/tournaments/${tournamentId}/concede`, {
        method: "POST",
        headers: { "Content-Type": "application/json" },
        credentials: "include",
        body: JSON.stringify({ conceding_team_id: teamId }),
      })
      if (!res.ok) {
        const body = await res.json().catch(() => null)
        const message: string = body?.detail?.message ?? "Klarte ikke å gi opp turneringen."
        setError(message)
        return message
      }
      return null
    } catch {
      const message = "Klarte ikke å gi opp turneringen."
      setError(message)
      return message
    }
  }

  // Hvilket lag er en gitt spiller (fra pool) allerede rostret på, om noen?
  function findPlayerTeam(playerId: string): Team | null {
    for (const t of teams) {
      if (t && t.roster.some((r) => r.player_id === playerId)) return t
    }
    return null
  }

  return (
    <div className="flex min-h-[100dvh] flex-col bg-background">
      <header className="sticky top-0 z-10 border-b border-border bg-background/80 backdrop-blur">
        <div className="mx-auto flex w-full max-w-4xl items-center gap-3 px-5 py-4">
          <Link
            href="/dashboard"
            aria-label="Tilbake til dashbord"
            className="flex size-10 shrink-0 items-center justify-center rounded-xl border border-border bg-card text-muted-foreground transition-colors hover:bg-accent/50 hover:text-foreground"
          >
            <ArrowLeft aria-hidden="true" className="size-5" />
          </Link>
          <div className="flex min-w-0 flex-1 flex-col">
            <span className="text-xs font-semibold uppercase tracking-wide text-muted-foreground">
              Turnering
            </span>
            <h1 className="truncate text-xl font-extrabold tracking-tight text-foreground">
              {tournamentName}
            </h1>
          </div>
          {status && <TournamentStatusPicker status={status} onChange={updateStatus} />}
          {joinCode && <JoinCodeChip code={joinCode} />}
        </div>

        <nav className="mx-auto flex w-full max-w-4xl items-center gap-2 px-5 pb-3" aria-label="Turneringsseksjoner">
          <span
            aria-current="page"
            className="rounded-full bg-primary px-4 py-2 text-sm font-bold text-primary-foreground"
          >
            Lag og spillere
          </span>
          <Link
            href={`/tournaments/${tournamentId}/program?org=${organizationId}&name=${encodeURIComponent(tournamentName)}`}
            className="rounded-full px-4 py-2 text-sm font-semibold text-muted-foreground transition-colors hover:bg-accent/60 hover:text-foreground"
          >
            Program
          </Link>
          <Link
            href={`/tournaments/${tournamentId}/leaderboard?org=${organizationId}&name=${encodeURIComponent(tournamentName)}`}
            className="rounded-full px-4 py-2 text-sm font-semibold text-muted-foreground transition-colors hover:bg-accent/60 hover:text-foreground"
          >
            Leaderboard
          </Link>
        </nav>
      </header>

      <main className="mx-auto w-full max-w-4xl flex-1 px-5 py-6 sm:py-8">
        <div className="mb-5 flex flex-col gap-1">
          <h2 className="text-base font-bold text-foreground">Lag og spillere</h2>
          <p className="text-sm leading-relaxed text-muted-foreground text-pretty">
            Ryder Cup-format: nøyaktig to lag. Sett opp begge lagene og fyll troppene før
            turneringen kan starte.
          </p>
        </div>

        {error && (
          <p role="alert" className="mb-4 text-sm font-medium text-destructive">
            {error}
          </p>
        )}

        {loading ? (
          <div className="flex justify-center py-16">
            <div
              aria-hidden="true"
              className="size-10 animate-spin rounded-full border-4 border-primary/20 border-t-primary"
            />
          </div>
        ) : (
          <div className="grid gap-4 md:grid-cols-2">
            {([0, 1] as const).map((slot) => {
              const team = teams[slot]
              if (team) {
                const otherTeam = teams[slot === 0 ? 1 : 0]
                return (
                  <TeamPanel
                    key={team.id}
                    team={team}
                    otherTeam={otherTeam}
                    pool={pool}
                    chatHref={`/tournaments/${tournamentId}/teams/${team.id}/chat?org=${organizationId}&name=${encodeURIComponent(tournamentName)}&team=${encodeURIComponent(team.name)}`}
                    findPlayerTeam={findPlayerTeam}
                    onToggleCaptain={toggleCaptain}
                    onRemovePlayer={removePlayer}
                    onMovePlayer={movePlayer}
                    onAddExisting={addExistingPlayer}
                    onAddNew={addNewPlayer}
                    onUpdatePlayer={updatePlayer}
                    onConcedeTournament={concedeTournament}
                  />
                )
              }
              return <CreateTeamCard key={`slot-${slot}`} slot={slot} onCreate={createTeam} />
            })}
          </div>
        )}
      </main>
    </div>
  )
}

// --- Invitasjonskode-chip (ADR-020) -----------------------------------------
// Vises til organisator slik at koden kan gis muntlig/på en lapp til
// spillere som ellers ikke ville funnet turneringen. Overstyrer
// tournament.visibility når den brukes -- se login-skjermets kode-felt.

function JoinCodeChip({ code }: { code: string }) {
  const [copied, setCopied] = useState(false)

  async function handleCopy() {
    try {
      await navigator.clipboard.writeText(code)
      setCopied(true)
      setTimeout(() => setCopied(false), 2000)
    } catch {
      // Utilgjengelig clipboard-API (f.eks. usikker kontekst) -- koden er
      // uansett synlig i chipen, bare uten kopier-snarveien.
    }
  }

  return (
    <button
      type="button"
      onClick={handleCopy}
      title="Del denne koden med spillere som skal finne turneringen uten lenke"
      className="flex shrink-0 items-center gap-1.5 rounded-xl border border-border bg-secondary/60 px-3 py-2 text-sm font-bold tracking-widest text-foreground transition-colors hover:bg-secondary"
    >
      <KeyRound aria-hidden="true" className="size-3.5 text-muted-foreground" />
      {code}
      {copied ? (
        <Check aria-hidden="true" className="size-3.5 text-primary" />
      ) : (
        <Copy aria-hidden="true" className="size-3.5 text-muted-foreground" />
      )}
    </button>
  )
}

// --- Create team (State A) -------------------------------------------------

function CreateTeamCard({
  slot,
  onCreate,
}: {
  slot: 0 | 1
  onCreate: (slot: 0 | 1, name: string, color: string) => void
}) {
  const [name, setName] = useState("")
  const [color, setColor] = useState(TEAM_COLORS[slot === 0 ? 0 : 1].value)
  const valid = name.trim().length >= 2

  function handleSubmit(e: React.FormEvent) {
    e.preventDefault()
    if (!valid) return
    onCreate(slot, name.trim(), color)
  }

  return (
    <form
      onSubmit={handleSubmit}
      className="flex flex-col gap-5 rounded-3xl border border-dashed border-border bg-card/50 p-5 sm:p-6"
    >
      <div className="flex items-center gap-3">
        <div className="flex size-11 items-center justify-center rounded-xl bg-muted">
          <Users aria-hidden="true" className="size-5 text-muted-foreground" />
        </div>
        <div className="flex flex-col">
          <span className="text-xs font-semibold uppercase tracking-wide text-muted-foreground">
            Lag {slot + 1}
          </span>
          <span className="text-base font-bold text-foreground">Opprett lag</span>
        </div>
      </div>

      <div className="flex flex-col gap-2">
        <Label htmlFor={`team-name-${slot}`} className="text-sm font-semibold">
          Lagnavn
        </Label>
        <Input
          id={`team-name-${slot}`}
          placeholder="F.eks. Lag Birdie"
          value={name}
          onChange={(e) => setName(e.target.value)}
          className="h-12 rounded-2xl text-base"
        />
      </div>

      <div className="flex flex-col gap-2">
        <Label className="text-sm font-semibold">Lagfarge</Label>
        <div className="flex flex-wrap gap-2.5">
          {TEAM_COLORS.map((c) => {
            const selected = c.value === color
            return (
              <button
                key={c.value}
                type="button"
                onClick={() => setColor(c.value)}
                aria-label={c.label}
                aria-pressed={selected}
                title={c.label}
                className={cn(
                  "flex size-9 items-center justify-center rounded-full ring-2 ring-offset-2 ring-offset-card transition-transform hover:scale-105",
                  selected ? "ring-foreground" : "ring-transparent",
                )}
                style={{ backgroundColor: c.value }}
              >
                {selected && <Check aria-hidden="true" className="size-4 text-white" />}
              </button>
            )
          })}
        </div>
      </div>

      <Button
        type="submit"
        disabled={!valid}
        className="h-12 rounded-2xl text-base font-bold shadow-sm"
      >
        <Plus aria-hidden="true" className="size-5" />
        Opprett lag
      </Button>
    </form>
  )
}

// --- Team panel with roster (State B) --------------------------------------

function TeamPanel({
  team,
  otherTeam,
  pool,
  chatHref,
  findPlayerTeam,
  onToggleCaptain,
  onRemovePlayer,
  onMovePlayer,
  onAddExisting,
  onAddNew,
  onUpdatePlayer,
  onConcedeTournament,
}: {
  team: Team
  otherTeam: Team | null
  pool: ApiPlayer[]
  chatHref: string
  findPlayerTeam: (playerId: string) => Team | null
  onToggleCaptain: (teamId: string, rosterId: string, current: boolean) => void
  onRemovePlayer: (teamId: string, rosterId: string) => void
  onMovePlayer: (teamId: string, rosterId: string, targetTeamId: string) => void
  onAddExisting: (teamId: string, playerId: string) => void
  onAddNew: (teamId: string, name: string, handicap?: number) => void
  onUpdatePlayer: (
    playerId: string,
    updates: { display_name?: string; handicap_index?: number | null; gender?: string | null },
  ) => void
  onConcedeTournament: (teamId: string) => Promise<string | null>
}) {
  const [confirmingId, setConfirmingId] = useState<string | null>(null)
  const [editingPlayerId, setEditingPlayerId] = useState<string | null>(null)
  const [confirmingGiveUp, setConfirmingGiveUp] = useState(false)
  const [giveUpError, setGiveUpError] = useState<string | null>(null)
  const [givingUp, setGivingUp] = useState(false)

  async function handleGiveUp() {
    setGivingUp(true)
    const message = await onConcedeTournament(team.id)
    setGivingUp(false)
    if (message) {
      setGiveUpError(message)
    } else {
      setConfirmingGiveUp(false)
    }
  }

  return (
    <section
      className="flex flex-col overflow-hidden rounded-3xl border border-border bg-card shadow-sm shadow-black/5"
      style={{ borderLeftWidth: 6, borderLeftColor: team.color }}
      aria-label={`Lag ${team.name}`}
    >
      <div className="flex items-center gap-3 border-b border-border px-5 py-4">
        <span
          aria-hidden="true"
          className="size-4 shrink-0 rounded-full"
          style={{ backgroundColor: team.color }}
        />
        <div className="flex min-w-0 flex-1 flex-col">
          <h3 className="truncate text-lg font-extrabold tracking-tight text-foreground">
            {team.name}
          </h3>
          <span className="text-sm text-muted-foreground">
            {team.roster.length} {team.roster.length === 1 ? "spiller" : "spillere"}
          </span>
        </div>
        <Link
          href={chatHref}
          title="Privat lagchat -- kun for spillere rostret på laget"
          className="flex size-9 shrink-0 items-center justify-center rounded-xl border border-border text-muted-foreground transition-colors hover:bg-accent/60 hover:text-foreground"
        >
          <MessageCircle aria-hidden="true" className="size-4" />
        </Link>
      </div>

      <ul className="flex flex-col">
        {team.roster.length === 0 && (
          <li className="px-5 py-6 text-center text-sm text-muted-foreground">
            Ingen spillere ennå. Legg til nedenfor.
          </li>
        )}
        {team.roster.map((entry) => {
          const confirming = confirmingId === entry.id
          const editing = editingPlayerId === entry.player_id

          if (editing) {
            const player = pool.find((p) => p.id === entry.player_id)
            return (
              <li key={entry.id} className="border-b border-border px-5 py-3 last:border-b-0">
                <EditPlayerForm
                  displayName={player?.display_name ?? entry.display_name}
                  handicapIndex={player?.handicap_index ?? null}
                  gender={player?.gender ?? null}
                  onSave={(updates) => {
                    onUpdatePlayer(entry.player_id, updates)
                    setEditingPlayerId(null)
                  }}
                  onCancel={() => setEditingPlayerId(null)}
                />
              </li>
            )
          }

          if (confirming) {
            return (
              <li
                key={entry.id}
                className="flex items-center justify-between gap-3 border-b border-border bg-destructive/5 px-5 py-3 last:border-b-0"
              >
                <span className="text-sm text-foreground text-pretty">
                  Fjern <span className="font-semibold">{entry.display_name}</span> fra laget?
                </span>
                <div className="flex shrink-0 items-center gap-2">
                  <Button
                    type="button"
                    size="sm"
                    variant="destructive"
                    className="h-9 rounded-xl"
                    onClick={() => {
                      onRemovePlayer(team.id, entry.id)
                      setConfirmingId(null)
                    }}
                  >
                    Fjern
                  </Button>
                  <Button
                    type="button"
                    size="sm"
                    variant="ghost"
                    className="h-9 rounded-xl"
                    onClick={() => setConfirmingId(null)}
                  >
                    Avbryt
                  </Button>
                </div>
              </li>
            )
          }

          return (
            <li
              key={entry.id}
              className="flex items-center gap-3 border-b border-border px-5 py-3 last:border-b-0"
            >
              <div className="flex min-w-0 flex-1 items-center gap-2">
                <span className="truncate font-semibold text-foreground">
                  {entry.display_name}
                </span>
                {entry.is_captain && (
                  <span className="inline-flex shrink-0 items-center gap-1 rounded-full bg-primary/15 px-2 py-0.5 text-xs font-semibold text-foreground">
                    <Star aria-hidden="true" className="size-3 fill-primary text-primary" />
                    Kaptein
                  </span>
                )}
              </div>
              <span className="shrink-0 tabular-nums text-sm font-medium text-muted-foreground">
                {formatHandicap(entry.handicap_index_snapshot)}
              </span>
              <DropdownMenu>
                <DropdownMenuTrigger
                  aria-label={`Handlinger for ${entry.display_name}`}
                  className="flex size-8 shrink-0 items-center justify-center rounded-lg text-muted-foreground transition-colors hover:bg-accent/60 hover:text-foreground"
                >
                  <MoreVertical aria-hidden="true" className="size-4" />
                </DropdownMenuTrigger>
                <DropdownMenuContent align="end" className="w-52 rounded-2xl p-1.5">
                  <DropdownMenuItem
                    onClick={() => setEditingPlayerId(entry.player_id)}
                    className="flex cursor-pointer items-center gap-2 rounded-xl px-3 py-2.5 text-sm font-semibold"
                  >
                    <Pencil aria-hidden="true" className="size-4" />
                    Rediger spiller
                  </DropdownMenuItem>
                  <DropdownMenuItem
                    onClick={() => onToggleCaptain(team.id, entry.id, entry.is_captain)}
                    className="flex cursor-pointer items-center gap-2 rounded-xl px-3 py-2.5 text-sm font-semibold"
                  >
                    <Star aria-hidden="true" className="size-4" />
                    {entry.is_captain ? "Fjern som kaptein" : "Gjør til kaptein"}
                  </DropdownMenuItem>
                  {otherTeam && (
                    <DropdownMenuItem
                      onClick={() => onMovePlayer(team.id, entry.id, otherTeam.id)}
                      className="flex cursor-pointer items-center gap-2 rounded-xl px-3 py-2.5 text-sm font-semibold"
                    >
                      <ArrowLeftRight aria-hidden="true" className="size-4" />
                      Flytt til {otherTeam.name}
                    </DropdownMenuItem>
                  )}
                  <DropdownMenuItem
                    onClick={() => setConfirmingId(entry.id)}
                    className="flex cursor-pointer items-center gap-2 rounded-xl px-3 py-2.5 text-sm font-semibold text-destructive"
                  >
                    <Trash2 aria-hidden="true" className="size-4" />
                    Fjern fra laget
                  </DropdownMenuItem>
                </DropdownMenuContent>
              </DropdownMenu>
            </li>
          )
        })}
      </ul>

      <div className="border-t border-border p-4">
        <AddPlayerControl
          team={team}
          otherTeam={otherTeam}
          pool={pool}
          findPlayerTeam={findPlayerTeam}
          onAddExisting={onAddExisting}
          onAddNew={onAddNew}
        />
      </div>

      <div className="border-t border-border p-4">
        {confirmingGiveUp ? (
          <div className="flex flex-col gap-3 rounded-2xl bg-destructive/5 p-3">
            {giveUpError && (
              <p role="alert" className="text-xs font-medium text-destructive text-pretty">
                {giveUpError}
              </p>
            )}
            <p className="text-sm text-foreground text-pretty">
              Er du sikker på at <span className="font-semibold">{team.name}</span> gir opp
              resten av turneringen? Motstanderen får full poengsum for ALLE ikke-avgjorte
              matcher, med én gang.
            </p>
            <div className="flex justify-end gap-2">
              <Button
                type="button"
                size="sm"
                variant="destructive"
                className="h-9 rounded-xl"
                disabled={givingUp}
                onClick={handleGiveUp}
              >
                Gi opp turneringen
              </Button>
              <Button
                type="button"
                size="sm"
                variant="ghost"
                className="h-9 rounded-xl"
                onClick={() => {
                  setConfirmingGiveUp(false)
                  setGiveUpError(null)
                }}
              >
                Avbryt
              </Button>
            </div>
          </div>
        ) : (
          <Button
            type="button"
            variant="ghost"
            onClick={() => setConfirmingGiveUp(true)}
            className="h-9 w-full justify-start rounded-xl text-xs font-semibold text-muted-foreground hover:text-destructive"
          >
            <Flag aria-hidden="true" className="size-3.5" />
            Gi opp resten av turneringen for laget (walkover)
          </Button>
        )}
      </div>
    </section>
  )
}

// --- Add player type-ahead -------------------------------------------------

function AddPlayerControl({
  team,
  pool,
  findPlayerTeam,
  onAddExisting,
  onAddNew,
}: {
  team: Team
  otherTeam: Team | null
  pool: ApiPlayer[]
  findPlayerTeam: (playerId: string) => Team | null
  onAddExisting: (teamId: string, playerId: string) => void
  onAddNew: (teamId: string, name: string, handicap?: number) => void
}) {
  const [open, setOpen] = useState(false)
  const [query, setQuery] = useState("")
  const [creating, setCreating] = useState(false)
  const [newHandicap, setNewHandicap] = useState("")

  const trimmed = query.trim()

  const matches = useMemo(() => {
    if (!trimmed) return []
    const q = trimmed.toLowerCase()
    return pool
      .filter((p) => p.display_name.toLowerCase().includes(q))
      .map((p) => {
        const onTeam = findPlayerTeam(p.id)
        return {
          player: p,
          onThisTeam: onTeam?.id === team.id,
          onOtherTeam: onTeam && onTeam.id !== team.id ? onTeam : null,
        }
      })
      .filter((m) => !m.onThisTeam)
  }, [pool, trimmed, findPlayerTeam, team.id])

  const exactMatch = useMemo(
    () => pool.some((p) => p.display_name.toLowerCase() === trimmed.toLowerCase()),
    [pool, trimmed],
  )

  const showCreate = trimmed.length >= 2 && !exactMatch

  function reset() {
    setQuery("")
    setCreating(false)
    setNewHandicap("")
  }

  function handleAddExisting(playerId: string) {
    onAddExisting(team.id, playerId)
    reset()
  }

  function handleCreate() {
    if (trimmed.length < 2) return
    const hcpValue = newHandicap.trim() === "" ? undefined : Number(newHandicap.replace(",", "."))
    const hcp = hcpValue !== undefined && !Number.isNaN(hcpValue) ? hcpValue : undefined
    onAddNew(team.id, trimmed, hcp)
    reset()
  }

  if (!open) {
    return (
      <Button
        type="button"
        variant="secondary"
        onClick={() => setOpen(true)}
        className="h-11 w-full rounded-2xl text-sm font-bold"
      >
        <UserPlus aria-hidden="true" className="size-4" />
        Legg til spiller
      </Button>
    )
  }

  return (
    <div className="flex flex-col gap-2">
      <div className="flex items-center gap-2">
        <Input
          autoFocus
          placeholder="Søk eller skriv navn…"
          value={query}
          onChange={(e) => {
            setQuery(e.target.value)
            setCreating(false)
          }}
          onKeyDown={(e) => {
            if (e.key === "Escape") {
              setOpen(false)
              reset()
            }
          }}
          className="h-11 flex-1 rounded-2xl text-base"
        />
        <Button
          type="button"
          variant="ghost"
          size="icon"
          onClick={() => {
            setOpen(false)
            reset()
          }}
          className="size-11 shrink-0 rounded-2xl text-muted-foreground"
          aria-label="Lukk"
        >
          <X aria-hidden="true" className="size-5" />
        </Button>
      </div>

      {trimmed.length > 0 && (
        <div className="overflow-hidden rounded-2xl border border-border bg-background">
          <ul className="flex max-h-64 flex-col overflow-auto">
            {matches.map(({ player, onOtherTeam }) => {
              if (onOtherTeam) {
                return (
                  <li
                    key={player.id}
                    className="flex cursor-not-allowed items-center justify-between gap-3 border-b border-border px-4 py-2.5 opacity-60 last:border-b-0"
                  >
                    <div className="flex min-w-0 flex-col">
                      <span className="truncate text-sm font-medium text-muted-foreground line-through">
                        {player.display_name}
                      </span>
                      <span className="truncate text-xs text-muted-foreground">
                        allerede på {onOtherTeam.name}
                      </span>
                    </div>
                    <span className="shrink-0 tabular-nums text-xs text-muted-foreground">
                      {formatHandicap(player.handicap_index)}
                    </span>
                  </li>
                )
              }
              return (
                <li key={player.id} className="border-b border-border last:border-b-0">
                  <button
                    type="button"
                    onClick={() => handleAddExisting(player.id)}
                    className="flex w-full items-center justify-between gap-3 px-4 py-2.5 text-left transition-colors hover:bg-accent/60"
                  >
                    <span className="truncate text-sm font-semibold text-foreground">
                      {player.display_name}
                    </span>
                    <span className="shrink-0 tabular-nums text-sm text-muted-foreground">
                      {formatHandicap(player.handicap_index)}
                    </span>
                  </button>
                </li>
              )
            })}

            {matches.length === 0 && !showCreate && (
              <li className="px-4 py-3 text-center text-sm text-muted-foreground">
                Ingen treff.
              </li>
            )}

            {showCreate && !creating && (
              <li className="border-t border-border">
                <button
                  type="button"
                  onClick={() => setCreating(true)}
                  className="flex w-full items-center gap-2 px-4 py-3 text-left text-sm font-semibold text-primary transition-colors hover:bg-accent/60"
                >
                  <Plus aria-hidden="true" className="size-4" />
                  Opprett ny spiller: «{trimmed}»
                </button>
              </li>
            )}

            {showCreate && creating && (
              <li className="flex flex-col gap-3 border-t border-border bg-accent/30 px-4 py-3">
                <span className="text-sm font-semibold text-foreground">
                  Ny spiller: {trimmed}
                </span>
                <div className="flex items-end gap-2">
                  <div className="flex flex-1 flex-col gap-1.5">
                    <Label htmlFor="new-hcp" className="text-xs font-semibold text-muted-foreground">
                      Handicap-indeks (valgfritt)
                    </Label>
                    <Input
                      id="new-hcp"
                      autoFocus
                      inputMode="decimal"
                      placeholder="F.eks. 12.5"
                      value={newHandicap}
                      onChange={(e) => setNewHandicap(e.target.value)}
                      onKeyDown={(e) => {
                        if (e.key === "Enter") {
                          e.preventDefault()
                          handleCreate()
                        }
                      }}
                      className="h-11 rounded-xl text-base"
                    />
                  </div>
                  <Button
                    type="button"
                    onClick={handleCreate}
                    className="h-11 shrink-0 rounded-xl font-bold"
                  >
                    Legg til
                  </Button>
                </div>
              </li>
            )}
          </ul>
        </div>
      )}
    </div>
  )
}

// --- Rediger spiller (spillerpoolen, ikke et lags frosne snapshot) --------

function EditPlayerForm({
  displayName,
  handicapIndex,
  gender,
  onSave,
  onCancel,
}: {
  displayName: string
  handicapIndex: number | null
  gender: "m" | "f" | "x" | null
  onSave: (updates: { display_name: string; handicap_index: number | null; gender: string | null }) => void
  onCancel: () => void
}) {
  const [name, setName] = useState(displayName)
  const [hcp, setHcp] = useState(handicapIndex === null ? "" : String(handicapIndex))
  const [genderValue, setGenderValue] = useState<string>(gender ?? "")
  const valid = name.trim().length >= 1

  function handleSubmit(e: React.FormEvent) {
    e.preventDefault()
    if (!valid) return
    onSave({
      display_name: name.trim(),
      handicap_index: hcp.trim() === "" ? null : Number(hcp.replace(",", ".")),
      gender: genderValue === "" ? null : genderValue,
    })
  }

  return (
    <form onSubmit={handleSubmit} className="flex flex-col gap-3">
      <div className="grid grid-cols-1 gap-2 sm:grid-cols-3">
        <Input
          value={name}
          onChange={(e) => setName(e.target.value)}
          placeholder="Navn"
          className="h-10 rounded-xl text-sm sm:col-span-1"
        />
        <Input
          value={hcp}
          onChange={(e) => setHcp(e.target.value)}
          placeholder="HCP"
          inputMode="decimal"
          className="h-10 rounded-xl text-sm"
        />
        <select
          value={genderValue}
          onChange={(e) => setGenderValue(e.target.value)}
          className="h-10 rounded-xl border border-border bg-card px-2.5 text-sm font-medium text-foreground outline-none"
        >
          <option value="">Kjønn ikke satt</option>
          <option value="f">Dame</option>
          <option value="m">Herre</option>
          <option value="x">Annet</option>
        </select>
      </div>
      <p className="text-xs leading-relaxed text-muted-foreground text-pretty">
        Endrer spilleren i poolen (brukes ved fremtidig rostring). Endrer IKKE HCP-tallet som
        allerede er registrert på et lag i denne turneringen — fjern og legg til spilleren på
        nytt på laget for å oppdatere det.
      </p>
      <div className="flex justify-end gap-2">
        <Button type="submit" size="sm" disabled={!valid} className="h-9 rounded-xl">
          Lagre
        </Button>
        <Button type="button" size="sm" variant="ghost" onClick={onCancel} className="h-9 rounded-xl">
          Avbryt
        </Button>
      </div>
    </form>
  )
}

// --- Helpers ---------------------------------------------------------------

function formatHandicap(handicap: number | null | undefined) {
  if (handicap === null || handicap === undefined) return "—"
  return handicap.toFixed(1)
}
