"use client"

import type React from "react"
import { useEffect, useId, useRef, useState } from "react"
import { Download, Printer } from "lucide-react"
import { cn } from "@/lib/utils"
import {
  fetchCourseHoles,
  fetchMatches,
  fetchRoundGroups,
  fetchRoundParticipants,
  fetchRounds,
  fetchSessions,
  fetchTeams,
  fetchTournament,
  fetchTournamentParticipants,
  mockHoleLength,
  type ApiCourseHole,
  type ApiMatch,
  type ApiRound,
  type ApiRoundGroup,
  type ApiRoundParticipant,
  type ApiSession,
  type ApiTeam,
  type ApiTournament,
  type ApiTournamentParticipant,
} from "@/lib/print-data"

/**
 * Print-friendly, tradisjonelt golf-SCOREKORT -- ekte data (ADR-097).
 *
 * Videreført fra V0-mockupen (samme sheet-mekanikk: A4/Letter/A5,
 * portrett/landskap, per-felt-toggles, én sheet PER UTSLAGSGRUPPE
 * (individuell) eller PER MATCH (Cup) -- en organisator skriver ut kort for
 * HELE feltet på én gang, ikke ett enkelt eksempelkort.
 *
 * Hullengde finnes ikke i datamodellen ennå (bevisst utsatt, se
 * FEATURE_BACKLOG.md) -- mockHoleLength() brukes akkurat som i selve
 * V0-utskriftspromptene, ikke lenger her.
 */

const PAPER = {
  A4: { w: 210, h: 297 },
  Letter: { w: 216, h: 279 },
  A5: { w: 148, h: 210 },
} as const
type PaperKey = keyof typeof PAPER
type Orientation = "portrait" | "landscape"
type PerSheet = 1 | 2

type SheetPlayer = {
  name: string
  hcpLabel: string
  phcp: number | null
  teeName: string | null
  className: string | null
  teamName?: string
  teamColor?: string | null
}
type Sheet = { title: string; sublabel: string; players: SheetPlayer[] }

type FieldOpts = { netto: boolean; strokes: boolean; putts: boolean; stableford: boolean; matchplay: boolean }

function strokesOnHole(phcp: number, idx: number): number {
  const base = Math.floor(phcp / 18)
  const extra = phcp % 18
  return base + (idx <= extra ? 1 : 0)
}

function ReceivedDots({ count }: { count: number }) {
  if (count <= 0) return null
  if (count >= 3) return <span className="text-[7px] font-bold leading-none text-neutral-500">{count}•</span>
  return (
    <span className="flex gap-0.5">
      {Array.from({ length: count }).map((_, i) => (
        <span key={i} className="size-[3px] rounded-full bg-neutral-600" />
      ))}
    </span>
  )
}

function GridCell({
  children,
  wide,
  shaded,
  header,
  className,
}: {
  children?: React.ReactNode
  wide?: boolean
  shaded?: boolean
  header?: boolean
  className?: string
}) {
  return (
    <td
      className={cn(
        "border border-neutral-400 text-center align-middle",
        shaded && "bg-neutral-100",
        header ? "font-bold" : "",
        className,
      )}
    >
      {children}
    </td>
  )
}

function LabelCell({ children, shaded }: { children: React.ReactNode; shaded?: boolean }) {
  return (
    <td className={cn("border border-neutral-400 px-2 text-left align-middle text-[11px]", shaded && "bg-neutral-100")}>
      {children}
    </td>
  )
}

// -------------------------- selve sheet-rendering --------------------------

function ScorecardSheet({ sheet, holes, fields, dense }: { sheet: Sheet; holes: ApiCourseHole[]; fields: FieldOpts; dense: boolean }) {
  const splitInOut = holes.length > 9
  const out = splitInOut ? holes.slice(0, 9) : holes
  const inn = splitInOut ? holes.slice(9) : []
  const outPar = out.reduce((s, h) => s + h.par, 0)
  const inPar = inn.reduce((s, h) => s + h.par, 0)
  const totalPar = outPar + inPar

  const W_LABEL = 150
  const W_HOLE = 42
  const W_SUM = 50
  const sumCols = splitInOut ? 3 : 1
  const colUnits = W_LABEL + holes.length * W_HOLE + sumCols * W_SUM
  const pctLabel = `${(W_LABEL / colUnits) * 100}%`
  const pctHole = `${(W_HOLE / colUnits) * 100}%`
  const pctSum = `${(W_SUM / colUnits) * 100}%`

  function HoleCells({ render }: { render: (kind: "hole" | "out" | "in" | "total", hole?: ApiCourseHole) => React.ReactNode }) {
    if (!splitInOut) {
      return (
        <>
          {holes.map((h) => (
            <GridCell key={`h-${h.hole_number}`}>{render("hole", h)}</GridCell>
          ))}
          <GridCell wide shaded>
            {render("total")}
          </GridCell>
        </>
      )
    }
    return (
      <>
        {out.map((h) => (
          <GridCell key={`o-${h.hole_number}`}>{render("hole", h)}</GridCell>
        ))}
        <GridCell wide shaded>
          {render("out")}
        </GridCell>
        {inn.map((h) => (
          <GridCell key={`i-${h.hole_number}`}>{render("hole", h)}</GridCell>
        ))}
        <GridCell wide shaded>
          {render("in")}
        </GridCell>
        <GridCell wide shaded>
          {render("total")}
        </GridCell>
      </>
    )
  }

  function PlayerRow({ player }: { player: SheetPlayer }) {
    const sub = (
      <>
        HCP {player.hcpLabel} · {player.teeName ?? "—"}
        {player.className ? <> · Kl. {player.className}</> : null}
        {player.teamName ? (
          <>
            {" · "}
            <span className="inline-flex items-center gap-1">
              <span className="inline-block size-2 rounded-sm" style={{ backgroundColor: player.teamColor ?? "#a3a3a3" }} />
              {player.teamName}
            </span>
          </>
        ) : null}
      </>
    )
    return (
      <>
        <tr>
          <LabelCell>
            <div className="flex flex-col leading-tight">
              <span className="font-bold text-neutral-900">{player.name}</span>
              <span className="text-[9px] text-neutral-500">{sub}</span>
            </div>
          </LabelCell>
          <HoleCells
            render={(kind, hole) => {
              if (kind !== "hole") return null
              if (fields.strokes && hole && player.phcp != null) {
                const s = strokesOnHole(player.phcp, hole.stroke_index)
                return (
                  <div className="relative h-full w-full" style={{ minHeight: 24 }}>
                    <span className="absolute left-0.5 top-0.5">
                      <ReceivedDots count={s} />
                    </span>
                  </div>
                )
              }
              return <div style={{ minHeight: 24 }} />
            }}
          />
        </tr>
        {fields.netto ? (
          <tr>
            <LabelCell shaded>
              <span className="text-[10px] italic text-neutral-600">Netto</span>
            </LabelCell>
            <HoleCells render={() => <div style={{ minHeight: 16 }} />} />
          </tr>
        ) : null}
        {fields.putts ? (
          <tr>
            <LabelCell shaded>
              <span className="text-[10px] italic text-neutral-600">Putts</span>
            </LabelCell>
            <HoleCells render={() => <div style={{ minHeight: 16 }} />} />
          </tr>
        ) : null}
        {fields.stableford ? (
          <tr>
            <LabelCell shaded>
              <span className="text-[10px] italic text-neutral-600">Poeng</span>
            </LabelCell>
            <HoleCells render={() => <div style={{ minHeight: 16 }} />} />
          </tr>
        ) : null}
      </>
    )
  }

  return (
    <div className={cn("flex h-full flex-col text-neutral-900", dense ? "gap-2 p-4" : "gap-3 p-6")}>
      <header className="flex items-end justify-between border-b-2 border-neutral-800 pb-2">
        <div className="flex flex-col">
          <span className={cn("font-extrabold leading-none", dense ? "text-sm" : "text-lg")}>{sheet.title}</span>
          <span className={cn("text-neutral-600", dense ? "text-[11px]" : "text-sm")}>{sheet.sublabel}</span>
        </div>
        <div className="text-right text-[11px] text-neutral-600">
          <div>Offisielt scorekort — fylles ut for hånd</div>
        </div>
      </header>

      <table className="w-full border-collapse text-[11px]" style={{ tableLayout: "fixed" }}>
        <colgroup>
          <col style={{ width: pctLabel }} />
          {holes.map((h) => (
            <col key={`c-${h.hole_number}`} style={{ width: pctHole }} />
          ))}
          {splitInOut ? <col style={{ width: pctSum }} /> : null}
          {splitInOut ? <col style={{ width: pctSum }} /> : null}
          <col style={{ width: pctSum }} />
        </colgroup>
        <tbody>
          <tr>
            <LabelCell shaded>
              <span className="font-bold uppercase tracking-wide text-neutral-700">Hull</span>
            </LabelCell>
            <HoleCells
              render={(kind, hole) => {
                if (kind === "hole") return <span className="font-bold">{hole!.hole_number}</span>
                if (kind === "out") return <span className="font-extrabold">Ut</span>
                if (kind === "in") return <span className="font-extrabold">Inn</span>
                return <span className="font-extrabold">{splitInOut ? "Tot" : "Sum"}</span>
              }}
            />
          </tr>
          <tr>
            <LabelCell shaded>
              <span className="font-bold text-neutral-700">Par</span>
            </LabelCell>
            <HoleCells
              render={(kind, hole) => {
                if (kind === "hole") return hole!.par
                if (kind === "out") return <span className="font-bold">{outPar}</span>
                if (kind === "in") return <span className="font-bold">{inPar}</span>
                return <span className="font-bold">{totalPar}</span>
              }}
            />
          </tr>
          <tr>
            <LabelCell shaded>
              <span className="text-[10px] text-neutral-600">Indeks</span>
            </LabelCell>
            <HoleCells render={(kind, hole) => (kind === "hole" ? <span className="text-neutral-500">{hole!.stroke_index}</span> : null)} />
          </tr>
          <tr>
            <LabelCell shaded>
              <span className="text-[9px] text-neutral-500">Meter</span>
            </LabelCell>
            <HoleCells
              render={(kind, hole) => (kind === "hole" ? <span className="text-[9px] text-neutral-400">{mockHoleLength(hole!.par, hole!.hole_number)}</span> : null)}
            />
          </tr>

          {sheet.players.map((p, i) => (
            <PlayerRow key={i} player={p} />
          ))}

          {fields.matchplay ? (
            <tr>
              <LabelCell shaded>
                <span className="text-[10px] font-bold text-neutral-700">Match-status</span>
                <div className="text-[8px] text-neutral-500">f.eks. «2 opp», «AS»</div>
              </LabelCell>
              <HoleCells render={() => <div style={{ minHeight: 20 }} />} />
            </tr>
          ) : null}
        </tbody>
      </table>

      {fields.strokes ? (
        <p className="text-[9px] text-neutral-500">
          Mottatte slag: <span className="mx-0.5 inline-block size-[3px] rounded-full bg-neutral-600 align-middle" /> = ett slag,{" "}
          <span className="mx-0.5 inline-block size-[3px] rounded-full bg-neutral-600 align-middle" />
          <span className="mr-0.5 inline-block size-[3px] rounded-full bg-neutral-600 align-middle" /> = to slag (tall ved 3+).
        </p>
      ) : null}

      <div className="mt-auto grid grid-cols-2 gap-x-8 gap-y-3 border-t border-neutral-300 pt-3">
        {sheet.players.map((p, i) => (
          <div key={i} className="flex items-end gap-2">
            <div className="flex-1">
              <div className="h-5 border-b border-neutral-500" />
              <span className="text-[9px] text-neutral-600">Spillerens signatur — {p.name}</span>
            </div>
            <div className="w-24">
              <div className="h-5 border-b border-neutral-500" />
              <span className="text-[9px] text-neutral-600">Dato</span>
            </div>
          </div>
        ))}
        <div className="col-span-2 flex items-end gap-2">
          <div className="flex-1">
            <div className="h-5 border-b border-neutral-500" />
            <span className="text-[9px] text-neutral-600">Markørens signatur</span>
          </div>
          <div className="w-24">
            <div className="h-5 border-b border-neutral-500" />
            <span className="text-[9px] text-neutral-600">Dato</span>
          </div>
        </div>
      </div>
    </div>
  )
}

function ScaledSheet({ paper, orientation, children }: { paper: PaperKey; orientation: Orientation; children: React.ReactNode }) {
  const containerRef = useRef<HTMLDivElement>(null)
  const [scale, setScale] = useState(1)
  const base = PAPER[paper]
  const wMm = orientation === "landscape" ? base.h : base.w
  const hMm = orientation === "landscape" ? base.w : base.h
  const PX_PER_MM = 3.7795
  const sheetWpx = wMm * PX_PER_MM
  const sheetHpx = hMm * PX_PER_MM

  useEffect(() => {
    const el = containerRef.current
    if (!el) return
    const ro = new ResizeObserver(() => setScale(Math.min(1, el.clientWidth / sheetWpx)))
    ro.observe(el)
    return () => ro.disconnect()
  }, [sheetWpx])

  return (
    <div ref={containerRef} className="w-full print:contents">
      <div style={{ height: sheetHpx * scale }} className="mx-auto print:hidden">
        <div
          className="origin-top-left overflow-hidden bg-white shadow-lg ring-1 ring-neutral-300"
          style={{ width: sheetWpx, minHeight: sheetHpx, transform: `scale(${scale})` }}
        >
          {children}
        </div>
      </div>
      <div className="hidden print:block print:break-after-page" style={{ width: `${wMm}mm`, minHeight: `${hMm}mm` }}>
        {children}
      </div>
    </div>
  )
}

function PanelSection({ title, children }: { title: string; children: React.ReactNode }) {
  return (
    <section className="flex flex-col gap-2">
      <h3 className="text-xs font-bold uppercase tracking-wide text-muted-foreground">{title}</h3>
      {children}
    </section>
  )
}

function Segmented<T extends string>({
  label,
  value,
  onChange,
  options,
}: {
  label: string
  value: T
  onChange: (v: T) => void
  options: { value: T; label: string; disabled?: boolean }[]
}) {
  return (
    <div role="radiogroup" aria-label={label} className="flex flex-wrap gap-1 rounded-xl bg-muted p-1">
      {options.map((o) => {
        const active = o.value === value
        return (
          <button
            key={o.value}
            type="button"
            role="radio"
            aria-checked={active}
            disabled={o.disabled}
            onClick={() => onChange(o.value)}
            className={cn(
              "min-h-9 flex-1 rounded-lg px-3 text-sm font-bold transition-colors",
              "focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 focus-visible:ring-offset-background",
              active ? "bg-card text-foreground shadow-sm" : "text-muted-foreground hover:text-foreground",
              o.disabled && "cursor-not-allowed opacity-40 hover:text-muted-foreground",
            )}
          >
            {o.label}
          </button>
        )
      })}
    </div>
  )
}

function Toggle({ label, hint, checked, onChange }: { label: string; hint?: string; checked: boolean; onChange: (v: boolean) => void }) {
  return (
    <label className="flex items-center justify-between gap-3 rounded-xl border border-border bg-card px-3 py-2.5">
      <span className="flex flex-col">
        <span className="text-sm font-bold text-foreground">{label}</span>
        {hint ? <span className="text-xs text-muted-foreground">{hint}</span> : null}
      </span>
      <button
        type="button"
        role="switch"
        aria-checked={checked}
        aria-label={label}
        onClick={() => onChange(!checked)}
        className={cn(
          "relative h-6 w-11 shrink-0 rounded-full transition-colors",
          "focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 focus-visible:ring-offset-background",
          checked ? "bg-primary" : "bg-muted-foreground/30",
        )}
      >
        <span className={cn("absolute top-0.5 size-5 rounded-full bg-card shadow transition-all", checked ? "left-[22px]" : "left-0.5")} />
      </button>
    </label>
  )
}

// -------------------------- data-lasting + hovedkomponent --------------------------

export function PrintScorecard({
  organizationId,
  tournamentId,
  roundId,
  sessionId,
  initialPaper = "A4",
  initialOrientation = "landscape",
}: {
  organizationId: string
  tournamentId: string
  roundId?: string
  sessionId?: string
  initialPaper?: PaperKey
  initialOrientation?: Orientation
}) {
  const [loading, setLoading] = useState(true)
  const [error, setError] = useState<string | null>(null)
  const [tournament, setTournament] = useState<ApiTournament | null>(null)
  const [holes, setHoles] = useState<ApiCourseHole[]>([])
  const [sheets, setSheets] = useState<Sheet[]>([])
  const [contextLabel, setContextLabel] = useState("")

  const [paper, setPaper] = useState<PaperKey>(initialPaper)
  const [orientation, setOrientation] = useState<Orientation>(initialOrientation)
  const [perSheet, setPerSheet] = useState<PerSheet>(1)
  const [fields, setFields] = useState<FieldOpts>({
    netto: false,
    strokes: true,
    putts: false,
    stableford: false,
    matchplay: sessionId != null,
  })
  const [downloading, setDownloading] = useState(false)
  const styleId = useId()

  useEffect(() => {
    let cancelled = false
    async function load() {
      setLoading(true)
      setError(null)
      try {
        const t = await fetchTournament(organizationId, tournamentId)
        if (cancelled) return
        setTournament(t)

        if (roundId) {
          const [rounds, groupsRes, roundParticipants, tournamentParticipants] = await Promise.all([
            fetchRounds(organizationId, tournamentId),
            fetchRoundGroups(organizationId, tournamentId, roundId),
            fetchRoundParticipants(organizationId, tournamentId, roundId),
            fetchTournamentParticipants(organizationId, tournamentId),
          ])
          const round = rounds.find((r: ApiRound) => r.id === roundId) ?? null
          if (!round) throw new Error("Fant ikke runden.")
          const courseHoles = await fetchCourseHoles(organizationId, round.course_id)
          const playedHoles = filterHolesByConfig(courseHoles, round.hole_config)

          const rpById = new Map<string, ApiRoundParticipant>(roundParticipants.map((rp) => [rp.id, rp]))
          const tpById = new Map<string, ApiTournamentParticipant>(tournamentParticipants.map((tp) => [tp.id, tp]))

          const builtSheets: Sheet[] = groupsRes.groups.map((g: ApiRoundGroup, i: number) => ({
            title: t?.name ?? "Turnering",
            sublabel: `${round.name} · ${round.course_name} · Gruppe ${g.sequence ?? i + 1}`,
            players: g.participants.map((gp) => {
              const rp = rpById.get(gp.round_participant_id)
              const tp = rp ? tpById.get(rp.tournament_participant_id) : undefined
              return {
                name: gp.player_name,
                hcpLabel: tp?.handicap_index_snapshot != null ? tp.handicap_index_snapshot.toFixed(1).replace(".", ",") : "–",
                phcp: rp?.playing_handicap ?? null,
                teeName: rp?.tee_name ?? null,
                className: tp?.class_name ?? null,
              }
            }),
          }))

          if (cancelled) return
          setHoles(playedHoles)
          setContextLabel(`${round.name} · Individuell slagspill`)
          setSheets(builtSheets)
        } else if (sessionId) {
          const [sessions, matches, teams] = await Promise.all([
            fetchSessions(organizationId, tournamentId),
            fetchMatches(organizationId, sessionId),
            fetchTeams(organizationId, tournamentId),
          ])
          const session = sessions.find((s: ApiSession) => s.id === sessionId) ?? null
          if (!session) throw new Error("Fant ikke økten.")
          const courseHoles = await fetchCourseHoles(organizationId, session.course_id)
          const playedHoles = filterHolesByConfig(courseHoles, session.hole_config)
          const teamById = new Map<string, ApiTeam>(teams.map((tm) => [tm.id, tm]))

          const builtSheets: Sheet[] = matches.map((m: ApiMatch) => {
            const teamA = teamById.get(m.team_a_id)
            const teamB = teamById.get(m.team_b_id)
            const players: SheetPlayer[] = m.participants.map((mp) => ({
              name: mp.player_name,
              hcpLabel: mp.playing_handicap != null ? String(mp.playing_handicap) : "–",
              phcp: mp.playing_handicap,
              teeName: mp.tee_name,
              className: null,
              teamName: mp.team_side === "a" ? teamA?.name : teamB?.name,
              teamColor: mp.team_side === "a" ? teamA?.color : teamB?.color,
            }))
            return {
              title: t?.name ?? "Turnering",
              sublabel: `${session.name} · ${session.format} · Match ${m.sequence}`,
              players,
            }
          })

          if (cancelled) return
          setHoles(playedHoles)
          setContextLabel(`${session.name} · Cup-format · Matchplay`)
          setSheets(builtSheets)
        } else {
          throw new Error("Mangler runde- eller økt-ID.")
        }
      } catch {
        if (!cancelled) setError("Klarte ikke å laste data for scorekortet. Prøv igjen.")
      } finally {
        if (!cancelled) setLoading(false)
      }
    }
    void load()
    return () => {
      cancelled = true
    }
  }, [organizationId, tournamentId, roundId, sessionId])

  function choosePaper(p: PaperKey) {
    setPaper(p)
    if (p === "A5") {
      setPerSheet(1)
      setOrientation("landscape")
    }
  }
  function choosePerSheet(n: PerSheet) {
    setPerSheet(n)
    if (n === 2) setOrientation("portrait")
  }

  const twoUp = perSheet === 2
  const dense = twoUp || paper === "A5"
  const base = PAPER[paper]
  const pageSize = `${base.w}mm ${base.h}mm ${orientation}`

  async function downloadPdf() {
    setDownloading(true)
    try {
      const res = await fetch(`/orgs/${organizationId}/print/pdf`, {
        method: "POST",
        headers: { "Content-Type": "application/json" },
        credentials: "include",
        body: JSON.stringify({
          kind: "scorecard",
          tournament_id: tournamentId,
          round_id: roundId ?? null,
          session_id: sessionId ?? null,
          paper,
          orientation,
        }),
      })
      if (!res.ok) throw new Error()
      const blob = await res.blob()
      const url = URL.createObjectURL(blob)
      const a = document.createElement("a")
      a.href = url
      a.download = "teecup-scorekort.pdf"
      document.body.appendChild(a)
      a.click()
      a.remove()
      URL.revokeObjectURL(url)
    } catch {
      setError("Klarte ikke å generere PDF-en. Prøv igjen.")
    } finally {
      setDownloading(false)
    }
  }

  const ready = !loading

  return (
    <div className="min-h-screen bg-background text-foreground" data-print-ready={ready ? "true" : undefined}>
      <style>{`@media print { @page { size: ${pageSize}; margin: 8mm; } }`}</style>
      <div id={styleId} className="mx-auto flex max-w-[1400px] flex-col gap-6 p-4 lg:flex-row lg:p-6 print:block print:p-0">
        <aside className="flex w-full shrink-0 flex-col gap-5 rounded-2xl border border-border bg-card p-4 lg:w-80 print:hidden">
          <div className="flex items-center gap-2">
            <span className="flex size-9 items-center justify-center rounded-xl bg-primary/10 text-primary">
              <Printer aria-hidden="true" className="size-5" />
            </span>
            <div className="flex flex-col">
              <h2 className="text-base font-extrabold leading-none text-foreground">Skriv ut scorekort</h2>
              <span className="text-xs text-muted-foreground">{contextLabel || "Fysisk kort til bruk på banen"}</span>
            </div>
          </div>

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

          <PanelSection title="Papir">
            <Segmented label="Papirstørrelse" value={paper} onChange={choosePaper} options={[
              { value: "A4", label: "A4" },
              { value: "Letter", label: "Letter" },
              { value: "A5", label: "A5" },
            ]} />
            <Segmented
              label="Arkoppsett"
              value={String(perSheet) as "1" | "2"}
              onChange={(v) => choosePerSheet(Number(v) as PerSheet)}
              options={[
                { value: "1", label: "Ett kort" },
                { value: "2", label: "To kort per ark", disabled: paper === "A5" },
              ]}
            />
            <Segmented label="Retning" value={orientation} onChange={setOrientation} options={[
              { value: "landscape", label: "Landskap" },
              { value: "portrait", label: "Portrett" },
            ]} />
          </PanelSection>

          <PanelSection title="Valgfrie felt">
            <div className="flex flex-col gap-2">
              <Toggle label="Nettoscore-rad" hint="Tom rad under bruttoraden" checked={fields.netto} onChange={(v) => setFields((f) => ({ ...f, netto: v }))} />
              <Toggle label="Mottatte slag (prikker)" hint="Prikker over hull-cellen" checked={fields.strokes} onChange={(v) => setFields((f) => ({ ...f, strokes: v }))} />
              <Toggle label="Putts-rad" checked={fields.putts} onChange={(v) => setFields((f) => ({ ...f, putts: v }))} />
              <Toggle label="Stableford-poeng" checked={fields.stableford} onChange={(v) => setFields((f) => ({ ...f, stableford: v }))} />
              {sessionId ? (
                <Toggle label="Matchplay-status" hint="Statusrad per hull" checked={fields.matchplay} onChange={(v) => setFields((f) => ({ ...f, matchplay: v }))} />
              ) : null}
            </div>
          </PanelSection>

          <button
            type="button"
            onClick={downloadPdf}
            disabled={downloading || loading || sheets.length === 0}
            className={cn(
              "mt-1 flex min-h-11 w-full items-center justify-center gap-2 rounded-xl bg-primary px-4 font-bold text-primary-foreground shadow-sm transition-colors",
              "hover:bg-primary/90 focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 focus-visible:ring-offset-background disabled:opacity-60",
            )}
          >
            <Download aria-hidden="true" className="size-4" />
            {downloading ? "Genererer …" : "Last ned PDF"}
          </button>
          <p className="text-center text-[11px] text-muted-foreground">
            {sheets.length > 0 ? `${sheets.length} kort i denne utskriften.` : loading ? "Laster …" : "Ingen grupper/matcher å skrive ut ennå."}
          </p>
        </aside>

        <main className="min-w-0 flex-1 print:w-full">
          <div className="rounded-2xl border border-border bg-muted/40 p-4 lg:p-8 print:border-0 print:bg-transparent print:p-0">
            {loading ? (
              <p className="p-8 text-center text-sm text-muted-foreground">Laster scorekort …</p>
            ) : sheets.length === 0 ? (
              <p className="p-8 text-center text-sm text-muted-foreground">Ingen grupper eller matcher funnet for denne runden/økten ennå.</p>
            ) : twoUp ? (
              chunk(sheets, 2).map((pair, i) => (
                <div key={i} className="mb-6 last:mb-0">
                  <ScaledSheet paper={paper} orientation={orientation}>
                    <TwoUp orientation={orientation}>
                      <ScorecardSheet sheet={pair[0]} holes={holes} fields={fields} dense />
                      {pair[1] ? <ScorecardSheet sheet={pair[1]} holes={holes} fields={fields} dense /> : <div />}
                    </TwoUp>
                  </ScaledSheet>
                </div>
              ))
            ) : (
              sheets.map((sheet, i) => (
                <div key={i} className="mb-6 last:mb-0">
                  <ScaledSheet paper={paper} orientation={orientation}>
                    <ScorecardSheet sheet={sheet} holes={holes} fields={fields} dense={dense} />
                  </ScaledSheet>
                </div>
              ))
            )}
          </div>
        </main>
      </div>
    </div>
  )
}

function TwoUp({ orientation, children }: { orientation: Orientation; children: React.ReactNode[] | React.ReactNode }) {
  const stackVertical = orientation === "portrait"
  const kids = Array.isArray(children) ? children : [children]
  return (
    <div className={cn("flex h-full w-full", stackVertical ? "flex-col" : "flex-row")}>
      <div className="min-h-0 min-w-0 flex-1 overflow-hidden">{kids[0]}</div>
      <div
        className={cn(
          "relative flex shrink-0 items-center justify-center",
          stackVertical ? "h-0 w-full border-t border-dashed border-neutral-400" : "h-full w-0 border-l border-dashed border-neutral-400",
        )}
      >
        <span className={cn("absolute bg-white px-1 text-[9px] text-neutral-400", stackVertical ? "left-2" : "top-2 -rotate-90")}>
          {"✂"} klipp/brett her
        </span>
      </div>
      <div className="min-h-0 min-w-0 flex-1 overflow-hidden">{kids[1]}</div>
    </div>
  )
}

function chunk<T>(arr: T[], size: number): T[][] {
  const out: T[][] = []
  for (let i = 0; i < arr.length; i += size) out.push(arr.slice(i, i + size))
  return out
}

function filterHolesByConfig(holes: ApiCourseHole[], config: "full_18" | "front_9" | "back_9"): ApiCourseHole[] {
  const sorted = [...holes].sort((a, b) => a.hole_number - b.hole_number)
  if (config === "front_9") return sorted.filter((h) => h.hole_number <= 9)
  if (config === "back_9") return sorted.filter((h) => h.hole_number > 9)
  return sorted
}
