"use client"

import type React from "react"
import { useEffect, useState } from "react"
import Link from "next/link"
import {
  Calendar,
  Camera,
  Users,
  ChevronDown,
  ChevronRight,
  CheckCircle2,
  Clock3,
  Hourglass,
  ImagePlus,
  Lock,
  MessageSquare,
  Send,
  ShieldAlert,
  Trophy,
  X,
} from "lucide-react"
import { Button } from "@/components/ui/button"
import { Input } from "@/components/ui/input"
import { Label } from "@/components/ui/label"
import { Wordmark } from "@/components/wordmark"
import { cn } from "@/lib/utils"
import { PostEngagement, type ReactionSummary } from "@/components/post-engagement"

// --- Types -----------------------------------------------------------------
// Interne visningstyper -- matcher ikke API-et 1:1 (se ApiTournamentInfo/
// ApiSession under og mappingen i PublicTournament), men er det
// presentasjonskomponentene under (uendret fra V0) faktisk konsumerer.

type Session = {
  id: string
  name: string
  format: string
  time?: string // ISO-streng, optional
}

type Sponsor = {
  id: string
  name: string
  url: string
  logoUrl?: string
}

type TournamentInfo = {
  name: string
  club: string
  intro: string
  startDate?: Date
  endDate?: Date
  registered: number
  capacity?: number // undefined = no cap
  heroImageUrl?: string
  sessions: Session[]
  sponsors: Sponsor[]
}

// "waitlisted" fra API-et vises som "waitlist" her -- se mapOutcome().
type Outcome = "confirmed" | "waitlist" | "pending"

// --- API-typer (matcher app/routers/registration.py) -----------------------

type ApiSponsor = { id: string; name: string; url: string | null; logo_url: string | null }

type ApiTournamentInfo = {
  id: string
  name: string
  organization_name: string
  status: string
  visibility: string
  description: string | null
  start_date: string | null
  end_date: string | null
  registration_open: boolean
  registration_deadline: string | null
  registration_capacity: number | null
  confirmed_count: number
  hero_image_url: string | null
  sponsors: ApiSponsor[]
}

type ApiSession = {
  id: string
  name: string
  format: string
  scheduled_at: string | null
}

function mapOutcome(status: string): Outcome {
  return status === "waitlisted" ? "waitlist" : (status as Outcome)
}

// --- Formatting helpers ----------------------------------------------------

const DATE_FMT = new Intl.DateTimeFormat("no-NO", {
  day: "numeric",
  month: "long",
  year: "numeric",
})
const TIME_FMT = new Intl.DateTimeFormat("no-NO", {
  hour: "2-digit",
  minute: "2-digit",
})

function formatDateRange(start?: Date, end?: Date) {
  if (!start) return "Ingen datoer satt"
  if (!end || start.toDateString() === end.toDateString()) {
    return DATE_FMT.format(start)
  }
  return `${DATE_FMT.format(start)} – ${DATE_FMT.format(end)}`
}

// --- Root ------------------------------------------------------------------

export function PublicTournament({ tournamentId, code }: { tournamentId: string; code?: string }) {
  const [info, setInfo] = useState<ApiTournamentInfo | null>(null)
  const [sessions, setSessions] = useState<Session[]>([])
  const [loading, setLoading] = useState(true)
  const [accessError, setAccessError] = useState<string | null>(null)

  // ADR-020: en gyldig invitasjonskode overstyrer turneringens synlighet --
  // føres med på BÅDE lesingen og registreringen (RegistrationCard under),
  // ikke bare det første oppslaget som tok deg hit fra login-skjermet.
  const codeParam = code ? `?code=${encodeURIComponent(code)}` : ""

  useEffect(() => {
    let cancelled = false
    async function load() {
      try {
        const res = await fetch(`/public/tournaments/${tournamentId}${codeParam}`, { credentials: "include" })
        if (res.status === 403 || res.status === 404) {
          const body = await res.json().catch(() => null)
          if (!cancelled) {
            setAccessError(
              body?.detail?.message ??
                (res.status === 404 ? "Turneringen finnes ikke." : "Du har ikke tilgang til denne turneringen."),
            )
          }
          return
        }
        if (!res.ok) throw new Error(`tournament: ${res.status}`)
        const data: ApiTournamentInfo = await res.json()
        if (cancelled) return
        setInfo(data)

        const sessionsRes = await fetch(`/public/tournaments/${tournamentId}/sessions${codeParam}`, {
          credentials: "include",
        })
        if (sessionsRes.ok) {
          const sessionData: ApiSession[] = await sessionsRes.json()
          if (!cancelled) {
            setSessions(
              sessionData.map((s) => ({
                id: s.id,
                name: s.name,
                format: s.format,
                time: s.scheduled_at ?? undefined,
              })),
            )
          }
        }
      } catch {
        if (!cancelled) setAccessError("Klarte ikke å laste turneringen. Prøv å laste siden på nytt.")
      } finally {
        if (!cancelled) setLoading(false)
      }
    }
    void load()
    return () => {
      cancelled = true
    }
  }, [tournamentId, codeParam])

  if (loading) {
    return (
      <div className="flex min-h-[100dvh] flex-col items-center justify-center gap-4 bg-background">
        <div
          aria-hidden="true"
          className="size-10 animate-spin rounded-full border-4 border-primary/20 border-t-primary"
        />
      </div>
    )
  }

  if (accessError || !info) {
    return (
      <div className="flex min-h-[100dvh] flex-col items-center justify-center gap-4 bg-background px-5 text-center">
        <div className="flex size-14 items-center justify-center rounded-2xl bg-muted">
          <ShieldAlert aria-hidden="true" className="size-7 text-muted-foreground" />
        </div>
        <p className="max-w-sm text-sm leading-relaxed text-muted-foreground text-pretty">
          {accessError ?? "Turneringen finnes ikke."}
        </p>
      </div>
    )
  }

  const t: TournamentInfo = {
    name: info.name,
    club: info.organization_name,
    intro: info.description ?? "",
    startDate: info.start_date ? new Date(info.start_date) : undefined,
    endDate: info.end_date ? new Date(info.end_date) : undefined,
    registered: info.confirmed_count,
    capacity: info.registration_capacity ?? undefined,
    heroImageUrl: info.hero_image_url ?? undefined,
    sessions,
    sponsors: info.sponsors.map((s) => ({
      id: s.id,
      name: s.name,
      url: s.url ?? "#",
      logoUrl: s.logo_url ?? undefined,
    })),
  }

  return (
    <div className="flex min-h-[100dvh] flex-col bg-background">
      <header className="border-b border-border bg-background/80 backdrop-blur">
        <div className="mx-auto flex w-full max-w-2xl items-center justify-center px-5 py-4">
          <Wordmark compact />
        </div>
      </header>

      <main className="mx-auto w-full max-w-2xl flex-1 px-5 py-6 sm:py-8">
        <div className="flex flex-col gap-6">
          <Banner name={t.name} club={t.club} imageUrl={t.heroImageUrl} />

          {t.intro && (
            <section aria-label="Om turneringen">
              <p className="text-[15px] leading-relaxed text-foreground text-pretty">{t.intro}</p>
            </section>
          )}

          <StatusArea
            start={t.startDate}
            end={t.endDate}
            registered={t.registered}
            capacity={t.capacity}
            registrationOpen={info.registration_open}
          />

          <Link
            href={`/t/${tournamentId}/live${codeParam}`}
            className="flex items-center justify-between gap-3 rounded-2xl border border-border bg-card p-4 shadow-md shadow-black/8 transition-colors hover:bg-accent/40"
          >
            <div className="flex items-center gap-3">
              <div className="flex size-11 shrink-0 items-center justify-center rounded-xl bg-muted">
                <Trophy aria-hidden="true" className="size-5 text-muted-foreground" />
              </div>
              <span className="text-sm font-bold text-foreground">Følg live -- stilling og matcher</span>
            </div>
            <ChevronRight aria-hidden="true" className="size-5 text-muted-foreground" />
          </Link>

          <Program sessions={t.sessions} />

          {info.registration_open ? (
            <RegistrationCard tournamentId={tournamentId} tournamentName={t.name} code={code} />
          ) : (
            <ClosedCard />
          )}

          <Sponsors sponsors={t.sponsors} />

          <TournamentFeed tournamentId={tournamentId} code={code} />
        </div>
      </main>
    </div>
  )
}

// --- Offentlig runde-feed («Banter Board», ADR-025) -------------------------
//
// LESING er tilgjengelig for alle som kan se selve turneringssiden (samme
// visibility-sjekk som info-kallet over -- får denne siden vist, får du også
// lest feeden). POSTING er strengere (håndheves server-side, ikke gjettet
// her): krever innlogging OG org-medlemskap/deltakelse -- en anonym eller
// uvedkommende bruker ser derfor et forklarende felt i stedet for skjemaet.

type ApiFeedMessage = {
  id: string
  author_user_id: string
  author_display_name: string
  body: string | null
  image_url: string | null
  created_at: string
  reactions: ReactionSummary[]
  comment_count: number
}

const FEED_TIME_FMT = new Intl.DateTimeFormat("no-NO", {
  day: "numeric",
  month: "short",
  hour: "2-digit",
  minute: "2-digit",
})

function feedWsUrl(tournamentId: string, code?: string): string {
  const protocol = window.location.protocol === "https:" ? "wss:" : "ws:"
  const query = code ? `?code=${encodeURIComponent(code)}` : ""
  return `${protocol}//${window.location.host}/ws/public/tournaments/${tournamentId}/feed${query}`
}

function TournamentFeed({ tournamentId, code }: { tournamentId: string; code?: string }) {
  const [messages, setMessages] = useState<ApiFeedMessage[]>([])
  const [loading, setLoading] = useState(true)
  const [text, setText] = useState("")
  const [image, setImage] = useState<File | null>(null)
  const [sending, setSending] = useState(false)
  const [postError, setPostError] = useState<string | null>(null)
  const [currentUserId, setCurrentUserId] = useState<string | null>(null)
  const codeParam = code ? `?code=${encodeURIComponent(code)}` : ""

  // Kun brukt til å avgjøre om PostEngagement skal vise reaksjons-/
  // kommentarfeltet som innlogget (samme "beste innsats" som feed.tsx --
  // selve autorisasjonen håndheves av backend uansett).
  useEffect(() => {
    let cancelled = false
    fetch("/auth/me", { credentials: "include" })
      .then((res) => (res.ok ? res.json() : null))
      .then((data: { id: string } | null) => {
        if (!cancelled && data) setCurrentUserId(data.id)
      })
      .catch(() => {})
    return () => {
      cancelled = true
    }
  }, [])

  useEffect(() => {
    let cancelled = false
    fetch(`/public/tournaments/${tournamentId}/feed${codeParam}`, { credentials: "include" })
      .then((res) => (res.ok ? res.json() : []))
      .then((data: ApiFeedMessage[]) => {
        if (!cancelled) setMessages(data)
      })
      .catch(() => {})
      .finally(() => {
        if (!cancelled) setLoading(false)
      })
    return () => {
      cancelled = true
    }
  }, [tournamentId, codeParam])

  useEffect(() => {
    const socket = new WebSocket(feedWsUrl(tournamentId, code))
    socket.onmessage = (event) => {
      try {
        const msg: ApiFeedMessage = JSON.parse(event.data)
        // Nyeste øverst (2026-08-06) -- legg til FØRST, ikke sist.
        setMessages((prev) => (prev.some((m) => m.id === msg.id) ? prev : [msg, ...prev]))
      } catch {
        // ignorer ugyldig payload
      }
    }
    return () => socket.close()
  }, [tournamentId, code])

  async function send(e: React.FormEvent) {
    e.preventDefault()
    if (!text.trim() && !image) return
    setSending(true)
    setPostError(null)
    try {
      const form = new FormData()
      if (text.trim()) form.set("body", text.trim())
      if (image) form.set("image", image)
      if (code) form.set("code", code)
      const res = await fetch(`/public/tournaments/${tournamentId}/feed`, {
        method: "POST",
        credentials: "include",
        body: form,
      })
      if (res.status === 401) {
        setPostError("Du må logge inn for å poste i feeden.")
        return
      }
      if (res.status === 403) {
        setPostError("Du må være medlem av arrangøren eller delta i turneringen for å poste.")
        return
      }
      if (!res.ok) {
        let message = "Klarte ikke å poste. Prøv igjen."
        try {
          const data = await res.json()
          if (typeof data?.detail?.message === "string") message = data.detail.message
        } catch {
          // Ikke JSON -- behold standardmeldingen.
        }
        setPostError(message)
        return
      }
      const msg: ApiFeedMessage = await res.json()
      // Nyeste øverst (2026-08-06) -- legg til FØRST, ikke sist.
      setMessages((prev) => (prev.some((m) => m.id === msg.id) ? prev : [msg, ...prev]))
      setText("")
      setImage(null)
    } catch {
      setPostError("Klarte ikke å poste. Sjekk tilkoblingen og prøv igjen.")
    } finally {
      setSending(false)
    }
  }

  // Samme grense som storage.MAX_UPLOAD_BYTES (server-siden) -- sjekket
  // klient-side for en umiddelbar, presis feilmelding.
  function handleImageSelected(e: React.ChangeEvent<HTMLInputElement>) {
    const file = e.target.files?.[0]
    if (!file) return
    if (file.size > 20 * 1024 * 1024) {
      setPostError("Bildet er for stort (maks 20 MB). Velg et mindre bilde.")
      e.target.value = ""
      return
    }
    setPostError(null)
    setImage(file)
  }

  return (
    <section aria-label="Runde-feed" className="flex flex-col gap-3 border-t border-border pt-6">
      <div className="flex items-center gap-2">
        <MessageSquare aria-hidden="true" className="size-4 text-primary" />
        <h2 className="text-base font-bold text-foreground">Oppslagstavle</h2>
      </div>

      {loading ? (
        <div className="flex justify-center py-6">
          <div
            aria-hidden="true"
            className="size-6 animate-spin rounded-full border-2 border-primary/20 border-t-primary"
          />
        </div>
      ) : (
        <div className="flex flex-col gap-3">
          {messages.length === 0 && (
            <p className="text-sm text-muted-foreground">Ingenting postet ennå -- bli den første.</p>
          )}
          {messages.map((m) => (
            <div key={m.id} className="rounded-2xl border border-border bg-card p-4 shadow-md shadow-black/8">
              <div className="mb-1.5 flex items-baseline justify-between gap-2">
                <span className="text-sm font-bold text-foreground">{m.author_display_name}</span>
                <span className="shrink-0 text-xs text-muted-foreground">
                  {FEED_TIME_FMT.format(new Date(m.created_at))}
                </span>
              </div>
              {m.image_url && (
                // eslint-disable-next-line @next/next/no-img-element -- images.unoptimized er alt satt
                <img src={m.image_url} alt="" className="mb-2 max-h-72 w-full rounded-xl object-cover" />
              )}
              {m.body && <p className="text-sm leading-relaxed text-foreground text-pretty">{m.body}</p>}

              <PostEngagement
                apiBase={`/public/tournaments/${tournamentId}/feed/${m.id}`}
                currentUserId={currentUserId}
                initialReactions={m.reactions}
                initialCommentCount={m.comment_count}
                canModerate={false}
              />
            </div>
          ))}
        </div>
      )}

      <form onSubmit={send} className="flex flex-col gap-2 rounded-2xl border border-border bg-card p-3">
        {postError && (
          <p role="alert" className="text-xs font-medium text-destructive text-pretty">
            {postError}
          </p>
        )}
        {image && (
          <div className="flex w-fit items-center gap-2 rounded-xl bg-muted px-3 py-1.5 text-xs font-medium text-foreground">
            {image.name}
            <button type="button" onClick={() => setImage(null)} aria-label="Fjern bilde">
              <X aria-hidden="true" className="size-3.5" />
            </button>
          </div>
        )}
        <div className="flex items-center gap-2">
          {/* To atskilte inputs -- Android sin systembilde-vlger (Photo
              Picker) viser ALDRI et kamera-alternativ når accept="image/*"
              mangler capture, uansett nettleser (funnet 2026-08-06, ekte
              enhet). */}
          <input
            type="file"
            accept="image/*"
            capture="environment"
            id="feed-camera-input"
            className="hidden"
            onChange={handleImageSelected}
          />
          <label
            htmlFor="feed-camera-input"
            aria-label="Ta bilde"
            className="flex size-10 shrink-0 cursor-pointer items-center justify-center rounded-xl text-muted-foreground transition-colors hover:bg-accent/60 hover:text-foreground"
          >
            <Camera aria-hidden="true" className="size-5" />
          </label>
          <input
            type="file"
            accept="image/*"
            id="feed-image-input"
            className="hidden"
            onChange={handleImageSelected}
          />
          <label
            htmlFor="feed-image-input"
            aria-label="Velg bilde fra galleri"
            className="flex size-10 shrink-0 cursor-pointer items-center justify-center rounded-xl text-muted-foreground transition-colors hover:bg-accent/60 hover:text-foreground"
          >
            <ImagePlus aria-hidden="true" className="size-5" />
          </label>
          <input
            value={text}
            onChange={(e) => setText(e.target.value)}
            placeholder="Skriv noe til feeden …"
            className="h-10 flex-1 rounded-xl border border-input bg-background px-3 text-sm outline-none focus-visible:ring-2 focus-visible:ring-ring"
          />
          <Button
            type="submit"
            size="icon"
            disabled={sending || (!text.trim() && !image)}
            aria-label="Post"
            className="size-10 shrink-0 rounded-xl"
          >
            <Send aria-hidden="true" className="size-4" />
          </Button>
        </div>
      </form>
    </section>
  )
}

// --- Banner ----------------------------------------------------------------

function Banner({ name, club, imageUrl }: { name: string; club: string; imageUrl?: string }) {
  return (
    <div className="relative overflow-hidden rounded-3xl bg-gradient-to-br from-primary to-primary/80 px-6 py-10 shadow-lg shadow-primary/20 sm:px-8 sm:py-12">
      {imageUrl ? (
        <>
          {/* eslint-disable-next-line @next/next/no-img-element -- images.unoptimized er alt satt, ingen next/image-fordel her */}
          <img
            src={imageUrl}
            alt=""
            aria-hidden="true"
            className="absolute inset-0 size-full object-cover"
          />
          {/* Skrim for lesbar tekst over et vilkårlig opplastet bilde. */}
          <div className="absolute inset-0 bg-gradient-to-t from-black/70 via-black/20 to-black/10" />
        </>
      ) : (
        <>
          {/* Ingen bilde lastet opp ennå -- bevisst permanent fargebanner, ikke en "kommer snart"-plassholder. */}
          <div
            aria-hidden="true"
            className="pointer-events-none absolute -right-16 -top-16 size-56 rounded-full border-[12px] border-primary-foreground/10"
          />
          <div
            aria-hidden="true"
            className="pointer-events-none absolute -bottom-20 -left-10 size-48 rounded-full border-[12px] border-primary-foreground/10"
          />
        </>
      )}
      <div className="relative flex flex-col gap-2">
        <span className="text-sm font-semibold uppercase tracking-wide text-primary-foreground/80">
          {club}
        </span>
        <h1 className="text-3xl font-extrabold leading-tight tracking-tight text-primary-foreground text-balance sm:text-4xl">
          {name}
        </h1>
      </div>
    </div>
  )
}

// --- Status area -----------------------------------------------------------

function StatusArea({
  start,
  end,
  registered,
  capacity,
  registrationOpen,
}: {
  start?: Date
  end?: Date
  registered: number
  capacity?: number
  registrationOpen: boolean
}) {
  const capacityText =
    capacity != null ? `${registered} av ${capacity} plasser` : `${registered} påmeldt`
  const full = capacity != null && registered >= capacity

  return (
    <section className="grid gap-3 sm:grid-cols-2" aria-label="Status">
      <div className="flex items-center gap-3 rounded-2xl border border-border bg-card p-4 shadow-md shadow-black/8">
        <div className="flex size-11 shrink-0 items-center justify-center rounded-xl bg-muted">
          <Calendar aria-hidden="true" className="size-5 text-muted-foreground" />
        </div>
        <div className="flex min-w-0 flex-col">
          <span className="text-xs font-semibold uppercase tracking-wide text-muted-foreground">
            Datoer
          </span>
          <span className="truncate text-sm font-bold text-foreground">
            {formatDateRange(start, end)}
          </span>
        </div>
      </div>

      <div className="flex items-center gap-3 rounded-2xl border border-border bg-card p-4 shadow-md shadow-black/8">
        <div className="flex size-11 shrink-0 items-center justify-center rounded-xl bg-muted">
          <Users aria-hidden="true" className="size-5 text-muted-foreground" />
        </div>
        <div className="flex min-w-0 flex-col">
          <span className="text-xs font-semibold uppercase tracking-wide text-muted-foreground">
            Påmelding
          </span>
          <span className="truncate text-sm font-bold text-foreground">
            {capacityText}
            {!registrationOpen && " · stengt"}
            {registrationOpen && full && " · fullt"}
          </span>
        </div>
      </div>
    </section>
  )
}

// --- Program ---------------------------------------------------------------

function Program({ sessions }: { sessions: Session[] }) {
  return (
    <section aria-label="Program" className="flex flex-col gap-3">
      <h2 className="text-base font-bold text-foreground">Program</h2>
      <ul className="flex flex-col overflow-hidden rounded-2xl border border-border bg-card shadow-md shadow-black/8">
        {sessions.map((s) => {
          const time = s.time ? TIME_FMT.format(new Date(s.time)) : null
          return (
            <li
              key={s.id}
              className="flex items-center gap-4 border-b border-border px-4 py-3.5 last:border-b-0"
            >
              <div className="flex w-14 shrink-0 items-center gap-1.5 tabular-nums">
                {time ? (
                  <span className="text-sm font-bold text-foreground">{time}</span>
                ) : (
                  <span className="text-xs text-muted-foreground">—</span>
                )}
              </div>
              <div className="flex min-w-0 flex-col">
                <span className="truncate font-semibold text-foreground">{s.name}</span>
                <span className="truncate text-sm text-muted-foreground">{s.format}</span>
              </div>
            </li>
          )
        })}
      </ul>
    </section>
  )
}

// --- Sponsors --------------------------------------------------------------

function Sponsors({ sponsors }: { sponsors: Sponsor[] }) {
  if (sponsors.length === 0) return null
  return (
    <section aria-label="Sponsorer" className="flex flex-col gap-3 border-t border-border pt-6">
      <h2 className="text-xs font-semibold uppercase tracking-wide text-muted-foreground">
        Sponsorer
      </h2>
      <div className="flex flex-wrap items-center gap-x-6 gap-y-3">
        {sponsors.map((sp) =>
          sp.logoUrl ? (
            <a key={sp.id} href={sp.url} aria-label={sp.name} className="opacity-80 transition-opacity hover:opacity-100">
              {/* eslint-disable-next-line @next/next/no-img-element -- images.unoptimized er alt satt */}
              <img src={sp.logoUrl} alt={sp.name} className="h-8 w-auto object-contain" />
            </a>
          ) : (
            <a
              key={sp.id}
              href={sp.url}
              className="text-sm font-semibold text-foreground underline-offset-4 transition-colors hover:text-primary hover:underline"
            >
              {sp.name}
            </a>
          ),
        )}
      </div>
    </section>
  )
}

// --- Closed state ----------------------------------------------------------

function ClosedCard() {
  return (
    <section className="flex flex-col items-center gap-3 rounded-3xl border border-border bg-muted/40 px-6 py-8 text-center">
      <div className="flex size-14 items-center justify-center rounded-2xl bg-muted">
        <Lock aria-hidden="true" className="size-7 text-muted-foreground" />
      </div>
      <h2 className="text-xl font-extrabold tracking-tight text-foreground text-balance">
        Påmeldingen er stengt
      </h2>
      <p className="max-w-sm text-sm leading-relaxed text-muted-foreground text-pretty">
        Fristen for å melde seg på denne turneringen har gått ut. Ta kontakt med arrangøren dersom
        du har spørsmål.
      </p>
    </section>
  )
}

// --- Registration ----------------------------------------------------------

function isValidEmail(value: string) {
  return /^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(value.trim())
}

// nb-skjemaets kjønnsvalg -> API-ets ^[mfx]$ (app/routers/players.py).
const GENDER_TO_API: Record<string, string> = { kvinne: "f", mann: "m", annet: "x" }

function RegistrationCard({
  tournamentId,
  tournamentName,
  code,
}: {
  tournamentId: string
  tournamentName: string
  code?: string
}) {
  const [name, setName] = useState("")
  const [email, setEmail] = useState("")
  const [touchedEmail, setTouchedEmail] = useState(false)
  const [showMore, setShowMore] = useState(false)
  const [consent, setConsent] = useState(false)
  const [submitting, setSubmitting] = useState(false)
  const [submitted, setSubmitted] = useState<Outcome | null>(null)
  const [error, setError] = useState<string | null>(null)

  const [optional, setOptional] = useState({
    mobile: "",
    birthDate: "",
    nickname: "",
    country: "",
    club: "",
    membershipNo: "",
    gender: "",
    handicap: "",
  })

  const emailValid = isValidEmail(email)
  const showEmailError = touchedEmail && email.length > 0 && !emailValid
  const canSubmit = name.trim().length >= 2 && emailValid && consent && !submitting

  function updateOptional(key: keyof typeof optional, value: string) {
    setOptional((prev) => ({ ...prev, [key]: value }))
  }

  async function handleSubmit(e: React.FormEvent) {
    e.preventDefault()
    if (!canSubmit) return
    setSubmitting(true)
    setError(null)
    try {
      const hcpRaw = optional.handicap.trim()
      const hcpValue = hcpRaw === "" ? undefined : Number(hcpRaw.replace(",", "."))
      const res = await fetch(`/public/tournaments/${tournamentId}/register`, {
        method: "POST",
        headers: { "Content-Type": "application/json" },
        credentials: "include",
        body: JSON.stringify({
          display_name: name.trim(),
          email: email.trim(),
          mobile: optional.mobile.trim() || undefined,
          birth_date: optional.birthDate || undefined,
          nickname: optional.nickname.trim() || undefined,
          country: optional.country.trim() || undefined,
          club: optional.club.trim() || undefined,
          club_member_number: optional.membershipNo.trim() || undefined,
          gender: GENDER_TO_API[optional.gender],
          handicap_index: hcpValue !== undefined && !Number.isNaN(hcpValue) ? hcpValue : undefined,
          consent,
          code: code || undefined,
        }),
      })
      if (!res.ok) {
        const body = await res.json().catch(() => null)
        throw new Error(body?.detail?.message ?? "Klarte ikke å melde deg på. Prøv igjen.")
      }
      const result: { id: string; status: string } = await res.json()
      setSubmitted(mapOutcome(result.status))
    } catch (err) {
      setError(err instanceof Error ? err.message : "Noe gikk galt. Prøv igjen.")
    } finally {
      setSubmitting(false)
    }
  }

  if (submitted) {
    return <RegistrationOutcome outcome={submitted} name={name} tournamentName={tournamentName} />
  }

  return (
    <section
      aria-label="Påmelding"
      className="flex flex-col gap-6 rounded-3xl border border-border bg-card p-5 shadow-md shadow-black/8 sm:p-6"
    >
      <div className="flex flex-col gap-1">
        <h2 className="text-lg font-extrabold tracking-tight text-foreground">Meld deg på</h2>
        <p className="text-sm leading-relaxed text-muted-foreground text-pretty">
          Fyll inn navn og e-post, så er du i gang. Resten kan du legge til senere.
        </p>
      </div>

      <form onSubmit={handleSubmit} className="flex flex-col gap-5" noValidate>
        <div className="flex flex-col gap-2">
          <Label htmlFor="reg-name" className="text-sm font-semibold">
            Navn
          </Label>
          <Input
            id="reg-name"
            autoComplete="name"
            placeholder="Ola Nordmann"
            value={name}
            onChange={(e) => setName(e.target.value)}
            className="h-13 rounded-2xl text-base"
          />
        </div>

        <div className="flex flex-col gap-2">
          <Label htmlFor="reg-email" className="text-sm font-semibold">
            E-post
          </Label>
          <Input
            id="reg-email"
            type="email"
            inputMode="email"
            autoComplete="email"
            placeholder="deg@epost.no"
            value={email}
            onChange={(e) => setEmail(e.target.value)}
            onBlur={() => setTouchedEmail(true)}
            aria-invalid={showEmailError}
            aria-describedby={showEmailError ? "reg-email-error" : undefined}
            className="h-13 rounded-2xl text-base"
          />
          {showEmailError && (
            <p id="reg-email-error" className="text-sm font-medium text-destructive">
              Skriv inn en gyldig e-postadresse.
            </p>
          )}
        </div>

        {/* Optional details ---------------------------------------------- */}
        <div className="rounded-2xl border border-border">
          <button
            type="button"
            onClick={() => setShowMore((v) => !v)}
            aria-expanded={showMore}
            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="text-sm font-semibold text-foreground">Flere detaljer (valgfritt)</span>
            <ChevronDown
              aria-hidden="true"
              className={cn(
                "size-5 text-muted-foreground transition-transform",
                showMore && "rotate-180",
              )}
            />
          </button>
          {showMore && (
            <div className="flex flex-col gap-4 border-t border-border p-4">
              <div className="grid gap-4 sm:grid-cols-2">
                <OptionalField
                  id="opt-mobile"
                  label="Mobil"
                  type="tel"
                  value={optional.mobile}
                  onChange={(v) => updateOptional("mobile", v)}
                />
                <OptionalField
                  id="opt-birth"
                  label="Fødselsdato"
                  type="date"
                  value={optional.birthDate}
                  onChange={(v) => updateOptional("birthDate", v)}
                />
                <OptionalField
                  id="opt-nick"
                  label="Kallenavn"
                  value={optional.nickname}
                  onChange={(v) => updateOptional("nickname", v)}
                />
                <OptionalField
                  id="opt-country"
                  label="Land"
                  value={optional.country}
                  onChange={(v) => updateOptional("country", v)}
                />
                <OptionalField
                  id="opt-club"
                  label="Klubb"
                  value={optional.club}
                  onChange={(v) => updateOptional("club", v)}
                />
                <OptionalField
                  id="opt-membership"
                  label="Medlemsnummer"
                  value={optional.membershipNo}
                  onChange={(v) => updateOptional("membershipNo", v)}
                />
                <div className="flex flex-col gap-2">
                  <Label htmlFor="opt-gender" className="text-sm font-semibold">
                    Kjønn
                  </Label>
                  <select
                    id="opt-gender"
                    value={optional.gender}
                    onChange={(e) => updateOptional("gender", e.target.value)}
                    className="h-12 rounded-2xl border border-input bg-background px-3 text-base text-foreground outline-none focus-visible:ring-2 focus-visible:ring-ring"
                  >
                    <option value="">Ikke oppgitt</option>
                    <option value="kvinne">Kvinne</option>
                    <option value="mann">Mann</option>
                    <option value="annet">Annet</option>
                  </select>
                </div>
                <OptionalField
                  id="opt-handicap"
                  label="Handicap-indeks"
                  inputMode="decimal"
                  value={optional.handicap}
                  onChange={(v) => updateOptional("handicap", v)}
                />
              </div>
            </div>
          )}
        </div>

        {/* Consent ------------------------------------------------------- */}
        <label className="flex cursor-pointer items-start gap-3 rounded-2xl bg-muted/40 p-4">
          <input
            type="checkbox"
            checked={consent}
            onChange={(e) => setConsent(e.target.checked)}
            className="mt-0.5 size-5 shrink-0 cursor-pointer accent-primary"
          />
          <span className="text-sm leading-relaxed text-foreground text-pretty">
            Jeg samtykker til at mine opplysninger behandles for denne turneringen.
          </span>
        </label>

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

        <Button
          type="submit"
          disabled={!canSubmit}
          className="h-14 rounded-2xl text-base font-bold shadow-sm"
        >
          {submitting ? "Sender …" : "Meld meg på"}
        </Button>
      </form>
    </section>
  )
}

function OptionalField({
  id,
  label,
  value,
  onChange,
  type = "text",
  inputMode,
}: {
  id: string
  label: string
  value: string
  onChange: (value: string) => void
  type?: string
  inputMode?: React.HTMLAttributes<HTMLInputElement>["inputMode"]
}) {
  return (
    <div className="flex flex-col gap-2">
      <Label htmlFor={id} className="text-sm font-semibold">
        {label}
      </Label>
      <Input
        id={id}
        type={type}
        inputMode={inputMode}
        value={value}
        onChange={(e) => onChange(e.target.value)}
        className="h-12 rounded-2xl text-base"
      />
    </div>
  )
}

// --- Registration outcomes -------------------------------------------------

function RegistrationOutcome({
  outcome,
  name,
  tournamentName,
}: {
  outcome: Outcome
  name: string
  tournamentName: string
}) {
  const firstName = name.trim().split(/\s+/)[0] || "der"

  const config = {
    confirmed: {
      icon: CheckCircle2,
      title: "Du er påmeldt!",
      accent: "text-primary",
      iconWrap: "bg-primary/15",
      ring: "border-primary/30",
      body: (
        <>
          Flott, {firstName}! Plassen din i{" "}
          <span className="font-semibold text-foreground">{tournamentName}</span> er bekreftet. Du
          får en bekreftelse på e-post med alle detaljer.
        </>
      ),
    },
    waitlist: {
      icon: Clock3,
      title: "Du står på venteliste",
      accent: "text-brand-orange",
      iconWrap: "bg-brand-orange/15",
      ring: "border-brand-orange/40",
      body: (
        <>
          Turneringen er full akkurat nå, men du er satt på venteliste. Vi gir deg beskjed på e-post
          med en gang en plass blir ledig.
        </>
      ),
    },
    pending: {
      icon: Hourglass,
      title: "Påmeldingen din venter på godkjenning",
      accent: "text-foreground",
      iconWrap: "bg-muted",
      ring: "border-border",
      body: (
        <>
          Takk, {firstName}! Arrangøren må godkjenne påmeldingen din før plassen er bekreftet. Du får
          en e-post så snart den er behandlet.
        </>
      ),
    },
  }[outcome]

  const Icon = config.icon

  return (
    <section
      aria-live="polite"
      className={cn(
        "flex flex-col items-center gap-4 rounded-3xl border bg-card px-6 py-9 text-center shadow-md shadow-black/8",
        config.ring,
      )}
    >
      <div className={cn("flex size-16 items-center justify-center rounded-2xl", config.iconWrap)}>
        <Icon aria-hidden="true" className={cn("size-8", config.accent)} />
      </div>
      <h2 className="text-2xl font-extrabold tracking-tight text-foreground text-balance">
        {config.title}
      </h2>
      <p className="max-w-md text-sm leading-relaxed text-muted-foreground text-pretty">
        {config.body}
      </p>
    </section>
  )
}

