"use client"

// Tredjeparts/offentlig live-visning av en frittstående runde (ADR-036
// fase 2, 2026-07-28) -- der en venn (i en synlig kategori) eller alle
// (visibility_mode='public') kan følge runden UTEN å være eier/deltaker.
// Ferskbygget, IKKE en gjenbruk av round-detail.tsx/round-leaderboard.tsx
// (som antar eier-/deltaker-tilgang og full skrive-UI) -- denne siden er
// rendyrket lesevisning mot de nye /public/rounds/*-endepunktene, som
// fungerer like fint anonymt som innlogget (get_current_user_optional).
//
// Tre distinkte presentasjoner avhengig av play_format, samme inndeling
// som round-leaderboard.tsx sin TWO_SIDED_FORMATS-logikk:
// - Slagspill: individuell rangering (brutto til par).
// - Skins: skins-tavle (hvem har vunnet flest skins).
// - Match/fourball/foursome/greensome/scramble: matchstatus + hull-merker.

import { useEffect, useState } from "react"
import Link from "next/link"
import { Radio, Trophy } from "lucide-react"
import { Badge } from "@/components/ui/badge"
import { cn } from "@/lib/utils"

type ApiSide = { id: string; label: string | null }

type ApiParticipant = {
  id: string
  display_name: string
  is_owner: boolean
}

type ApiRound = {
  id: string
  name: string | null
  course_name_snapshot: string
  tee_name_snapshot: string
  played_at: string
  play_format: string
  completed_at: string | null
  owner_display_name: string
  participants: ApiParticipant[]
  sides: ApiSide[]
}

type ApiLeaderboardEntry = {
  participant_id: string
  display_name: string
  holes_played: number
  total_score: number | null
  score_to_par: number | null
}

type ApiLeaderboard = { holes_planned: number; completed: boolean; entries: ApiLeaderboardEntry[] }

type ApiFormatResult = {
  play_format: string
  ready: boolean
  match_lead: number | null
  match_holes_played: number | null
  match_holes_remaining: number | null
  match_is_closed: boolean | null
  match_is_dormie: boolean | null
  match_status_text: string | null
  hole_results: string[] | null
  skins_won: Record<string, number> | null
}

// Territorium-bar (2026-07-29, samme visuelle språk som identitetsbanneret i
// round-detail.tsx/round-scorecard.tsx/session-scorecard.tsx/round-
// leaderboard.tsx) -- ingen navn her (vises andre steder på siden), kun
// fargesonene + den sentrerte statuspillen, for full visuell konsistens.
function leadZoneFraction(lead: number, totalHoles: number): number {
  if (totalHoles <= 0) return 0.5
  const fraction = 0.5 + (lead / totalHoles) * 0.5
  return Math.min(0.82, Math.max(0.18, fraction))
}

const FORMAT_LABELS: Record<string, string> = {
  stroke: "Slagspill",
  stableford: "Stableford",
  match: "Match",
  skins: "Skins",
  fourball: "Fourball",
  foursome: "Foursome",
  greensome: "Greensome",
  scramble_2: "Scramble (2)",
  scramble_4: "Scramble (4)",
}
const TWO_SIDED_FORMATS = new Set(["match", "fourball", "foursome", "greensome", "scramble_2", "scramble_4"])

const dateFormatter = new Intl.DateTimeFormat("no-NO", { day: "numeric", month: "long", year: "numeric" })

function formatToPar(value: number): string {
  if (value === 0) return "E"
  return value > 0 ? `+${value}` : `−${Math.abs(value)}`
}

function substituteSideLabels(text: string, sides: ApiSide[]): string {
  const labelFor = (idx: number) => sides[idx]?.label?.trim() || `Side ${idx === 0 ? "A" : "B"}`
  return text.replace(/\(A\)/, `(${labelFor(0)})`).replace(/\(B\)/, `(${labelFor(1)})`)
}

// --- Slagspill: individuell rangering ---------------------------------------

function StrokeLeaderboard({ leaderboard }: { leaderboard: ApiLeaderboard }) {
  const ranked = [...leaderboard.entries].sort((a, b) => {
    if (a.score_to_par === null) return 1
    if (b.score_to_par === null) return -1
    return a.score_to_par - b.score_to_par
  })
  return (
    <ul className="flex flex-col divide-y divide-border overflow-hidden rounded-2xl border border-border bg-card">
      {ranked.map((entry, i) => (
        <li key={entry.participant_id} className="flex items-center gap-3 p-3 sm:p-4">
          <span
            className={cn(
              "flex size-9 shrink-0 items-center justify-center rounded-full text-sm font-extrabold tabular-nums",
              i === 0 && entry.score_to_par !== null ? "bg-primary text-primary-foreground" : "bg-muted text-muted-foreground",
            )}
          >
            {entry.score_to_par !== null ? `#${i + 1}` : "–"}
          </span>
          <span className="min-w-0 flex-1 truncate text-base font-bold text-foreground">{entry.display_name}</span>
          <span className="shrink-0 text-sm text-muted-foreground">
            {leaderboard.completed ? "Ferdig" : entry.holes_played > 0 ? `${entry.holes_played} hull` : "Ikke startet"}
          </span>
          {entry.score_to_par !== null && (
            <span className="shrink-0 text-base font-extrabold tabular-nums text-foreground">
              {formatToPar(entry.score_to_par)}
            </span>
          )}
        </li>
      ))}
    </ul>
  )
}

// --- Skins-tavle -------------------------------------------------------------

function SkinsBoard({ participants, skinsWon }: { participants: ApiParticipant[]; skinsWon: Record<string, number> }) {
  const rows = participants
    .map((p) => ({ participant: p, skins: skinsWon[p.id] ?? 0 }))
    .sort((a, b) => b.skins - a.skins)
  const totalAwarded = Object.values(skinsWon).reduce((sum, v) => sum + v, 0)
  return (
    <div className="flex flex-col gap-3 rounded-2xl border border-border bg-card p-4 sm:p-5">
      <div className="flex items-center justify-between gap-2">
        <span className="text-sm font-bold text-foreground">Skins-tavle</span>
        <span className="text-xs font-semibold tabular-nums text-muted-foreground">
          {totalAwarded} skin{totalAwarded !== 1 ? "s" : ""} avgjort
        </span>
      </div>
      <ul className="flex flex-col divide-y divide-border overflow-hidden rounded-xl border border-border">
        {rows.map(({ participant, skins }) => (
          <li key={participant.id} className="flex items-center justify-between gap-3 px-4 py-2.5">
            <span className="text-sm font-semibold text-foreground">{participant.display_name}</span>
            <span className="text-base font-extrabold tabular-nums text-foreground">{skins}</span>
          </li>
        ))}
      </ul>
    </div>
  )
}

// --- Matchstatus (to-sidede formater) ----------------------------------------

function MatchStatus({ result, sides }: { result: ApiFormatResult; sides: ApiSide[] }) {
  if (!result.ready) {
    return (
      <div className="rounded-2xl border border-dashed border-border bg-card p-4 text-sm text-muted-foreground sm:p-5">
        Venter på at begge sider er komplette og har beregnet handicap før matchstatus kan vises.
      </div>
    )
  }
  const statusText = result.match_status_text ? substituteSideLabels(result.match_status_text, sides) : null
  const lead = result.match_lead ?? 0
  const holesPlayed = result.match_holes_played ?? 0
  const holesRemaining = result.match_holes_remaining ?? 0
  const totalHoles = holesPlayed + holesRemaining
  const tone: "a" | "b" | "neutral" = lead > 0 ? "a" : lead < 0 ? "b" : "neutral"
  const widthA = holesPlayed > 0 ? leadZoneFraction(lead, totalHoles) * 100 : 50
  const widthB = 100 - widthA
  const zoneAClass = tone === "a" ? "bg-primary" : tone === "b" ? "bg-primary/12" : "bg-muted"
  const zoneBClass = tone === "b" ? "bg-brand-orange" : tone === "a" ? "bg-brand-orange/12" : "bg-muted"

  return (
    <div className="flex flex-col gap-3 rounded-2xl border border-border bg-card p-4 shadow-md shadow-black/8 sm:p-5">
      <div className="flex flex-wrap items-center justify-between gap-2">
        <span className="text-sm font-bold text-muted-foreground">Matchstatus</span>
        {result.match_is_closed && <Badge variant="default">Avgjort</Badge>}
        {result.match_is_dormie && !result.match_is_closed && <Badge variant="outline">Dormie</Badge>}
      </div>
      <div
        className="grid h-20 w-full overflow-hidden rounded-2xl"
        style={{ gridTemplateColumns: `minmax(0, ${widthA}fr) auto minmax(0, ${widthB}fr)` }}
      >
        <div className={cn("h-full transition-[grid-template-columns] duration-300", zoneAClass)} />
        <div className="flex h-full items-center justify-center px-3">
          <div className="flex flex-col items-center rounded-xl border border-border/60 bg-card/95 px-3 py-1.5 shadow-sm shadow-black/10 backdrop-blur-sm">
            {statusText ? (
              <>
                <span
                  className={cn(
                    "text-xl font-extrabold leading-none tabular-nums sm:text-2xl",
                    tone === "a" ? "text-primary" : tone === "b" ? "text-brand-orange" : "text-foreground",
                  )}
                >
                  {statusText}
                </span>
                <span className="mt-1 text-[11px] font-semibold text-muted-foreground">
                  {holesPlayed} hull spilt{holesRemaining > 0 && `, ${holesRemaining} igjen`}
                </span>
              </>
            ) : (
              <span className="text-xs font-bold text-muted-foreground text-pretty">Ingen hull spilt ennå</span>
            )}
          </div>
        </div>
        <div className={cn("h-full transition-[grid-template-columns] duration-300", zoneBClass)} />
      </div>
      {result.hole_results && result.hole_results.length > 0 && (
        <ul className="flex flex-wrap gap-1">
          {result.hole_results.map((r, i) => (
            <li
              key={i}
              aria-label={
                r === "halved" ? `Hull ${i + 1}: delt` : `Hull ${i + 1}: ${r === "a" ? sides[0]?.label?.trim() || "Side A" : sides[1]?.label?.trim() || "Side B"} vant`
              }
              className={cn(
                "flex size-7 items-center justify-center rounded-full text-xs font-extrabold",
                r === "a" && "bg-primary text-primary-foreground",
                r === "b" && "bg-brand-orange text-brand-orange-foreground",
                r === "halved" && "border border-border bg-muted text-muted-foreground",
              )}
            >
              {r === "halved" ? "½" : r.toUpperCase()}
            </li>
          ))}
        </ul>
      )}
    </div>
  )
}

// --- Screen ------------------------------------------------------------------

export function WatchRound({ roundId }: { roundId: string }) {
  const [round, setRound] = useState<ApiRound | null>(null)
  const [leaderboard, setLeaderboard] = useState<ApiLeaderboard | null>(null)
  const [formatResult, setFormatResult] = useState<ApiFormatResult | null>(null)
  const [error, setError] = useState<string | null>(null)
  const [refreshKey, setRefreshKey] = useState(0)

  useEffect(() => {
    const protocol = window.location.protocol === "https:" ? "wss:" : "ws:"
    const socket = new WebSocket(`${protocol}//${window.location.host}/ws/public/rounds/${roundId}/live`)
    socket.onmessage = () => setRefreshKey((k) => k + 1)
    return () => socket.close()
  }, [roundId])

  useEffect(() => {
    let cancelled = false
    async function load() {
      const roundRes = await fetch(`/public/rounds/${roundId}`, { credentials: "include" })
      if (roundRes.status === 404) {
        if (!cancelled) setError("Denne runden finnes ikke.")
        return
      }
      if (roundRes.status === 403) {
        if (!cancelled) setError("Du har ikke tilgang til å se denne runden.")
        return
      }
      if (!roundRes.ok) {
        if (!cancelled) setError("Klarte ikke å hente runden. Prøv igjen om litt.")
        return
      }
      const roundData: ApiRound = await roundRes.json()
      if (cancelled) return
      setRound(roundData)

      if (roundData.play_format === "stroke" || roundData.play_format === "stableford" || roundData.play_format === "skins") {
        const lbRes = await fetch(`/public/rounds/${roundId}/leaderboard`, { credentials: "include" })
        if (lbRes.ok && !cancelled) setLeaderboard(await lbRes.json())
      }
      if (TWO_SIDED_FORMATS.has(roundData.play_format) || roundData.play_format === "skins") {
        const frRes = await fetch(`/public/rounds/${roundId}/format-result`, { credentials: "include" })
        if (frRes.ok && !cancelled) setFormatResult(await frRes.json())
      }
    }
    void load()
    return () => {
      cancelled = true
    }
  }, [roundId, refreshKey])

  if (error) {
    return (
      <div className="flex min-h-dvh flex-col items-center justify-center gap-4 bg-background px-5 text-center">
        <p className="text-base font-medium text-destructive">{error}</p>
        <Link href="/dashboard" className="text-base font-semibold text-primary underline underline-offset-2">
          Tilbake til dashbordet
        </Link>
      </div>
    )
  }

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

  const ongoing = round.completed_at === null

  return (
    <div className="min-h-dvh bg-background">
      <header className="sticky top-0 z-10 border-b border-border bg-background/95 backdrop-blur">
        <div className="mx-auto flex min-h-14 max-w-xl items-center gap-2 px-4 py-2">
          <span className="flex min-h-11 items-center gap-1.5 text-base font-bold text-foreground">
            <Trophy aria-hidden="true" className="size-5 text-primary" />
            Følger live
          </span>
        </div>
      </header>

      <main className="mx-auto flex max-w-xl flex-col gap-4 px-4 py-5 pb-16">
        <div className="flex flex-col gap-1 rounded-3xl border border-border bg-card p-4 shadow-md shadow-black/8">
          <span className="flex flex-wrap items-center gap-2">
            <span className="text-xl font-extrabold tracking-tight text-foreground text-balance">
              {round.name?.trim() || round.course_name_snapshot}
            </span>
            {ongoing && (
              <span className="flex shrink-0 items-center gap-1 rounded-full bg-primary px-2 py-0.5 text-xs font-bold text-primary-foreground">
                <Radio aria-hidden="true" className="size-3 animate-pulse" />
                Pågår nå
              </span>
            )}
          </span>
          <span className="text-sm font-semibold text-muted-foreground">
            {round.name?.trim() ? `${round.course_name_snapshot} · ` : ""}
            {FORMAT_LABELS[round.play_format] ?? round.play_format} · {dateFormatter.format(new Date(round.played_at))}
          </span>
          <span className="text-sm text-muted-foreground">Spilt av {round.owner_display_name}</span>
        </div>

        {TWO_SIDED_FORMATS.has(round.play_format) && formatResult && (
          <MatchStatus result={formatResult} sides={round.sides} />
        )}

        {round.play_format === "skins" && formatResult?.skins_won && (
          <SkinsBoard participants={round.participants} skinsWon={formatResult.skins_won} />
        )}

        {(round.play_format === "stroke" || round.play_format === "stableford") && leaderboard && (
          <StrokeLeaderboard leaderboard={leaderboard} />
        )}

        {!TWO_SIDED_FORMATS.has(round.play_format) &&
          round.play_format !== "skins" &&
          round.play_format !== "stroke" &&
          round.play_format !== "stableford" && (
          <p className="rounded-2xl border border-dashed border-border bg-card p-4 text-sm text-muted-foreground">
            Ingen live-visning tilgjengelig for dette formatet ennå.
          </p>
        )}
      </main>
    </div>
  )
}
