"use client"

import { ArrowLeft, Building2, ChevronRight, Flag, MapPin, PencilLine, Plus, Search } from "lucide-react"
import { useEffect, useMemo, useRef, useState } from "react"
import {
  fetchFacilityCourses,
  fetchOwnCourse,
  importInternationalCourse,
  nearbyOfficialFacilities,
  searchInternationalClubs,
  searchOfficialFacilities,
  searchOwnCourses,
} from "@/lib/ny-runde/api"
import type { ApiInternationalClub, ApiInternationalCourseOption } from "@/lib/ny-runde/api"
import type { Course, Facility } from "@/lib/ny-runde/types"
import { CreateCourseForm } from "./create-course-form"
import { ChoiceCard, Field, NativeSelect, Panel, Pill, TextInput, useDebouncedValue } from "./primitives"
import { useWizard } from "./wizard-context"

export function Step1CourseTime() {
  const { state, patch, exit } = useWizard()
  const sub = state.s1Sub

  function pickCourse(course: Course, meta: { source: "teeoff"; facilitySlug: string; teeoffCourseId: number } | { source: "custom"; personalCourseId: string }) {
    if (state.templateMode) {
      patch({ templateSeed: course, templateMode: false, s1Sub: "own-create" })
      return
    }
    const compatible = state.ownGender ? course.tees.filter((t) => t.genders.includes(state.ownGender!)) : course.tees
    const tee = compatible[0]
    patch({
      course,
      courseMeta: meta,
      courseSource: meta.source === "teeoff" ? "official" : "own",
      teeId: tee?.id,
      s1Sub: "fields",
      // Eierens EGET spillerkort (steg 3) har sitt eget teeId-felt, atskilt
      // fra state.teeId over -- uten denne synkroniseringen viser kortet
      // "Ikke valgt" selv om et utslag faktisk er valgt (kun kosmetisk, selve
      // innsendingen leser state.teeId direkte for eieren -- men samme
      // synkronisering som den opprinnelige new-round.tsx sin chooseCourse()
      // gjorde, så oppførselen matcher eksakt).
      players: state.players.map((p) => (p.kind === "owner" ? { ...p, teeId: tee?.id } : p)),
    })
  }

  switch (sub) {
    case "source":
      return (
        <SourceScreen
          templateMode={false}
          onOfficial={() => patch({ s1Sub: "official-search" })}
          onOwn={() => patch({ s1Sub: "own-search" })}
          onBack={exit}
        />
      )
    case "template-source":
      return (
        <SourceScreen
          templateMode
          onOfficial={() => patch({ templateMode: true, s1Sub: "official-search" })}
          onOwn={() => patch({ templateMode: true, s1Sub: "own-search" })}
          onBack={() => patch({ s1Sub: "own-create" })}
        />
      )
    case "official-search":
      return (
        <OfficialSearch
          templateMode={state.templateMode}
          onBack={() => patch({ s1Sub: state.templateMode ? "template-source" : "source" })}
          onPickFacility={(f) => patch({ selectedFacilitySlug: f.slug, s1Sub: "official-courses" })}
        />
      )
    case "official-courses":
      return (
        <OfficialCourses
          slug={state.selectedFacilitySlug}
          templateMode={state.templateMode}
          onBack={() => patch({ s1Sub: "official-search" })}
          onPick={(teeoffCourseId, course) =>
            pickCourse(course, { source: "teeoff", facilitySlug: state.selectedFacilitySlug!, teeoffCourseId })
          }
        />
      )
    case "own-search":
      return (
        <OwnSearch
          templateMode={state.templateMode}
          onBack={() => patch({ s1Sub: state.templateMode ? "template-source" : "source" })}
          onCreate={() => patch({ s1Sub: "own-create", templateSeed: undefined, ownCreateOrigin: "own-search" })}
          onPick={(course) => pickCourse(course, { source: "custom", personalCourseId: course.id })}
          onInternational={() => patch({ s1Sub: "international-search" })}
        />
      )
    case "international-search":
      return (
        <InternationalSearch
          onBack={() => patch({ s1Sub: "own-search" })}
          onPick={(course) => pickCourse(course, { source: "custom", personalCourseId: course.id })}
        />
      )
    case "own-create":
      return (
        <OwnCreate
          onBack={() => patch({ s1Sub: "own-search", templateSeed: undefined })}
          onTemplate={() => patch({ s1Sub: "template-source", ownCreateOrigin: "own-create" })}
          onCreate={(course) => pickCourse(course, { source: "custom", personalCourseId: course.id })}
          seed={state.templateSeed}
        />
      )
    case "fields":
      return <Fields />
    default:
      return null
  }
}

/* ------------------------------------------------------------------ */
function SubHeader({ title, onBack, subtitle }: { title: string; onBack: () => void; subtitle?: string }) {
  return (
    <div className="mb-4 flex items-start gap-3">
      <button
        type="button"
        onClick={onBack}
        aria-label="Tilbake"
        className="flex h-10 w-10 shrink-0 items-center justify-center rounded-lg border border-[var(--nr-border)] bg-[var(--nr-surface)] text-[var(--nr-ink)] transition-colors hover:bg-[var(--nr-surface-2)] focus-visible:outline-none focus-visible:ring-4 focus-visible:ring-[var(--nr-accent-ring)]/40"
      >
        <ArrowLeft className="h-4 w-4" aria-hidden="true" />
      </button>
      <div>
        <h2 className="text-lg font-semibold tracking-tight text-[var(--nr-ink)]">{title}</h2>
        {subtitle ? <p className="text-sm text-[var(--nr-muted)]">{subtitle}</p> : null}
      </div>
    </div>
  )
}

/* ------------------------------------------------------------------ */
/* source / template-source                                            */
function SourceScreen({
  templateMode,
  onOfficial,
  onOwn,
  onBack,
}: {
  templateMode: boolean
  onOfficial: () => void
  onOwn: () => void
  onBack: () => void
}) {
  return (
    <div>
      <SubHeader
        title={templateMode ? "Velg en mal" : "Hvor spiller du?"}
        subtitle={templateMode ? "Velg en bane å basere din egen bane på." : "Velg en offisiell bane eller din egen."}
        onBack={onBack}
      />
      <div className="grid gap-3">
        <ChoiceCard
          selected={false}
          onSelect={onOfficial}
          icon={<Building2 className="h-5 w-5" />}
          title="Offisiell bane"
          description="Søk opp en registrert golfbane fra databasen."
        />
        <ChoiceCard
          selected={false}
          onSelect={onOwn}
          icon={<PencilLine className="h-5 w-5" />}
          title="Egen bane"
          description="Bruk eller lag din egen manuelt registrerte bane."
        />
      </div>
    </div>
  )
}

/* ------------------------------------------------------------------ */
/* official-search (med geolokasjon "nærmest deg")                     */
function OfficialSearch({
  templateMode,
  onBack,
  onPickFacility,
}: {
  templateMode: boolean
  onBack: () => void
  onPickFacility: (f: Facility) => void
}) {
  const [query, setQuery] = useState("")
  const debounced = useDebouncedValue(query, 250)
  const [results, setResults] = useState<Facility[] | null>(null)
  const [nearest, setNearest] = useState<(Facility & { distanceKm: number })[]>([])
  const requested = useRef(false)

  useEffect(() => {
    if (requested.current) return
    requested.current = true
    if (typeof navigator === "undefined" || !navigator.geolocation) return
    navigator.geolocation.getCurrentPosition(
      (pos) => {
        void nearbyOfficialFacilities(pos.coords.latitude, pos.coords.longitude).then(setNearest)
      },
      () => {
        /* stille ved avslag/feil */
      },
      { timeout: 8000 },
    )
  }, [])

  useEffect(() => {
    const trimmed = debounced.trim()
    if (trimmed === "") {
      setResults(null)
      return
    }
    let cancelled = false
    void searchOfficialFacilities(trimmed).then((r) => {
      if (!cancelled) setResults(r)
    })
    return () => {
      cancelled = true
    }
  }, [debounced])

  return (
    <div>
      <SubHeader
        title={templateMode ? "Offisiell bane som mal" : "Offisiell bane"}
        subtitle="Søk etter anlegg på navn."
        onBack={onBack}
      />
      <Field label="Banenavn" htmlFor="official-q">
        <div className="relative">
          <Search className="pointer-events-none absolute left-3 top-1/2 h-4 w-4 -translate-y-1/2 text-[var(--nr-faint)]" aria-hidden="true" />
          <TextInput
            id="official-q"
            value={query}
            onChange={(e) => setQuery(e.target.value)}
            placeholder="Søk etter anlegg…"
            className="pl-9"
            autoComplete="off"
          />
        </div>
      </Field>

      <div className="mt-4">
        {results === null ? (
          nearest.length > 0 ? (
            <>
              <p className="mb-2 flex items-center gap-1.5 text-[13px] font-medium text-[var(--nr-muted)]">
                <MapPin className="h-4 w-4" aria-hidden="true" /> Nærmest deg
              </p>
              <ul className="flex flex-col gap-2">
                {nearest.map((f) => (
                  <FacilityRow
                    key={f.slug}
                    facility={f}
                    onClick={() => onPickFacility(f)}
                    distance={f.distanceKm * 1000 < 1000 ? `${Math.round(f.distanceKm * 1000)} m` : `${Math.round(f.distanceKm)} km`}
                  />
                ))}
              </ul>
            </>
          ) : (
            <p className="rounded-lg border border-dashed border-[var(--nr-border)] px-4 py-6 text-center text-sm text-[var(--nr-muted)]">
              Begynn å skrive for å søke etter en bane.
            </p>
          )
        ) : results.length > 0 ? (
          <ul className="flex flex-col gap-2">
            {results.map((f) => (
              <FacilityRow key={f.slug} facility={f} onClick={() => onPickFacility(f)} />
            ))}
          </ul>
        ) : (
          <p className="rounded-lg border border-dashed border-[var(--nr-border)] px-4 py-6 text-center text-sm text-[var(--nr-muted)]">
            Ingen anlegg matcher «{debounced}».
          </p>
        )}
      </div>
    </div>
  )
}

function FacilityRow({ facility, onClick, distance }: { facility: Facility; onClick: () => void; distance?: string }) {
  return (
    <li>
      <button
        type="button"
        onClick={onClick}
        className="flex min-h-14 w-full items-center gap-3 rounded-xl border border-[var(--nr-border)] bg-[var(--nr-surface)] px-4 py-3 text-left transition-colors hover:border-[var(--nr-border-strong)] focus-visible:outline-none focus-visible:ring-4 focus-visible:ring-[var(--nr-accent-ring)]/40"
      >
        <Building2 className="h-5 w-5 shrink-0 text-[var(--nr-muted)]" aria-hidden="true" />
        <span className="flex-1">
          <span className="block text-sm font-medium text-[var(--nr-ink)]">{facility.name}</span>
          <span className="block text-xs text-[var(--nr-muted)]">{[facility.city, facility.county].filter(Boolean).join(", ") || " "}</span>
        </span>
        {distance ? <Pill tone="neutral">{distance}</Pill> : null}
        <ChevronRight className="h-4 w-4 shrink-0 text-[var(--nr-faint)]" aria-hidden="true" />
      </button>
    </li>
  )
}

/* ------------------------------------------------------------------ */
/* official-courses                                                    */
function OfficialCourses({
  slug,
  templateMode,
  onBack,
  onPick,
}: {
  slug?: string
  templateMode: boolean
  onBack: () => void
  onPick: (teeoffCourseId: number, course: Course) => void
}) {
  const [courses, setCourses] = useState<{ teeoffCourseId: number; course: Course }[] | null>(null)
  const [loadError, setLoadError] = useState(false)

  useEffect(() => {
    if (!slug) return
    let cancelled = false
    setCourses(null)
    setLoadError(false)
    fetchFacilityCourses(slug)
      .then((r) => {
        if (!cancelled) setCourses(r)
      })
      .catch(() => {
        if (!cancelled) setLoadError(true)
      })
    return () => {
      cancelled = true
    }
  }, [slug])

  return (
    <div>
      <SubHeader title="Baner" subtitle="Velg en bane / sløyfe." onBack={onBack} />
      {loadError ? (
        <p role="alert" className="rounded-lg border border-[var(--nr-danger)]/30 bg-[var(--nr-danger-soft)] px-4 py-3 text-sm text-[var(--nr-danger)]">
          Klarte ikke å hente baner fra teeoff akkurat nå. Prøv igjen om litt.
        </p>
      ) : courses === null ? (
        <p className="text-sm text-[var(--nr-muted)]">Laster baner…</p>
      ) : (
        <ul className="flex flex-col gap-2">
          {courses.map(({ teeoffCourseId, course }) => (
            <li key={teeoffCourseId}>
              <CourseRow course={course} templateMode={templateMode} onPick={() => onPick(teeoffCourseId, course)} />
            </li>
          ))}
        </ul>
      )}
    </div>
  )
}

function CourseRow({ course, templateMode, onPick }: { course: Course; templateMode: boolean; onPick: () => void }) {
  return (
    <button
      type="button"
      onClick={onPick}
      className="flex min-h-14 w-full items-center gap-3 rounded-xl border border-[var(--nr-border)] bg-[var(--nr-surface)] px-4 py-3 text-left transition-colors hover:border-[var(--nr-border-strong)] focus-visible:outline-none focus-visible:ring-4 focus-visible:ring-[var(--nr-accent-ring)]/40"
    >
      <Flag className="h-5 w-5 shrink-0 text-[var(--nr-muted)]" aria-hidden="true" />
      <span className="flex-1">
        <span className="block text-sm font-medium text-[var(--nr-ink)]">{course.name}</span>
        <span className="block text-xs text-[var(--nr-muted)]">{course.tees.length} utslag</span>
      </span>
      {templateMode ? <Pill tone="accent">Bruk som mal for egen bane</Pill> : <ChevronRight className="h-4 w-4 shrink-0 text-[var(--nr-faint)]" aria-hidden="true" />}
    </button>
  )
}

/* ------------------------------------------------------------------ */
/* own-search                                                          */
function OwnSearch({
  templateMode,
  onBack,
  onCreate,
  onPick,
  onInternational,
}: {
  templateMode: boolean
  onBack: () => void
  onCreate: () => void
  onPick: (c: Course) => void
  onInternational: () => void
}) {
  const [query, setQuery] = useState("")
  const debounced = useDebouncedValue(query, 250)
  const [results, setResults] = useState<{ id: string; name: string }[] | null>(null)
  const inputRef = useRef<HTMLInputElement>(null)
  useEffect(() => {
    inputRef.current?.focus()
  }, [])

  useEffect(() => {
    const trimmed = debounced.trim()
    if (trimmed === "") {
      setResults(null)
      return
    }
    let cancelled = false
    void searchOwnCourses(trimmed).then((r) => {
      if (!cancelled) setResults(r)
    })
    return () => {
      cancelled = true
    }
  }, [debounced])

  async function pick(id: string) {
    const course = await fetchOwnCourse(id)
    if (course) onPick(course)
  }

  return (
    <div>
      <SubHeader
        title={templateMode ? "Egen bane som mal" : "Egen bane"}
        subtitle="Søk blant banene du har laget selv."
        onBack={onBack}
      />
      <Field label="Banenavn" htmlFor="own-q">
        <div className="relative">
          <Search className="pointer-events-none absolute left-3 top-1/2 h-4 w-4 -translate-y-1/2 text-[var(--nr-faint)]" aria-hidden="true" />
          <TextInput
            id="own-q"
            ref={inputRef}
            value={query}
            onChange={(e) => setQuery(e.target.value)}
            placeholder="Søk blant egne baner…"
            className="pl-9"
            autoComplete="off"
          />
        </div>
      </Field>

      {!templateMode ? (
        <button
          type="button"
          onClick={onCreate}
          className="mt-3 inline-flex min-h-11 w-full items-center justify-center gap-2 rounded-xl border border-dashed border-[var(--nr-border-strong)] bg-[var(--nr-surface)] px-4 text-sm font-medium text-[var(--nr-accent)] transition-colors hover:bg-[var(--nr-surface-2)] focus-visible:outline-none focus-visible:ring-4 focus-visible:ring-[var(--nr-accent-ring)]/40"
        >
          <Plus className="h-4 w-4" aria-hidden="true" />
          Opprett ny bane
        </button>
      ) : null}

      <div className="mt-4">
        {results === null ? (
          <p className="rounded-lg border border-dashed border-[var(--nr-border)] px-4 py-6 text-center text-sm text-[var(--nr-muted)]">
            Søk etter en egen bane{templateMode ? "" : ", eller opprett en ny"}.
          </p>
        ) : results.length > 0 ? (
          <ul className="flex flex-col gap-2">
            {results.map((c) => (
              <li key={c.id}>
                <button
                  type="button"
                  onClick={() => void pick(c.id)}
                  className="flex min-h-14 w-full items-center gap-3 rounded-xl border border-[var(--nr-border)] bg-[var(--nr-surface)] px-4 py-3 text-left transition-colors hover:border-[var(--nr-border-strong)] focus-visible:outline-none focus-visible:ring-4 focus-visible:ring-[var(--nr-accent-ring)]/40"
                >
                  <Flag className="h-5 w-5 shrink-0 text-[var(--nr-muted)]" aria-hidden="true" />
                  <span className="flex-1 text-sm font-medium text-[var(--nr-ink)]">{c.name}</span>
                  {templateMode ? <Pill tone="accent">Bruk som mal for egen bane</Pill> : <ChevronRight className="h-4 w-4 shrink-0 text-[var(--nr-faint)]" aria-hidden="true" />}
                </button>
              </li>
            ))}
          </ul>
        ) : (
          <p className="rounded-lg border border-dashed border-[var(--nr-border)] px-4 py-6 text-center text-sm text-[var(--nr-muted)]">
            Fant ingen egne baner som matcher «{debounced}».
          </p>
        )}
      </div>

      <button
        type="button"
        onClick={onInternational}
        className="mt-4 flex min-h-11 w-full items-center justify-center gap-2 text-[13px] font-medium text-[var(--nr-accent)] underline-offset-2 hover:underline"
      >
        Fant ikke banen? Søk internasjonalt (GolfAPI)
      </button>
    </div>
  )
}

/* ------------------------------------------------------------------ */
/* international-search (GolfAPI.io, ADR-064) -- for baner utenfor        */
/* teeoffs dekning (Tjøme Golfklubb var den konkrete anledningen).        */
/* Importerte baner havner i samme personal_course-katalog som "egen      */
/* bane" -- onPick gir tilbake en helt vanlig Course, ingen egen          */
/* CourseMeta-variant trengs (speiler OwnSearch/tournament-program.tsx). */
function InternationalSearch({
  onBack,
  onPick,
}: {
  onBack: () => void
  onPick: (c: Course) => 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 [importingId, setImportingId] = useState<string | null>(null)
  const [error, setError] = useState<string | null>(null)
  const inputRef = useRef<HTMLInputElement>(null)
  useEffect(() => {
    inputRef.current?.focus()
  }, [])

  async function runSearch() {
    if (!query.trim()) return
    setSearching(true)
    setError(null)
    try {
      setClubs(await searchInternationalClubs(query.trim()))
    } finally {
      setSearching(false)
    }
  }

  async function pick(course: ApiInternationalCourseOption) {
    setImportingId(course.course_id)
    setError(null)
    try {
      onPick(await importInternationalCourse(course.course_id))
    } catch {
      setError("Klarte ikke å importere banen fra GolfAPI. Prøv igjen.")
    } finally {
      setImportingId(null)
    }
  }

  return (
    <div>
      <SubHeader
        title={selectedClub ? selectedClub.club_name : "Søk internasjonalt"}
        subtitle={selectedClub ? "Velg en bane hos klubben." : "For baner utenfor TeeOffs dekning, via GolfAPI."}
        onBack={selectedClub ? () => setSelectedClub(null) : onBack}
      />
      {error ? (
        <p role="alert" className="mb-3 rounded-lg border border-[var(--nr-danger)]/30 bg-[var(--nr-danger-soft)] px-4 py-3 text-sm text-[var(--nr-danger)]">
          {error}
        </p>
      ) : null}

      {!selectedClub ? (
        <>
          <Field label="Klubbnavn" htmlFor="intl-q">
            <div className="relative">
              <Search className="pointer-events-none absolute left-3 top-1/2 h-4 w-4 -translate-y-1/2 text-[var(--nr-faint)]" aria-hidden="true" />
              <TextInput
                id="intl-q"
                ref={inputRef}
                value={query}
                onChange={(e) => setQuery(e.target.value)}
                onKeyDown={(e) => {
                  if (e.key === "Enter") {
                    e.preventDefault()
                    void runSearch()
                  }
                }}
                placeholder="Søk klubbnavn…"
                className="pl-9"
                autoComplete="off"
              />
            </div>
          </Field>
          <button
            type="button"
            onClick={() => void runSearch()}
            disabled={searching}
            className="mt-3 inline-flex min-h-11 w-full items-center justify-center rounded-xl bg-[var(--nr-accent)] px-4 text-sm font-semibold text-[var(--nr-accent-ink)] transition-colors hover:brightness-95 disabled:opacity-50"
          >
            {searching ? "Søker…" : "Søk"}
          </button>
          <div className="mt-4">
            {clubs === null ? (
              <p className="rounded-lg border border-dashed border-[var(--nr-border)] px-4 py-6 text-center text-sm text-[var(--nr-muted)]">
                Begynn å skrive for å søke etter en klubb.
              </p>
            ) : clubs.length > 0 ? (
              <ul className="flex flex-col gap-2">
                {clubs.map((c) => (
                  <li key={c.club_id}>
                    <button
                      type="button"
                      onClick={() => setSelectedClub(c)}
                      className="flex min-h-14 w-full items-center gap-3 rounded-xl border border-[var(--nr-border)] bg-[var(--nr-surface)] px-4 py-3 text-left transition-colors hover:border-[var(--nr-border-strong)] focus-visible:outline-none focus-visible:ring-4 focus-visible:ring-[var(--nr-accent-ring)]/40"
                    >
                      <Building2 className="h-5 w-5 shrink-0 text-[var(--nr-muted)]" aria-hidden="true" />
                      <span className="flex-1">
                        <span className="block text-sm font-medium text-[var(--nr-ink)]">{c.club_name}</span>
                        <span className="block text-xs text-[var(--nr-muted)]">{[c.city, c.country].filter(Boolean).join(", ") || " "}</span>
                      </span>
                      <ChevronRight className="h-4 w-4 shrink-0 text-[var(--nr-faint)]" aria-hidden="true" />
                    </button>
                  </li>
                ))}
              </ul>
            ) : (
              <p className="rounded-lg border border-dashed border-[var(--nr-border)] px-4 py-6 text-center text-sm text-[var(--nr-muted)]">
                Ingen klubber matcher «{query}».
              </p>
            )}
          </div>
        </>
      ) : (
        <ul className="flex flex-col gap-2">
          {selectedClub.courses.map((c) => (
            <li key={c.course_id}>
              <button
                type="button"
                disabled={importingId !== null}
                onClick={() => void pick(c)}
                className="flex min-h-14 w-full items-center gap-3 rounded-xl border border-[var(--nr-border)] bg-[var(--nr-surface)] px-4 py-3 text-left transition-colors hover:border-[var(--nr-border-strong)] focus-visible:outline-none focus-visible:ring-4 focus-visible:ring-[var(--nr-accent-ring)]/40 disabled:opacity-50"
              >
                <Flag className="h-5 w-5 shrink-0 text-[var(--nr-muted)]" aria-hidden="true" />
                <span className="flex-1">
                  <span className="block text-sm font-medium text-[var(--nr-ink)]">{c.course_name}</span>
                  <span className="block text-xs text-[var(--nr-muted)]">
                    {c.num_holes} hull{c.has_gps ? " · avstandsdata tilgjengelig" : ""}
                  </span>
                </span>
                {importingId === c.course_id ? (
                  <span className="text-xs font-medium text-[var(--nr-muted)]">Importerer…</span>
                ) : (
                  <ChevronRight className="h-4 w-4 shrink-0 text-[var(--nr-faint)]" aria-hidden="true" />
                )}
              </button>
            </li>
          ))}
          {selectedClub.courses.length === 0 ? (
            <li className="rounded-lg border border-dashed border-[var(--nr-border)] px-4 py-6 text-center text-sm text-[var(--nr-muted)]">
              Ingen baner registrert hos denne klubben hos GolfAPI ennå.
            </li>
          ) : null}
        </ul>
      )}
    </div>
  )
}

/* ------------------------------------------------------------------ */
/* own-create                                                          */
function OwnCreate({
  seed,
  onBack,
  onTemplate,
  onCreate,
}: {
  seed?: Course
  onBack: () => void
  onTemplate: () => void
  onCreate: (c: Course) => void
}) {
  return (
    <div>
      <SubHeader
        title={seed ? "Ny bane (fra mal)" : "Ny egen bane"}
        subtitle="Registrer hull, par, stroke-indeks og utslag."
        onBack={onBack}
      />
      {!seed ? (
        <button
          type="button"
          onClick={onTemplate}
          className="mb-4 text-[13px] font-medium text-[var(--nr-accent)] underline-offset-2 hover:underline"
        >
          Basér på en eksisterende bane i stedet
        </button>
      ) : (
        <div className="mb-4">
          <Pill tone="accent">Forhåndsutfylt fra «{seed.name}»</Pill>
        </div>
      )}
      <CreateCourseForm seed={seed} onCancel={onBack} onCreate={onCreate} />
    </div>
  )
}

/* ------------------------------------------------------------------ */
/* fields                                                              */
function Fields() {
  const { state, patch } = useWizard()
  const course = state.course
  if (!course) return null

  const compatibleTees = state.ownGender ? course.tees.filter((t) => t.genders.includes(state.ownGender!)) : course.tees
  const noCompatibleTee = compatibleTees.length === 0

  return (
    <div>
      <div className="mb-4">
        <h2 className="text-lg font-semibold tracking-tight text-[var(--nr-ink)]">Bane & tid</h2>
        <p className="text-sm text-[var(--nr-muted)]">Bekreft detaljene for runden.</p>
      </div>

      <Panel className="mb-4 bg-[var(--nr-surface-2)]">
        <div className="flex items-start justify-between gap-3">
          <div>
            <p className="text-sm font-semibold text-[var(--nr-ink)]">{course.name}</p>
            <p className="text-xs text-[var(--nr-muted)]">{course.tees.length} utslag</p>
          </div>
          <Pill tone={state.courseSource === "own" ? "neutral" : "accent"}>{state.courseSource === "own" ? "Egen bane" : "Offisiell"}</Pill>
        </div>
        <button
          type="button"
          onClick={() => patch({ s1Sub: "source", course: undefined, courseMeta: undefined, teeId: undefined })}
          className="mt-3 text-[13px] font-medium text-[var(--nr-accent)] underline-offset-2 hover:underline"
        >
          Bytt bane
        </button>
      </Panel>

      <div className="flex flex-col gap-4">
        <Field label="Navn på runden" optional htmlFor="round-name" hint="Maks 200 tegn.">
          <TextInput
            id="round-name"
            value={state.roundName}
            onChange={(e) => patch({ roundName: e.target.value.slice(0, 200) })}
            placeholder={course.name}
            maxLength={200}
          />
        </Field>

        <Field
          label="Utslag"
          htmlFor="tee"
          error={
            noCompatibleTee
              ? "Ingen utslag på denne banen har rating for ditt kjønn. Handicap kan ikke spores for denne runden, men du kan fortsette."
              : null
          }
        >
          {noCompatibleTee ? (
            <div className="rounded-lg border border-[var(--nr-border)] bg-[var(--nr-surface-2)] px-3 py-2.5 text-sm text-[var(--nr-muted)]">
              Ingen kompatible utslag.
            </div>
          ) : (
            <NativeSelect id="tee" value={state.teeId ?? ""} onChange={(e) => patch({ teeId: e.target.value })}>
              {compatibleTees.map((t) => (
                <option key={t.id} value={t.id}>
                  {t.name}
                </option>
              ))}
            </NativeSelect>
          )}
        </Field>

        <div className="grid grid-cols-2 gap-3">
          <Field label="Dato" htmlFor="date">
            <TextInput id="date" type="date" value={state.date} onChange={(e) => patch({ date: e.target.value })} />
          </Field>
          <Field label="Utslagstid" optional htmlFor="teetime">
            <TextInput id="teetime" type="time" value={state.teeTime} onChange={(e) => patch({ teeTime: e.target.value })} />
          </Field>
        </div>

        <Field label="Starthull" htmlFor="starthole">
          <NativeSelect
            id="starthole"
            value={state.startHole}
            onChange={(e) => patch({ startHole: Number.parseInt(e.target.value, 10) })}
          >
            {Array.from({ length: 18 }, (_, i) => i + 1).map((h) => (
              <option key={h} value={h}>
                Hull {h}
              </option>
            ))}
          </NativeSelect>
        </Field>
      </div>
    </div>
  )
}
