"use client"

import type React from "react"
import { useEffect, useMemo, useState } from "react"
import Link from "next/link"
import {
  ArrowLeft,
  CalendarClock,
  Check,
  ChevronDown,
  ChevronRight,
  Clock,
  Flag,
  MapPin,
  MoreVertical,
  Pencil,
  Plus,
  Sparkles,
  Trash2,
  Users,
  X,
} from "lucide-react"
import { Button } from "@/components/ui/button"
import { Input } from "@/components/ui/input"
import { Label } from "@/components/ui/label"
import { Switch } from "@/components/ui/switch"
import {
  DropdownMenu,
  DropdownMenuContent,
  DropdownMenuItem,
  DropdownMenuTrigger,
} from "@/components/ui/dropdown-menu"
import { cn } from "@/lib/utils"
import { CourseTemplatePicker } from "@/components/course-template-editor"

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

// 'scramble' finnes IKKE som egen verdi i API-et -- skjemaets CHECK-constraint
// (001_initial_schema.sql) og handicap_engine.py sin Format-enum krever
// scramble_2/scramble_4 (antall spillere per side er del av selve formatet,
// ikke en egen bryter).
// Fire nye org-lagturnering-formater (2026-07-30, se ADR/plan) -- flatt-
// felt-formatene (Københavner/BBB/Flag) hører ALDRI hjemme her (ADR-011s
// to-lags-modell passer strukturelt ikke), kun individuelle org-turneringer.
type SessionFormat =
  | "foursome"
  | "greensome"
  | "scramble_2"
  | "scramble_4"
  | "fourball"
  | "singles"
  | "chapman"
  | "shamble"
  | "money_ball"
  | "high_low_high"
type HoleConfig = "full_18" | "front_9" | "back_9"
type ScoringMode = "stroke" | "hole_result"

// Formater der ENHETEN som deler én Playing Handicap er SIDEN, ikke spilleren
// -- avgjør om et manuelt HCP-prosent-overstyr skal sendes som "combined"
// eller "per_player" (se app/handicap.py sin _SIDE_IS_UNIT). Chapman er
// delt-ball (som foursome); shamble/money_ball/high_low_high er
// individuell-ball (som fourball) selv om alle fire er to-sidede formater.
const SIDE_IS_UNIT_FORMAT = new Set<SessionFormat>(["foursome", "greensome", "scramble_2", "scramble_4", "chapman"])

type ApiCourse = {
  id: string
  name: string
  source: string
}

type ApiTee = {
  id: string
  name: string
}

// Konkurranseklasser (2026-08-03) -- fritt navngitte, med et valgfritt
// standardutslag brukt til å forhåndsutfylle riktig utslag når en spiller
// legges til en match (session-blind-draw.tsx). Ren utslag-bekvemmelighet
// her -- INGEN egen resultatliste for lagturneringer (bekreftet med
// bruker: poeng er knyttet til hele kamper, ikke enkeltspillere). Flyttet
// hit fra tournament-detail.tsx (2026-08-04) -- gir ingen mening å velge
// et standardutslag før en bane faktisk finnes i programmet.
type ApiTournamentClass = {
  id: string
  name: string
  default_tee_id: string | null
  default_tee_name: string | null
}

type ApiSession = {
  id: string
  sequence: number
  name: string | null
  format: SessionFormat
  hole_config: HoleConfig
  course_id: string
  points_per_match: number
  allowance_override: Record<string, unknown> | null
  scoring_mode: ScoringMode
  scheduled_at: string | null
  tee_interval_minutes: number | null
  start_hole: number
  locked_team_ids: string[]
  revealed: boolean
}

// --- Norwegian display labels ----------------------------------------------

const FORMAT_LABELS: Record<SessionFormat, string> = {
  foursome: "Foursome",
  greensome: "Greensome",
  scramble_2: "Scramble (2 spillere)",
  scramble_4: "Scramble (4 spillere)",
  fourball: "Fourball",
  singles: "Singel",
  chapman: "Chapman",
  shamble: "Shamble",
  money_ball: "Money Ball",
  high_low_high: "High-low-high",
}

const HOLE_LABELS: Record<HoleConfig, string> = {
  full_18: "18 hull",
  front_9: "Front 9",
  back_9: "Back 9",
}

const SCORING_LABELS: Record<ScoringMode, string> = {
  stroke: "Slag for slag",
  hole_result: "Kun hullresultat",
}

const FORMAT_OPTIONS = Object.keys(FORMAT_LABELS) as SessionFormat[]
const HOLE_OPTIONS = Object.keys(HOLE_LABELS) as HoleConfig[]
const SCORING_OPTIONS = Object.keys(SCORING_LABELS) as ScoringMode[]

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

export function TournamentProgram({
  organizationId,
  tournamentId,
  tournamentName,
}: {
  organizationId: string
  tournamentId: string
  tournamentName: string
}) {
  const [sessions, setSessions] = useState<ApiSession[]>([])
  const [courses, setCourses] = useState<ApiCourse[]>([])
  const [classes, setClasses] = useState<ApiTournamentClass[]>([])
  const [loading, setLoading] = useState(true)
  const [error, setError] = useState<string | null>(null)

  useEffect(() => {
    let cancelled = false
    async function load() {
      try {
        const [sessionsRes, coursesRes, classesRes] = await Promise.all([
          fetch(`/orgs/${organizationId}/tournaments/${tournamentId}/sessions`, {
            credentials: "include",
          }),
          fetch(`/orgs/${organizationId}/courses`, { credentials: "include" }),
          fetch(`/orgs/${organizationId}/tournaments/${tournamentId}/classes`, {
            credentials: "include",
          }),
        ])
        if (!sessionsRes.ok || !coursesRes.ok) throw new Error("load failed")
        const sessionsData: ApiSession[] = await sessionsRes.json()
        const coursesData: ApiCourse[] = await coursesRes.json()
        if (cancelled) return
        setSessions(sessionsData)
        setCourses(coursesData)
        if (classesRes.ok) setClasses(await classesRes.json())
      } catch {
        if (!cancelled) setError("Klarte ikke å laste programmet. Prøv å laste siden på nytt.")
      } finally {
        if (!cancelled) setLoading(false)
      }
    }
    void load()
    return () => {
      cancelled = true
    }
  }, [organizationId, tournamentId])

  async function createClass(name: string, defaultTeeId: string | null) {
    setError(null)
    try {
      const res = await fetch(`/orgs/${organizationId}/tournaments/${tournamentId}/classes`, {
        method: "POST",
        headers: { "Content-Type": "application/json" },
        credentials: "include",
        body: JSON.stringify({ name, default_tee_id: defaultTeeId }),
      })
      if (!res.ok) throw new Error(`create class: ${res.status}`)
      const created: ApiTournamentClass = await res.json()
      setClasses((prev) => [...prev, created])
    } catch {
      setError("Klarte ikke å opprette klassen. Prøv igjen.")
    }
  }

  async function deleteClass(classId: string) {
    setError(null)
    try {
      const res = await fetch(
        `/orgs/${organizationId}/tournaments/${tournamentId}/classes/${classId}`,
        { method: "DELETE", credentials: "include" },
      )
      if (res.status !== 204) throw new Error(`delete class: ${res.status}`)
      setClasses((prev) => prev.filter((c) => c.id !== classId))
    } catch {
      setError("Klarte ikke å fjerne klassen. Prøv igjen.")
    }
  }

  const coursesById = useMemo(() => {
    const map = new Map<string, ApiCourse>()
    for (const c of courses) map.set(c.id, c)
    return map
  }, [courses])

  const sorted = useMemo(() => [...sessions].sort((a, b) => a.sequence - b.sequence), [sessions])

  const nextSequence = useMemo(
    () => (sessions.length === 0 ? 1 : Math.max(...sessions.map((s) => s.sequence)) + 1),
    [sessions],
  )

  async function ensureCourseId(existingId: string | null, newName: string): Promise<string> {
    if (existingId) return existingId
    const res = await fetch(`/orgs/${organizationId}/courses`, {
      method: "POST",
      headers: { "Content-Type": "application/json" },
      credentials: "include",
      body: JSON.stringify({ name: newName }),
    })
    if (!res.ok) throw new Error(`create course: ${res.status}`)
    const created: ApiCourse = await res.json()
    setCourses((prev) => [...prev, created])
    return created.id
  }

  async function addSession(input: {
    name?: string
    format: SessionFormat
    holeConfig: HoleConfig
    scoringMode: ScoringMode
    pointsPerMatch: number
    scheduledAt?: string
    teeIntervalMinutes?: number
    startHole: number
    courseId: string | null
    newCourseName: string
    allowanceOverride: Record<string, unknown> | null
    shambleBestN: number | null
  }) {
    setError(null)
    try {
      const courseId = await ensureCourseId(input.courseId, input.newCourseName)
      const res = await fetch(`/orgs/${organizationId}/tournaments/${tournamentId}/sessions`, {
        method: "POST",
        headers: { "Content-Type": "application/json" },
        credentials: "include",
        body: JSON.stringify({
          sequence: nextSequence,
          name: input.name ?? null,
          format: input.format,
          hole_config: input.holeConfig,
          course_id: courseId,
          points_per_match: input.pointsPerMatch,
          allowance_override: input.allowanceOverride,
          scoring_mode: input.scoringMode,
          scheduled_at: input.scheduledAt ?? null,
          tee_interval_minutes: input.teeIntervalMinutes ?? null,
          start_hole: input.startHole,
          shamble_best_n: input.format === "shamble" ? input.shambleBestN : null,
        }),
      })
      if (!res.ok) throw new Error(`create session: ${res.status}`)
      const created: ApiSession = await res.json()
      setSessions((prev) => [...prev, created])
    } catch {
      setError("Klarte ikke å opprette økten. Prøv igjen.")
    }
  }

  async function updateSession(sessionId: string, patch: Record<string, unknown>): Promise<boolean> {
    setError(null)
    try {
      const res = await fetch(`/orgs/${organizationId}/sessions/${sessionId}`, {
        method: "PATCH",
        headers: { "Content-Type": "application/json" },
        credentials: "include",
        body: JSON.stringify(patch),
      })
      if (!res.ok) throw new Error(`update session: ${res.status}`)
      const updated: ApiSession = await res.json()
      setSessions((prev) => prev.map((s) => (s.id === sessionId ? updated : s)))
      return true
    } catch {
      setError("Klarte ikke å oppdatere økten. Prøv igjen.")
      return false
    }
  }

  async function deleteSession(sessionId: string): Promise<string | null> {
    setError(null)
    try {
      const res = await fetch(`/orgs/${organizationId}/sessions/${sessionId}`, {
        method: "DELETE",
        credentials: "include",
      })
      if (res.status === 204) {
        setSessions((prev) => prev.filter((s) => s.id !== sessionId))
        return null
      }
      const body = await res.json().catch(() => null)
      return body?.detail?.message ?? "Klarte ikke å slette økten. Prøv igjen."
    } catch {
      return "Klarte ikke å slette økten. Prøv igjen."
    }
  }

  const detailHref = `/tournaments/${tournamentId}?org=${organizationId}&name=${encodeURIComponent(tournamentName)}`
  const programHref = `/tournaments/${tournamentId}/program?org=${organizationId}&name=${encodeURIComponent(tournamentName)}`
  const leaderboardHref = `/tournaments/${tournamentId}/leaderboard?org=${organizationId}&name=${encodeURIComponent(tournamentName)}`

  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={detailHref}
            aria-label="Tilbake til turnering"
            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-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>
        </div>

        <nav
          className="mx-auto flex w-full max-w-4xl items-center gap-2 overflow-x-auto px-5 pb-3"
          aria-label="Turneringsseksjoner"
        >
          <Link
            href={detailHref}
            className="shrink-0 rounded-full px-4 py-2 text-sm font-semibold text-muted-foreground transition-colors hover:bg-accent/60 hover:text-foreground"
          >
            Lag og spillere
          </Link>
          <Link
            href={programHref}
            aria-current="page"
            className="shrink-0 rounded-full bg-primary px-4 py-2 text-sm font-bold text-primary-foreground"
          >
            Program
          </Link>
          <Link
            href={leaderboardHref}
            className="shrink-0 rounded-full px-4 py-2 text-sm font-semibold text-muted-foreground transition-colors hover:bg-accent/60 hover:text-foreground"
          >
            Leaderboard
          </Link>
          <Link
            href={`/tournaments/${tournamentId}/presentation?org=${organizationId}&name=${encodeURIComponent(tournamentName)}`}
            className="shrink-0 rounded-full px-4 py-2 text-sm font-semibold text-muted-foreground transition-colors hover:bg-accent/60 hover:text-foreground"
          >
            Presentasjon
          </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">Program</h2>
          <p className="text-sm leading-relaxed text-muted-foreground text-pretty">
            Sett opp turneringens økter i rekkefølge. Hver økt er én runde med et gitt format og
            tidspunkt.
          </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>
        ) : (
          <>
            {sorted.length === 0 ? (
              <EmptyState />
            ) : (
              <>
                <DateCoverageSummary
                  total={sorted.length}
                  withDate={sorted.filter((s) => s.scheduled_at !== null).length}
                />
                <ol className="flex flex-col gap-3">
                  {sorted.map((session, index) => (
                    <SessionCard
                      key={session.id}
                      session={session}
                      course={coursesById.get(session.course_id) ?? null}
                      courses={courses}
                      organizationId={organizationId}
                      isLast={index === sorted.length - 1}
                      href={`/tournaments/${tournamentId}/sessions/${session.id}?org=${organizationId}&name=${encodeURIComponent(tournamentName)}`}
                      onCourseImported={(course) => setCourses((prev) => [...prev, course])}
                      onSave={(patch) => updateSession(session.id, patch)}
                      onDelete={() => deleteSession(session.id)}
                    />
                  ))}
                </ol>
              </>
            )}

            <div className="mt-6">
              <CreateSessionCard
                nextSequence={nextSequence}
                courses={courses}
                organizationId={organizationId}
                onCourseImported={(course) => setCourses((prev) => [...prev, course])}
                onCreate={addSession}
              />
            </div>

            <div className="mt-6">
              <ClassesCard
                classes={classes}
                courses={courses}
                organizationId={organizationId}
                onCreate={createClass}
                onDelete={deleteClass}
              />
            </div>
          </>
        )}
      </main>
    </div>
  )
}

// --- Konkurranseklasser (2026-08-03, flyttet hit 2026-08-04) ---------------
// Fritt navngitte klasser med et valgfritt standardutslag -- se
// tournament_class-tabellen (053_tournament_classes.sql). Kun utslag-
// bekvemmelighet i lagturneringer (ingen egen resultatliste her, bekreftet
// med bruker -- se AssignRoundParticipantControl/LeaderboardTab i
// individual-tournament-detail.tsx for der klasse OGSÅ deler leaderboardet).
// Plassert her, ETTER økt-/baneoppsettet over, siden standardutslaget er
// meningsløst å velge før man vet hvilke utslag banen faktisk har.

function ClassesCard({
  classes,
  courses,
  organizationId,
  onCreate,
  onDelete,
}: {
  classes: ApiTournamentClass[]
  courses: ApiCourse[]
  organizationId: string
  onCreate: (name: string, defaultTeeId: string | null) => void
  onDelete: (classId: string) => void
}) {
  const [name, setName] = useState("")
  const [courseId, setCourseId] = useState("")
  const [teeId, setTeeId] = useState("")
  const [tees, setTees] = useState<ApiTee[]>([])
  const [adding, setAdding] = useState(false)

  useEffect(() => {
    if (!courseId) {
      setTees([])
      setTeeId("")
      return
    }
    let cancelled = false
    fetch(`/orgs/${organizationId}/courses/${courseId}/tees`, { credentials: "include" })
      .then((res) => (res.ok ? res.json() : []))
      .then((data: ApiTee[]) => {
        if (!cancelled) {
          setTees(data)
          setTeeId(data[0]?.id ?? "")
        }
      })
    return () => {
      cancelled = true
    }
  }, [organizationId, courseId])

  async function handleSubmit(e: React.FormEvent) {
    e.preventDefault()
    if (name.trim().length === 0 || adding) return
    setAdding(true)
    await onCreate(name.trim(), teeId || null)
    setAdding(false)
    setName("")
    setCourseId("")
    setTeeId("")
  }

  return (
    <section className="flex flex-col gap-4 rounded-3xl border border-border bg-card p-5 shadow-md shadow-black/8 sm:p-6">
      <div className="flex items-center gap-2.5">
        <div className="flex size-10 items-center justify-center rounded-xl bg-muted">
          <Users aria-hidden="true" className="size-5 text-muted-foreground" />
        </div>
        <div className="flex flex-col">
          <h3 className="text-sm font-bold text-foreground">Klasser</h3>
          <p className="text-xs text-muted-foreground text-pretty">
            Foreslår riktig utslag når en spiller legges til en kamp -- ingen egen resultatliste
            her (poeng er knyttet til hele kamper, ikke enkeltspillere).
          </p>
        </div>
      </div>

      {classes.length > 0 && (
        <ul className="flex flex-col divide-y divide-border rounded-2xl border border-border">
          {classes.map((c) => (
            <li key={c.id} className="flex items-center gap-3 px-3 py-2.5">
              <div className="flex min-w-0 flex-1 flex-col">
                <span className="truncate text-sm font-semibold text-foreground">{c.name}</span>
                {c.default_tee_name && (
                  <span className="text-xs text-muted-foreground">
                    Standardutslag: {c.default_tee_name}
                  </span>
                )}
              </div>
              <button
                type="button"
                onClick={() => onDelete(c.id)}
                aria-label={`Fjern klassen ${c.name}`}
                className="flex size-11 shrink-0 items-center justify-center rounded-xl text-muted-foreground transition-colors hover:bg-destructive/10 hover:text-destructive"
              >
                <Trash2 aria-hidden="true" className="size-4" />
              </button>
            </li>
          ))}
        </ul>
      )}

      <form onSubmit={handleSubmit} className="flex flex-col gap-2 sm:flex-row sm:items-end">
        <div className="flex flex-1 flex-col gap-1.5">
          <Label htmlFor="class-name">Klassenavn</Label>
          <Input
            id="class-name"
            value={name}
            onChange={(e) => setName(e.target.value)}
            placeholder="F.eks. Damer"
            className="h-11"
          />
        </div>
        <div className="flex flex-1 flex-col gap-1.5">
          <Label htmlFor="class-course">Bane (for standardutslag)</Label>
          <select
            id="class-course"
            value={courseId}
            onChange={(e) => setCourseId(e.target.value)}
            className="h-11 rounded-lg border border-border bg-card px-2.5 text-sm font-medium text-foreground outline-none"
          >
            <option value="">Ingen standardutslag</option>
            {courses.map((c) => (
              <option key={c.id} value={c.id}>
                {c.name}
              </option>
            ))}
          </select>
        </div>
        {tees.length > 0 && (
          <div className="flex flex-1 flex-col gap-1.5">
            <Label htmlFor="class-tee">Standardutslag</Label>
            <select
              id="class-tee"
              value={teeId}
              onChange={(e) => setTeeId(e.target.value)}
              className="h-11 rounded-lg border border-border bg-card px-2.5 text-sm font-medium text-foreground outline-none"
            >
              {tees.map((t) => (
                <option key={t.id} value={t.id}>
                  {t.name}
                </option>
              ))}
            </select>
          </div>
        )}
        <Button
          type="submit"
          variant="outline"
          disabled={adding || name.trim().length === 0}
          className="h-11 shrink-0 rounded-xl font-semibold"
        >
          <Plus aria-hidden="true" className="size-4" />
          Legg til
        </Button>
      </form>
    </section>
  )
}

// --- Session card (timeline item) ------------------------------------------

function SessionCard({
  session,
  course,
  courses,
  organizationId,
  isLast,
  href,
  onCourseImported,
  onSave,
  onDelete,
}: {
  session: ApiSession
  course: ApiCourse | null
  courses: ApiCourse[]
  organizationId: string
  isLast: boolean
  href: string
  onCourseImported: (course: ApiCourse) => void
  onSave: (patch: Record<string, unknown>) => Promise<boolean>
  onDelete: () => Promise<string | null>
}) {
  const [mode, setMode] = useState<"view" | "editing" | "confirmingDelete">("view")
  const [deleteError, setDeleteError] = useState<string | null>(null)
  const [deleting, setDeleting] = useState(false)
  const title = session.name?.trim() || `Økt ${session.sequence}`

  async function handleDelete() {
    setDeleting(true)
    const message = await onDelete()
    setDeleting(false)
    if (message) {
      setDeleteError(message)
    } else {
      setMode("view")
    }
  }

  return (
    <li className="relative flex gap-4">
      <div className="flex flex-col items-center">
        <div className="flex size-11 shrink-0 items-center justify-center rounded-2xl bg-primary text-lg font-extrabold tabular-nums text-primary-foreground shadow-sm">
          {session.sequence}
        </div>
        {!isLast && <div aria-hidden="true" className="mt-1 w-0.5 flex-1 rounded-full bg-border" />}
      </div>

      {mode === "editing" ? (
        <EditSessionForm
          session={session}
          course={course}
          courses={courses}
          organizationId={organizationId}
          onCourseImported={onCourseImported}
          onCancel={() => setMode("view")}
          onSave={async (patch) => {
            const ok = await onSave(patch)
            if (ok) setMode("view")
          }}
        />
      ) : (
        <div className="mb-1 flex flex-1 flex-col gap-3 rounded-3xl border border-border bg-card p-5 shadow-md shadow-black/8">
          <div className="flex items-start justify-between gap-3">
            <Link href={href} className="flex min-w-0 flex-1 flex-col gap-1">
              <h3 className="text-lg font-extrabold tracking-tight text-foreground">{title}</h3>
              <div className="flex flex-wrap items-center gap-2">
                <MetaBadge>{FORMAT_LABELS[session.format]}</MetaBadge>
                <MetaBadge>{HOLE_LABELS[session.hole_config]}</MetaBadge>
                <MetaBadge>{SCORING_LABELS[session.scoring_mode]}</MetaBadge>
                <MetaBadge>{formatPoints(session.points_per_match)} poeng</MetaBadge>
                {course && <MetaBadge>{course.name}</MetaBadge>}
              </div>
            </Link>
            <DropdownMenu>
              <DropdownMenuTrigger
                aria-label={`Handlinger for ${title}`}
                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-44 rounded-2xl p-1.5">
                <DropdownMenuItem
                  onClick={() => setMode("editing")}
                  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
                </DropdownMenuItem>
                <DropdownMenuItem
                  onClick={() => {
                    setDeleteError(null)
                    setMode("confirmingDelete")
                  }}
                  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" />
                  Slett
                </DropdownMenuItem>
              </DropdownMenuContent>
            </DropdownMenu>
          </div>

          <Link href={href} className="flex flex-col gap-1.5 border-t border-border pt-3">
            {session.scheduled_at ? (
              <div className="flex items-start gap-2 text-sm text-foreground">
                <CalendarClock aria-hidden="true" className="mt-0.5 size-4 shrink-0 text-primary" />
                <span className="text-pretty">
                  Første utslag {formatDateTime(session.scheduled_at)}
                  {session.tee_interval_minutes
                    ? `, ${session.tee_interval_minutes} min mellom hver`
                    : ""}
                </span>
              </div>
            ) : (
              <div className="flex items-center gap-2 text-sm text-muted-foreground">
                <Clock aria-hidden="true" className="size-4 shrink-0" />
                <span>Tidspunkt ikke satt</span>
              </div>
            )}
            {session.start_hole !== 1 && (
              <div className="flex items-center gap-2 text-sm text-muted-foreground">
                <Flag aria-hidden="true" className="size-4 shrink-0" />
                <span>Starter på hull {session.start_hole}</span>
              </div>
            )}
            <div className="mt-1 flex items-center gap-1.5 text-sm font-semibold text-primary">
              <Users aria-hidden="true" className="size-4 shrink-0" />
              <span>Sett opp flights og lås oppstilling</span>
              <ChevronRight aria-hidden="true" className="size-4 shrink-0" />
            </div>
          </Link>

          {mode === "confirmingDelete" &&
            (deleteError ? (
              <div className="flex flex-col gap-3 rounded-2xl border border-border bg-muted/50 p-4">
                <p className="text-sm leading-relaxed text-muted-foreground text-pretty">{deleteError}</p>
                <div className="flex justify-end">
                  <Button
                    type="button"
                    size="sm"
                    variant="outline"
                    className="h-9 rounded-xl"
                    onClick={() => setMode("view")}
                  >
                    Lukk
                  </Button>
                </div>
              </div>
            ) : (
              <div className="flex flex-col gap-3 rounded-2xl border border-destructive/30 bg-destructive/5 p-4">
                <p className="text-sm leading-relaxed text-foreground text-pretty">
                  Er du sikker på at du vil slette denne økten? Dette kan ikke angres.
                </p>
                <div className="flex justify-end gap-2">
                  <Button
                    type="button"
                    size="sm"
                    variant="destructive"
                    className="h-9 rounded-xl"
                    disabled={deleting}
                    onClick={handleDelete}
                  >
                    {deleting ? "Sletter…" : "Slett"}
                  </Button>
                  <Button
                    type="button"
                    size="sm"
                    variant="ghost"
                    className="h-9 rounded-xl"
                    onClick={() => setMode("view")}
                  >
                    Avbryt
                  </Button>
                </div>
              </div>
            ))}
        </div>
      )}
    </li>
  )
}

// --- Edit session form -------------------------------------------------------

function EditSessionForm({
  session,
  course,
  courses,
  organizationId,
  onCourseImported,
  onSave,
  onCancel,
}: {
  session: ApiSession
  course: ApiCourse | null
  courses: ApiCourse[]
  organizationId: string
  onCourseImported: (course: ApiCourse) => void
  onSave: (patch: Record<string, unknown>) => Promise<void>
  onCancel: () => void
}) {
  const [name, setName] = useState(session.name ?? "")
  const [points, setPoints] = useState(String(session.points_per_match))
  const [startHole, setStartHole] = useState(String(session.start_hole))
  const [scheduledAt, setScheduledAt] = useState(session.scheduled_at?.slice(0, 16) ?? "")
  const [teeInterval, setTeeInterval] = useState(
    session.tee_interval_minutes ? String(session.tee_interval_minutes) : "",
  )
  const [courseId, setCourseId] = useState(session.course_id)
  const [courseName, setCourseName] = useState(course?.name ?? "")
  const [submitting, setSubmitting] = useState(false)

  const hasTime = scheduledAt.trim() !== ""
  const uid = session.id

  async function handleSubmit(e: React.FormEvent) {
    e.preventDefault()
    const pointsValue = Number(points.replace(",", ".")) || session.points_per_match
    const startHoleValue = Math.min(18, Math.max(1, Number(startHole) || 1))
    const intervalValue = hasTime && teeInterval.trim() !== "" ? Number(teeInterval) : undefined

    setSubmitting(true)
    await onSave({
      name: name.trim() || null,
      points_per_match: pointsValue,
      start_hole: startHoleValue,
      scheduled_at: hasTime ? scheduledAt : null,
      tee_interval_minutes: intervalValue && !Number.isNaN(intervalValue) ? intervalValue : null,
      course_id: courseId,
    })
    setSubmitting(false)
  }

  return (
    <form
      onSubmit={handleSubmit}
      className="mb-1 flex flex-1 flex-col gap-6 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">
          <Pencil 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">
            Rediger økt {session.sequence}
          </span>
          <span className="text-base font-bold text-foreground">
            {session.name?.trim() || `Økt ${session.sequence}`}
          </span>
        </div>
      </div>

      <div className="flex flex-col gap-2">
        <Label htmlFor={`edit-name-${uid}`} className="text-sm font-semibold">
          Navn <span className="font-normal text-muted-foreground">(valgfritt)</span>
        </Label>
        <Input
          id={`edit-name-${uid}`}
          placeholder="F.eks. Foursome dag 1"
          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">Bane</Label>
        <EditCourseField
          organizationId={organizationId}
          courses={courses}
          currentCourseId={courseId}
          currentCourseName={courseName}
          onCourseImported={onCourseImported}
          onChange={(id, name) => {
            setCourseId(id)
            setCourseName(name)
          }}
        />
      </div>

      <div className="grid grid-cols-2 gap-4">
        <div className="flex flex-col gap-2">
          <Label htmlFor={`edit-points-${uid}`} className="text-sm font-semibold">
            Poeng per match
          </Label>
          <Input
            id={`edit-points-${uid}`}
            inputMode="decimal"
            type="number"
            step="0.5"
            min="0"
            value={points}
            onChange={(e) => setPoints(e.target.value)}
            className="h-12 rounded-2xl text-base"
          />
        </div>
        <div className="flex flex-col gap-2">
          <Label htmlFor={`edit-starthole-${uid}`} className="text-sm font-semibold">
            Starthull
          </Label>
          <Input
            id={`edit-starthole-${uid}`}
            inputMode="numeric"
            type="number"
            min="1"
            max="18"
            value={startHole}
            onChange={(e) => setStartHole(e.target.value)}
            className="h-12 rounded-2xl text-base"
          />
        </div>
      </div>

      <div className="flex flex-col gap-2">
        <Label htmlFor={`edit-time-${uid}`} className="text-sm font-semibold">
          Startdato og -klokkeslett{" "}
          <span className="font-normal text-muted-foreground">(valgfritt)</span>
        </Label>
        <Input
          id={`edit-time-${uid}`}
          type="datetime-local"
          value={scheduledAt}
          onChange={(e) => setScheduledAt(e.target.value)}
          className="h-12 rounded-2xl text-base"
        />
      </div>

      {hasTime && (
        <div className="flex flex-col gap-2">
          <Label htmlFor={`edit-interval-${uid}`} className="text-sm font-semibold">
            Minutter mellom hver flight
          </Label>
          <Input
            id={`edit-interval-${uid}`}
            inputMode="numeric"
            type="number"
            min="1"
            placeholder="F.eks. 10"
            value={teeInterval}
            onChange={(e) => setTeeInterval(e.target.value)}
            className="h-12 rounded-2xl text-base"
          />
        </div>
      )}

      <div className="flex gap-3">
        <Button type="submit" disabled={submitting} className="h-12 flex-1 rounded-2xl text-base font-bold shadow-sm">
          {submitting ? "Lagrer…" : "Lagre"}
        </Button>
        <Button
          type="button"
          variant="ghost"
          onClick={onCancel}
          className="h-12 rounded-2xl px-6 text-base font-semibold"
        >
          Avbryt
        </Button>
      </div>
    </form>
  )
}

// --- Bane-bytte i redigeringsskjemaet (kun eksisterende baner -- PATCH sin
//     course_id må være en ekte, allerede opprettet bane, ikke en "opprett
//     ny"-tekststreng slik opprett-skjemaet tillater) -------------------------

function EditCourseField({
  organizationId,
  courses,
  currentCourseId,
  currentCourseName,
  onCourseImported,
  onChange,
}: {
  organizationId: string
  courses: ApiCourse[]
  currentCourseId: string
  currentCourseName: string
  onCourseImported: (course: ApiCourse) => void
  onChange: (courseId: string, courseName: string) => void
}) {
  const [open, setOpen] = useState(false)
  const [query, setQuery] = useState("")
  const [officialSearchOpen, setOfficialSearchOpen] = useState(false)
  const [internationalSearchOpen, setInternationalSearchOpen] = useState(false)
  const [templatePickerOpen, setTemplatePickerOpen] = useState(false)

  if (!open) {
    return (
      <div className="flex flex-wrap items-center gap-2">
        <span className="inline-flex items-center gap-1.5 rounded-full bg-secondary px-3 py-1.5 text-sm font-semibold text-secondary-foreground">
          <MapPin aria-hidden="true" className="size-4 text-primary" />
          {currentCourseName || "Ukjent bane"}
        </span>
        <Button
          type="button"
          size="sm"
          variant="outline"
          className="h-9 rounded-xl"
          onClick={() => {
            setQuery("")
            setOpen(true)
          }}
        >
          Bytt bane
        </Button>
      </div>
    )
  }

  const q = query.trim().toLowerCase()
  const matches = courses.filter((c) => c.name.toLowerCase().includes(q))

  function select(c: ApiCourse) {
    onChange(c.id, c.name)
    setOpen(false)
  }

  return (
    <div className="flex flex-col gap-3 rounded-2xl border border-border bg-background/50 p-3">
      <div className="flex items-center gap-2">
        <Input
          autoFocus
          value={query}
          onChange={(e) => setQuery(e.target.value)}
          placeholder="Søk blant organisasjonens baner…"
          className="h-11 flex-1 rounded-xl text-base"
        />
        <button
          type="button"
          onClick={() => setOpen(false)}
          aria-label="Lukk banesøk"
          className="flex size-9 shrink-0 items-center justify-center rounded-xl text-muted-foreground transition-colors hover:bg-accent/60 hover:text-foreground"
        >
          <X aria-hidden="true" className="size-4" />
        </button>
      </div>

      <ul className="flex max-h-48 flex-col overflow-auto rounded-xl border border-border">
        {matches.map((c) => (
          <li key={c.id} className="border-b border-border last:border-b-0">
            <button
              type="button"
              onClick={() => select(c)}
              className="flex w-full items-center justify-between gap-2 px-3 py-2.5 text-left text-sm font-semibold text-foreground transition-colors hover:bg-accent/60"
            >
              <span className="flex items-center gap-2">
                <MapPin aria-hidden="true" className="size-4 text-muted-foreground" />
                {c.name}
              </span>
              {c.id === currentCourseId && <Check aria-hidden="true" className="size-4 text-primary" />}
            </button>
          </li>
        ))}
        {matches.length === 0 && (
          <li className="px-3 py-3 text-center text-sm text-muted-foreground">Ingen treff.</li>
        )}
      </ul>

      {!officialSearchOpen && !internationalSearchOpen && !templatePickerOpen ? (
        <div className="flex flex-wrap gap-x-4 gap-y-1">
          <button
            type="button"
            onClick={() => setOfficialSearchOpen(true)}
            className="self-start text-sm font-semibold text-primary underline-offset-2 hover:underline"
          >
            Hent bane fra teeoff i stedet
          </button>
          <button
            type="button"
            onClick={() => setInternationalSearchOpen(true)}
            className="self-start text-sm font-semibold text-primary underline-offset-2 hover:underline"
          >
            Hent bane fra GolfAPI i stedet
          </button>
          <button
            type="button"
            onClick={() => setTemplatePickerOpen(true)}
            className="self-start text-sm font-semibold text-primary underline-offset-2 hover:underline"
          >
            Opprett bane med hull/utslag i stedet
          </button>
        </div>
      ) : officialSearchOpen ? (
        <OfficialCourseSearch
          organizationId={organizationId}
          onClose={() => setOfficialSearchOpen(false)}
          onImported={(newCourse) => {
            onCourseImported(newCourse)
            select(newCourse)
            setOfficialSearchOpen(false)
          }}
        />
      ) : internationalSearchOpen ? (
        <InternationalCourseSearch
          organizationId={organizationId}
          onClose={() => setInternationalSearchOpen(false)}
          onImported={(newCourse) => {
            onCourseImported(newCourse)
            select(newCourse)
            setInternationalSearchOpen(false)
          }}
        />
      ) : (
        <CourseTemplatePicker
          organizationId={organizationId}
          onCreated={(created) => {
            const course = { id: created.id, name: created.name, source: "custom" }
            onCourseImported(course)
            select(course)
            setTemplatePickerOpen(false)
          }}
          onCancel={() => setTemplatePickerOpen(false)}
        />
      )}
    </div>
  )
}

function MetaBadge({ children }: { children: React.ReactNode }) {
  return (
    <span className="inline-flex items-center rounded-full bg-secondary px-2.5 py-1 text-xs font-semibold text-secondary-foreground">
      {children}
    </span>
  )
}

// --- Date coverage summary ---------------------------------------------------
// Ingen sammendrag fantes tidligere for "har alle runder fått dato" -- måtte
// leses manuelt per øktkort. All nødvendig data finnes allerede i sessions.

function DateCoverageSummary({ total, withDate }: { total: number; withDate: number }) {
  const allSet = withDate === total
  return (
    <div
      className={cn(
        "mb-3 flex items-center gap-2 rounded-2xl border px-4 py-3 text-sm font-semibold",
        allSet
          ? "border-primary/30 bg-primary/5 text-primary"
          : "border-border bg-muted/50 text-muted-foreground",
      )}
    >
      {allSet ? (
        <Check aria-hidden="true" className="size-4 shrink-0" />
      ) : (
        <Clock aria-hidden="true" className="size-4 shrink-0" />
      )}
      <span>
        {allSet
          ? `Alle ${total} runder har fått dato og klokkeslett.`
          : `${withDate} av ${total} runder har fått dato og klokkeslett.`}
      </span>
    </div>
  )
}

// --- Empty state -----------------------------------------------------------

function EmptyState() {
  return (
    <div className="flex flex-col items-center gap-3 rounded-3xl border border-dashed border-border bg-card/50 px-6 py-10 text-center">
      <div className="flex size-14 items-center justify-center rounded-2xl bg-muted">
        <CalendarClock aria-hidden="true" className="size-7 text-muted-foreground" />
      </div>
      <div className="flex flex-col gap-1">
        <h3 className="text-base font-bold text-foreground">Ingen økter ennå</h3>
        <p className="mx-auto max-w-sm text-sm leading-relaxed text-muted-foreground text-pretty">
          Legg til den første økten nedenfor for å bygge programmet.
        </p>
      </div>
      <ChevronDown aria-hidden="true" className="size-5 animate-bounce text-muted-foreground" />
    </div>
  )
}

// --- Create session form -----------------------------------------------------

function CreateSessionCard({
  nextSequence,
  courses,
  organizationId,
  onCourseImported,
  onCreate,
}: {
  nextSequence: number
  courses: ApiCourse[]
  organizationId: string
  onCourseImported: (course: ApiCourse) => void
  onCreate: (input: {
    name?: string
    format: SessionFormat
    holeConfig: HoleConfig
    scoringMode: ScoringMode
    pointsPerMatch: number
    scheduledAt?: string
    teeIntervalMinutes?: number
    startHole: number
    courseId: string | null
    newCourseName: string
    allowanceOverride: Record<string, unknown> | null
    shambleBestN: number | null
  }) => Promise<void>
}) {
  const [name, setName] = useState("")
  const [format, setFormat] = useState<SessionFormat>("foursome")
  const [shambleBestN, setShambleBestN] = useState(1)
  const [holeConfig, setHoleConfig] = useState<HoleConfig>("full_18")
  const [scoringMode, setScoringMode] = useState<ScoringMode>("stroke")
  const [points, setPoints] = useState("1")
  const [scheduledAt, setScheduledAt] = useState("")
  const [teeInterval, setTeeInterval] = useState("")
  const [startHole, setStartHole] = useState("1")
  const [submitting, setSubmitting] = useState(false)

  const [courseQuery, setCourseQuery] = useState("")
  const [selectedCourseId, setSelectedCourseId] = useState<string | null>(null)
  const [officialSearchOpen, setOfficialSearchOpen] = useState(false)
  const [internationalSearchOpen, setInternationalSearchOpen] = useState(false)
  const [templatePickerOpen, setTemplatePickerOpen] = useState(false)

  const [advancedOpen, setAdvancedOpen] = useState(false)
  const [useHandicap, setUseHandicap] = useState(true)
  const [useCourseHandicap, setUseCourseHandicap] = useState(true)
  const [useMatchplayHandicap, setUseMatchplayHandicap] = useState(true)
  const [hcpPercent, setHcpPercent] = useState("")

  const trimmedCourseQuery = courseQuery.trim()
  const courseMatches = useMemo(() => {
    if (!trimmedCourseQuery || selectedCourseId) return []
    const q = trimmedCourseQuery.toLowerCase()
    return courses.filter((c) => c.name.toLowerCase().includes(q))
  }, [courses, trimmedCourseQuery, selectedCourseId])
  const exactCourseMatch = courses.some(
    (c) => c.name.toLowerCase() === trimmedCourseQuery.toLowerCase(),
  )
  const showCreateCourse = trimmedCourseQuery.length >= 2 && !exactCourseMatch && !selectedCourseId

  const hasTime = scheduledAt.trim() !== ""
  const courseChosen = selectedCourseId !== null || (showCreateCourse && trimmedCourseQuery.length >= 2)
  const valid = courseChosen

  function buildAllowanceOverride(): Record<string, unknown> | null {
    const percentValue = hcpPercent.trim() === "" ? undefined : Number(hcpPercent.replace(",", "."))
    const hasPercent = percentValue !== undefined && !Number.isNaN(percentValue)

    if (useHandicap && useCourseHandicap && useMatchplayHandicap && !hasPercent) {
      // Alt på standard -- ikke send noe, backend bruker allerede riktige
      // defaults når allowance_override er null (se app/handicap.py).
      return null
    }

    const override: Record<string, unknown> = {
      use_handicap: useHandicap,
      use_course_handicap: useCourseHandicap,
      use_matchplay_handicap: useMatchplayHandicap,
    }
    if (hasPercent) {
      const fraction = percentValue! / 100
      override.strategy = SIDE_IS_UNIT_FORMAT.has(format)
        ? { type: "combined", percentage: fraction }
        : { type: "per_player", percentage: fraction }
    }
    return override
  }

  async function handleSubmit(e: React.FormEvent) {
    e.preventDefault()
    if (!valid || submitting) return

    const pointsValue = Number(points.replace(",", ".")) || 1
    const startHoleValue = Math.min(18, Math.max(1, Number(startHole) || 1))
    const intervalValue = hasTime && teeInterval.trim() !== "" ? Number(teeInterval) : undefined

    setSubmitting(true)
    await onCreate({
      name: name.trim() || undefined,
      format,
      holeConfig,
      scoringMode,
      pointsPerMatch: pointsValue,
      scheduledAt: hasTime ? scheduledAt : undefined,
      teeIntervalMinutes: intervalValue && !Number.isNaN(intervalValue) ? intervalValue : undefined,
      startHole: startHoleValue,
      courseId: selectedCourseId,
      newCourseName: trimmedCourseQuery,
      allowanceOverride: buildAllowanceOverride(),
      shambleBestN: format === "shamble" ? shambleBestN : null,
    })
    setSubmitting(false)

    setName("")
    setFormat("foursome")
    setShambleBestN(1)
    setHoleConfig("full_18")
    setScoringMode("stroke")
    setPoints("1")
    setScheduledAt("")
    setTeeInterval("")
    setStartHole("1")
    setCourseQuery("")
    setSelectedCourseId(null)
    setOfficialSearchOpen(false)
    setAdvancedOpen(false)
    setUseHandicap(true)
    setUseCourseHandicap(true)
    setUseMatchplayHandicap(true)
    setHcpPercent("")
  }

  return (
    <form
      onSubmit={handleSubmit}
      className="flex flex-col gap-6 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">
          <Plus 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">
            Økt {nextSequence}
          </span>
          <span className="text-base font-bold text-foreground">Legg til økt</span>
        </div>
      </div>

      <div className="flex flex-col gap-2">
        <Label htmlFor="session-name" className="text-sm font-semibold">
          Navn <span className="font-normal text-muted-foreground">(valgfritt)</span>
        </Label>
        <Input
          id="session-name"
          placeholder="F.eks. Foursome dag 1"
          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">Format</Label>
        <div className="grid grid-cols-2 gap-2 sm:grid-cols-3">
          {FORMAT_OPTIONS.map((opt) => (
            <SegmentButton key={opt} selected={format === opt} onClick={() => setFormat(opt)}>
              {FORMAT_LABELS[opt]}
            </SegmentButton>
          ))}
        </div>
        {format === "shamble" && (
          <div className="flex flex-col gap-2 rounded-2xl border border-border bg-background p-3">
            <span className="text-sm font-semibold text-foreground">Beste N av laget teller per hull</span>
            <div className="grid grid-cols-4 gap-2">
              {[1, 2, 3, 4].map((n) => (
                <SegmentButton key={n} selected={shambleBestN === n} onClick={() => setShambleBestN(n)}>
                  {n}
                </SegmentButton>
              ))}
            </div>
            <p className="text-xs text-muted-foreground">
              Kan ikke endres etter at økten er opprettet.
            </p>
          </div>
        )}
        {format === "money_ball" && (
          <p className="text-xs text-muted-foreground">
            Nøyaktig 4 spillere per side -- rekkefølgen (hvem som er "money ball" på hvilket hull)
            tildeles når spillerne legges til matchen.
          </p>
        )}
      </div>

      <div className="flex flex-col gap-2">
        <Label className="text-sm font-semibold">Bane</Label>
        {selectedCourseId ? (
          <div className="flex items-center justify-between gap-2 rounded-2xl border border-border bg-background px-4 py-3">
            <span className="text-sm font-semibold text-foreground">
              {courses.find((c) => c.id === selectedCourseId)?.name}
            </span>
            <Button
              type="button"
              variant="ghost"
              size="icon"
              onClick={() => {
                setSelectedCourseId(null)
                setCourseQuery("")
              }}
              className="size-8 rounded-lg text-muted-foreground"
              aria-label="Fjern valgt bane"
            >
              <X aria-hidden="true" className="size-4" />
            </Button>
          </div>
        ) : (
          <div className="flex flex-col gap-2">
            <Input
              placeholder="Søk eller skriv banenavn…"
              value={courseQuery}
              onChange={(e) => setCourseQuery(e.target.value)}
              className="h-12 rounded-2xl text-base"
            />
            {trimmedCourseQuery.length > 0 && (
              <div className="overflow-hidden rounded-2xl border border-border bg-background">
                <ul className="flex max-h-48 flex-col overflow-auto">
                  {courseMatches.map((c) => (
                    <li key={c.id} className="border-b border-border last:border-b-0">
                      <button
                        type="button"
                        onClick={() => {
                          setSelectedCourseId(c.id)
                          setCourseQuery("")
                        }}
                        className="flex w-full items-center px-4 py-2.5 text-left text-sm font-semibold text-foreground transition-colors hover:bg-accent/60"
                      >
                        {c.name}
                      </button>
                    </li>
                  ))}
                  {courseMatches.length === 0 && !showCreateCourse && (
                    <li className="px-4 py-3 text-center text-sm text-muted-foreground">Ingen treff.</li>
                  )}
                  {showCreateCourse && (
                    <li className={courseMatches.length > 0 ? "border-t border-border" : ""}>
                      <button
                        type="button"
                        onClick={() => setSelectedCourseId(null)}
                        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 bane: «{trimmedCourseQuery}»
                      </button>
                    </li>
                  )}
                </ul>
              </div>
            )}
            <div className="flex flex-wrap gap-x-4 gap-y-1">
              <button
                type="button"
                onClick={() => setOfficialSearchOpen(true)}
                className="self-start text-sm font-semibold text-primary underline-offset-2 hover:underline"
              >
                Hent bane fra teeoff i stedet
              </button>
              <button
                type="button"
                onClick={() => setInternationalSearchOpen(true)}
                className="self-start text-sm font-semibold text-primary underline-offset-2 hover:underline"
              >
                Hent bane fra GolfAPI i stedet
              </button>
              <button
                type="button"
                onClick={() => setTemplatePickerOpen(true)}
                className="self-start text-sm font-semibold text-primary underline-offset-2 hover:underline"
              >
                Opprett bane med hull/utslag i stedet
              </button>
            </div>
            {officialSearchOpen && (
              <OfficialCourseSearch
                organizationId={organizationId}
                onClose={() => setOfficialSearchOpen(false)}
                onImported={(course) => {
                  onCourseImported(course)
                  setSelectedCourseId(course.id)
                  setOfficialSearchOpen(false)
                }}
              />
            )}
            {internationalSearchOpen && (
              <InternationalCourseSearch
                organizationId={organizationId}
                onClose={() => setInternationalSearchOpen(false)}
                onImported={(course) => {
                  onCourseImported(course)
                  setSelectedCourseId(course.id)
                  setInternationalSearchOpen(false)
                }}
              />
            )}
            {templatePickerOpen && (
              <CourseTemplatePicker
                organizationId={organizationId}
                onCreated={(course) => {
                  onCourseImported({ id: course.id, name: course.name, source: "custom" })
                  setSelectedCourseId(course.id)
                  setTemplatePickerOpen(false)
                }}
                onCancel={() => setTemplatePickerOpen(false)}
              />
            )}
          </div>
        )}
      </div>

      <div className="flex flex-col gap-2">
        <Label className="text-sm font-semibold">Hullomfang</Label>
        <div className="grid grid-cols-3 gap-2">
          {HOLE_OPTIONS.map((opt) => (
            <SegmentButton key={opt} selected={holeConfig === opt} onClick={() => setHoleConfig(opt)}>
              {HOLE_LABELS[opt]}
            </SegmentButton>
          ))}
        </div>
      </div>

      <div className="flex flex-col gap-2">
        <Label className="text-sm font-semibold">Scoringsmodus</Label>
        <div className="grid grid-cols-2 gap-2">
          {SCORING_OPTIONS.map((opt) => (
            <SegmentButton key={opt} selected={scoringMode === opt} onClick={() => setScoringMode(opt)}>
              {SCORING_LABELS[opt]}
            </SegmentButton>
          ))}
        </div>
      </div>

      <div className="grid grid-cols-2 gap-4">
        <div className="flex flex-col gap-2">
          <Label htmlFor="session-points" className="text-sm font-semibold">
            Poeng per match
          </Label>
          <Input
            id="session-points"
            inputMode="decimal"
            type="number"
            step="0.5"
            min="0"
            value={points}
            onChange={(e) => setPoints(e.target.value)}
            className="h-12 rounded-2xl text-base"
          />
        </div>
        <div className="flex flex-col gap-2">
          <Label htmlFor="session-starthole" className="text-sm font-semibold">
            Starthull
          </Label>
          <Input
            id="session-starthole"
            inputMode="numeric"
            type="number"
            min="1"
            max="18"
            value={startHole}
            onChange={(e) => setStartHole(e.target.value)}
            className="h-12 rounded-2xl text-base"
          />
        </div>
      </div>

      <div className="flex flex-col gap-2">
        <Label htmlFor="session-time" className="text-sm font-semibold">
          Startdato og -klokkeslett{" "}
          <span className="font-normal text-muted-foreground">(valgfritt)</span>
        </Label>
        <Input
          id="session-time"
          type="datetime-local"
          value={scheduledAt}
          onChange={(e) => setScheduledAt(e.target.value)}
          className="h-12 rounded-2xl text-base"
        />
      </div>

      {hasTime && (
        <div className="flex flex-col gap-2">
          <Label htmlFor="session-interval" className="text-sm font-semibold">
            Minutter mellom hver flight
          </Label>
          <Input
            id="session-interval"
            inputMode="numeric"
            type="number"
            min="1"
            placeholder="F.eks. 10"
            value={teeInterval}
            onChange={(e) => setTeeInterval(e.target.value)}
            className="h-12 rounded-2xl text-base"
          />
        </div>
      )}

      <div className="rounded-2xl border border-border bg-background/50">
        <button
          type="button"
          onClick={() => setAdvancedOpen((v) => !v)}
          aria-expanded={advancedOpen}
          className="flex w-full items-center justify-between gap-2 rounded-2xl px-4 py-3.5 text-left transition-colors hover:bg-accent/40"
        >
          <span className="flex items-center gap-2 text-sm font-semibold text-foreground">
            <Sparkles aria-hidden="true" className="size-4 text-muted-foreground" />
            Avanserte handicap-innstillinger
          </span>
          <ChevronDown
            aria-hidden="true"
            className={cn("size-5 text-muted-foreground transition-transform", advancedOpen && "rotate-180")}
          />
        </button>

        {advancedOpen && (
          <div className="flex flex-col gap-1 border-t border-border px-4 py-2">
            <ToggleRow label="Bruk handicap" checked={useHandicap} onCheckedChange={setUseHandicap} />
            {useHandicap && (
              <>
                <ToggleRow
                  label="Bruk course handicap-justering"
                  checked={useCourseHandicap}
                  onCheckedChange={setUseCourseHandicap}
                />
                <ToggleRow
                  label="Bruk matchplay-handicap"
                  checked={useMatchplayHandicap}
                  onCheckedChange={setUseMatchplayHandicap}
                />
                <div className="flex flex-col gap-2 py-3">
                  <Label htmlFor="hcp-percent" className="text-sm font-semibold">
                    HCP-prosent <span className="font-normal text-muted-foreground">(valgfritt)</span>
                  </Label>
                  <Input
                    id="hcp-percent"
                    inputMode="decimal"
                    placeholder="Standard for format"
                    value={hcpPercent}
                    onChange={(e) => setHcpPercent(e.target.value)}
                    className="h-11 rounded-xl text-base"
                  />
                </div>
              </>
            )}
          </div>
        )}
      </div>

      <Button type="submit" disabled={!valid || submitting} className="h-12 rounded-2xl text-base font-bold shadow-sm">
        <Plus aria-hidden="true" className="size-5" />
        {submitting ? "Legger til…" : "Legg til økt"}
      </Button>
    </form>
  )
}

// --- Offisiell bane fra teeoff (ADR-019) ------------------------------------

type ApiOfficialFacility = {
  slug: string
  name: string
  city: string | null
  county: string | null
}

type ApiOfficialCourseOption = {
  teeoff_course_id: number
  name: string
  is_main_course: boolean
}

function OfficialCourseSearch({
  organizationId,
  onClose,
  onImported,
}: {
  organizationId: string
  onClose: () => void
  onImported: (course: ApiCourse) => void
}) {
  const [query, setQuery] = useState("")
  const [facilities, setFacilities] = useState<ApiOfficialFacility[] | null>(null)
  const [selectedFacility, setSelectedFacility] = useState<ApiOfficialFacility | null>(null)
  const [courseOptions, setCourseOptions] = useState<ApiOfficialCourseOption[] | null>(null)
  const [searching, setSearching] = useState(false)
  const [importing, setImporting] = useState(false)
  const [error, setError] = useState<string | null>(null)

  async function runSearch() {
    setSearching(true)
    setError(null)
    try {
      const res = await fetch(
        `/orgs/${organizationId}/courses/official-search?q=${encodeURIComponent(query.trim())}`,
        { credentials: "include" },
      )
      if (!res.ok) throw new Error(`search: ${res.status}`)
      setFacilities(await res.json())
    } catch {
      setError("Klarte ikke å søke i teeoff sine baner akkurat nå.")
      setFacilities([])
    } finally {
      setSearching(false)
    }
  }

  async function pickFacility(facility: ApiOfficialFacility) {
    setSelectedFacility(facility)
    setError(null)
    setCourseOptions(null)
    try {
      const res = await fetch(`/orgs/${organizationId}/courses/official-search/${facility.slug}`, {
        credentials: "include",
      })
      if (!res.ok) throw new Error(`facility detail: ${res.status}`)
      const detail: { courses: ApiOfficialCourseOption[] } = await res.json()
      setCourseOptions(detail.courses)
    } catch {
      setError("Klarte ikke å hente baner for dette anlegget.")
      setCourseOptions([])
    }
  }

  async function importCourse(course: ApiOfficialCourseOption) {
    if (!selectedFacility) return
    setImporting(true)
    setError(null)
    try {
      const res = await fetch(`/orgs/${organizationId}/courses/official-import`, {
        method: "POST",
        headers: { "Content-Type": "application/json" },
        credentials: "include",
        body: JSON.stringify({
          facility_slug: selectedFacility.slug,
          teeoff_course_id: course.teeoff_course_id,
        }),
      })
      if (!res.ok) {
        const body = await res.json().catch(() => null)
        const code = body?.detail?.code
        if (code === "EXTERNAL_DATA_INCOMPLETE") {
          setError("Denne banen mangler nok data i teeoff til å importeres ennå.")
        } else if (code === "DUPLICATE") {
          setError("Denne banen er allerede importert til organisasjonen.")
        } else {
          setError("Klarte ikke å importere banen. Prøv igjen.")
        }
        return
      }
      onImported(await res.json())
    } catch {
      setError("Klarte ikke å importere banen. Prøv igjen.")
    } finally {
      setImporting(false)
    }
  }

  return (
    <div className="flex flex-col gap-3 rounded-2xl border border-border bg-background p-4">
      <div className="flex items-center justify-between gap-2">
        <span className="text-sm font-bold text-foreground">Hent bane fra teeoff</span>
        <Button
          type="button"
          variant="ghost"
          size="icon"
          onClick={onClose}
          className="size-8 rounded-lg text-muted-foreground"
          aria-label="Lukk"
        >
          <X aria-hidden="true" className="size-4" />
        </Button>
      </div>

      {error && <p className="text-sm font-medium text-destructive">{error}</p>}

      {!selectedFacility ? (
        <>
          {/* Bevisst IKKE et eget <form> her -- denne komponenten rendres
              inne i CreateSessionCard sitt <form onSubmit={handleSubmit}>,
              og nestede <form>-elementer er ugyldig HTML. Nettleseren
              slår da sammen de to skjemaene i den faktiske DOM-en, som
              gjorde at "Søk"-knappen i praksis submittet det YTRE
              økt-skjemaet i stedet -- en ekte native side-navigasjon som
              vasket bort ?org=...-parameteren fra URL-en (funnet ved en
              reell feilrapport fra bruker mot produksjon). */}
          <div className="flex items-center gap-2">
            <Input
              autoFocus
              placeholder="Søk anleggsnavn…"
              value={query}
              onChange={(e) => setQuery(e.target.value)}
              onKeyDown={(e) => {
                if (e.key === "Enter") {
                  e.preventDefault()
                  runSearch()
                }
              }}
              className="h-11 flex-1 rounded-xl text-base"
            />
            <Button
              type="button"
              onClick={() => runSearch()}
              disabled={searching}
              className="h-11 shrink-0 rounded-xl font-bold"
            >
              {searching ? "Søker…" : "Søk"}
            </Button>
          </div>
          {facilities && (
            <ul className="flex max-h-56 flex-col overflow-auto rounded-xl border border-border">
              {facilities.map((f) => (
                <li key={f.slug} className="border-b border-border last:border-b-0">
                  <button
                    type="button"
                    onClick={() => pickFacility(f)}
                    className="flex w-full flex-col px-4 py-2.5 text-left transition-colors hover:bg-accent/60"
                  >
                    <span className="text-sm font-semibold text-foreground">{f.name}</span>
                    {(f.city || f.county) && (
                      <span className="text-xs text-muted-foreground">
                        {[f.city, f.county].filter(Boolean).join(", ")}
                      </span>
                    )}
                  </button>
                </li>
              ))}
              {facilities.length === 0 && (
                <li className="px-4 py-3 text-center text-sm text-muted-foreground">Ingen treff.</li>
              )}
            </ul>
          )}
        </>
      ) : (
        <>
          <button
            type="button"
            onClick={() => {
              setSelectedFacility(null)
              setCourseOptions(null)
            }}
            className="self-start text-sm font-semibold text-muted-foreground hover:text-foreground"
          >
            ← {selectedFacility.name}
          </button>
          {courseOptions === null ? (
            <p className="text-sm text-muted-foreground">Laster baner…</p>
          ) : (
            <ul className="flex flex-col overflow-hidden rounded-xl border border-border">
              {courseOptions.map((c) => (
                <li key={c.teeoff_course_id} className="border-b border-border last:border-b-0">
                  <button
                    type="button"
                    disabled={importing}
                    onClick={() => importCourse(c)}
                    className="flex w-full items-center justify-between px-4 py-2.5 text-left text-sm font-semibold text-foreground transition-colors hover:bg-accent/60 disabled:opacity-50"
                  >
                    {c.name}
                    {importing && <span className="text-xs font-normal text-muted-foreground">Importerer…</span>}
                  </button>
                </li>
              ))}
              {courseOptions.length === 0 && (
                <li className="px-4 py-3 text-center text-sm text-muted-foreground">
                  Ingen 18-hulls baner å importere hos dette anlegget ennå.
                </li>
              )}
            </ul>
          )}
        </>
      )}
    </div>
  )
}

// --- Internasjonal bane fra GolfAPI.io (ADR-064) ----------------------------
//
// For baner utenfor teeoffs dekning (f.eks. Tjøme Golfklubb, bekreftet
// IKKE i teeoff 2026-08-12). Speiler OfficialCourseSearch over i STRUKTUR,
// men GolfAPIs /clubs-søk returnerer klubbens baner INLINE i samme svar
// (ingen eget facility-detalj-kall trengs, ulikt teeoff).

type ApiInternationalCourseOption = {
  course_id: string
  course_name: string
  num_holes: number
  has_gps: boolean
}

type ApiInternationalClub = {
  club_id: string
  club_name: string
  city: string | null
  country: string | null
  courses: ApiInternationalCourseOption[]
}

function InternationalCourseSearch({
  organizationId,
  onClose,
  onImported,
}: {
  organizationId: string
  onClose: () => void
  onImported: (course: ApiCourse) => void
}) {
  const [query, setQuery] = useState("")
  const [clubs, setClubs] = useState<ApiInternationalClub[] | null>(null)
  const [selectedClub, setSelectedClub] = useState<ApiInternationalClub | null>(null)
  const [searching, setSearching] = useState(false)
  const [importing, setImporting] = useState(false)
  const [error, setError] = useState<string | null>(null)

  async function runSearch() {
    if (!query.trim()) return
    setSearching(true)
    setError(null)
    try {
      const res = await fetch(
        `/orgs/${organizationId}/courses/international-search?q=${encodeURIComponent(query.trim())}`,
        { credentials: "include" },
      )
      if (!res.ok) throw new Error(`search: ${res.status}`)
      setClubs(await res.json())
    } catch {
      setError("Klarte ikke å søke hos GolfAPI akkurat nå.")
      setClubs([])
    } finally {
      setSearching(false)
    }
  }

  async function importCourse(course: ApiInternationalCourseOption) {
    setImporting(true)
    setError(null)
    try {
      const res = await fetch(`/orgs/${organizationId}/courses/international-import`, {
        method: "POST",
        headers: { "Content-Type": "application/json" },
        credentials: "include",
        body: JSON.stringify({ golfapi_course_id: course.course_id }),
      })
      if (!res.ok) {
        const body = await res.json().catch(() => null)
        const code = body?.detail?.code
        if (code === "EXTERNAL_DATA_INCOMPLETE") {
          setError("Denne banen mangler nok data hos GolfAPI til å importeres ennå.")
        } else if (code === "NOT_CONFIGURED") {
          setError("GolfAPI er ikke konfigurert ennå.")
        } else {
          setError("Klarte ikke å importere banen. Prøv igjen.")
        }
        return
      }
      onImported(await res.json())
    } catch {
      setError("Klarte ikke å importere banen. Prøv igjen.")
    } finally {
      setImporting(false)
    }
  }

  return (
    <div className="flex flex-col gap-3 rounded-2xl border border-border bg-background p-4">
      <div className="flex items-center justify-between gap-2">
        <span className="text-sm font-bold text-foreground">Hent bane fra GolfAPI</span>
        <Button
          type="button"
          variant="ghost"
          size="icon"
          onClick={onClose}
          className="size-8 rounded-lg text-muted-foreground"
          aria-label="Lukk"
        >
          <X aria-hidden="true" className="size-4" />
        </Button>
      </div>

      {error && <p className="text-sm font-medium text-destructive">{error}</p>}

      {!selectedClub ? (
        <>
          {/* Bevisst IKKE et eget <form> her -- samme nesting-fellgruve som
              OfficialCourseSearch over (nestede <form>-er er ugyldig HTML). */}
          <div className="flex items-center gap-2">
            <Input
              autoFocus
              placeholder="Søk klubbnavn…"
              value={query}
              onChange={(e) => setQuery(e.target.value)}
              onKeyDown={(e) => {
                if (e.key === "Enter") {
                  e.preventDefault()
                  runSearch()
                }
              }}
              className="h-11 flex-1 rounded-xl text-base"
            />
            <Button
              type="button"
              onClick={() => runSearch()}
              disabled={searching}
              className="h-11 shrink-0 rounded-xl font-bold"
            >
              {searching ? "Søker…" : "Søk"}
            </Button>
          </div>
          {clubs && (
            <ul className="flex max-h-56 flex-col overflow-auto rounded-xl border border-border">
              {clubs.map((c) => (
                <li key={c.club_id} className="border-b border-border last:border-b-0">
                  <button
                    type="button"
                    onClick={() => setSelectedClub(c)}
                    className="flex w-full flex-col px-4 py-2.5 text-left transition-colors hover:bg-accent/60"
                  >
                    <span className="text-sm font-semibold text-foreground">{c.club_name}</span>
                    {(c.city || c.country) && (
                      <span className="text-xs text-muted-foreground">
                        {[c.city, c.country].filter(Boolean).join(", ")}
                      </span>
                    )}
                  </button>
                </li>
              ))}
              {clubs.length === 0 && (
                <li className="px-4 py-3 text-center text-sm text-muted-foreground">Ingen treff.</li>
              )}
            </ul>
          )}
        </>
      ) : (
        <>
          <button
            type="button"
            onClick={() => setSelectedClub(null)}
            className="self-start text-sm font-semibold text-muted-foreground hover:text-foreground"
          >
            ← {selectedClub.club_name}
          </button>
          <ul className="flex flex-col overflow-hidden rounded-xl border border-border">
            {selectedClub.courses.map((c) => (
              <li key={c.course_id} className="border-b border-border last:border-b-0">
                <button
                  type="button"
                  disabled={importing}
                  onClick={() => importCourse(c)}
                  className="flex w-full items-center justify-between px-4 py-2.5 text-left text-sm font-semibold text-foreground transition-colors hover:bg-accent/60 disabled:opacity-50"
                >
                  <span className="flex flex-col">
                    {c.course_name}
                    <span className="text-xs font-normal text-muted-foreground">
                      {c.num_holes} hull{c.has_gps ? " · avstandsdata tilgjengelig" : ""}
                    </span>
                  </span>
                  {importing && <span className="text-xs font-normal text-muted-foreground">Importerer…</span>}
                </button>
              </li>
            ))}
            {selectedClub.courses.length === 0 && (
              <li className="px-4 py-3 text-center text-sm text-muted-foreground">
                Ingen baner registrert hos denne klubben hos GolfAPI ennå.
              </li>
            )}
          </ul>
        </>
      )}
    </div>
  )
}

// --- Small UI helpers ------------------------------------------------------

function SegmentButton({
  selected,
  onClick,
  children,
}: {
  selected: boolean
  onClick: () => void
  children: React.ReactNode
}) {
  return (
    <button
      type="button"
      onClick={onClick}
      aria-pressed={selected}
      className={cn(
        "flex items-center justify-center rounded-2xl border px-3 py-3 text-sm font-semibold transition-colors",
        selected
          ? "border-primary bg-primary/10 text-foreground"
          : "border-border bg-card text-muted-foreground hover:bg-accent/50 hover:text-foreground",
      )}
    >
      {children}
    </button>
  )
}

function ToggleRow({
  label,
  checked,
  onCheckedChange,
}: {
  label: string
  checked: boolean
  onCheckedChange: (checked: boolean) => void
}) {
  return (
    <div className="flex items-center justify-between gap-4 border-b border-border py-3 last:border-b-0">
      <span className="text-sm font-medium text-foreground text-pretty">{label}</span>
      <Switch checked={checked} onCheckedChange={onCheckedChange} />
    </div>
  )
}

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

function formatPoints(points: number) {
  return Number.isInteger(points) ? String(points) : points.toFixed(1).replace(".", ",")
}

function formatDateTime(iso: string) {
  const date = new Date(iso)
  if (Number.isNaN(date.getTime())) return iso
  return date.toLocaleString("no-NO", {
    weekday: "short",
    day: "numeric",
    month: "short",
    hour: "2-digit",
    minute: "2-digit",
  })
}
