"use client"

// Tredjeparts/offentlig live-visning av en frittstående runde (ADR-036
// fase 2, 2026-07-28). Ferskbygget, IKKE en gjenbruk av round-detail.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).
//
// Score-fanen (denne filen): kompakt status + "Spillere og runde"
// (deltakerliste, HCP/utslag/tildelte slag, "så langt", flight-
// gruppering) -- se watch-players.tsx. Selve matchstatus/skins-tavle/
// leaderboard flyttet til /watch/[id]/leaderboard (ADR-044, 2026-08-06),
// som gjenbruker den ALLEREDE eksisterende round-leaderboard.tsx uendret
// (kun `publicMode`-bryteren), for full formatparitet med eiersiden.

import { useEffect, useState } from "react"
import Link from "next/link"
import dynamic from "next/dynamic"
import { Radio, Trophy } from "lucide-react"
import { WatchTabs } from "@/components/watch-tabs"
import { WatchPlayers, type ApiPublicParticipant, type ApiLeaderboardEntry, type ApiFlightSummary } from "@/components/watch-players"
import { RoundMessages } from "@/components/round-messages"
import type { FlagMapEntry } from "@/components/flag-map-overview"

const FlagMapOverviewLazy = dynamic(() => import("@/components/flag-map-overview"), { ssr: false })

// Flaggturnering: kartoversikt (migrasjon 071, "Del B", ADR-067) --
// tilskuer-varianten, mot /public/rounds/{id}/flag-map. Tilgang er
// allerede gatet av _get_viewable_round_or_404 (samme regel som resten
// av denne siden, styrt av round.visibility_mode) -- selve INNHOLDET
// (alle flagg vs. ingenting) styres i tillegg av round.flag_map_visible
// server-side (`visible_to_all` i responsen), en tilskuer har jo ikke
// noe "eget flagg" å falle tilbake til når bryteren er av.
type ApiFlagMapPublic = { visible_to_all: boolean; flags: FlagMapEntry[] }

function WatchFlagMap({ roundId, refreshKey }: { roundId: string; refreshKey: number }) {
  const [data, setData] = useState<ApiFlagMapPublic | null>(null)
  const [expanded, setExpanded] = useState(false)

  useEffect(() => {
    let cancelled = false
    fetch(`/public/rounds/${roundId}/flag-map`, { credentials: "include" })
      .then((res) => (res.ok ? res.json() : null))
      .then((json: { visible_to_all: boolean; flags: Array<Record<string, unknown>> } | null) => {
        if (cancelled || !json) return
        setData({
          visible_to_all: json.visible_to_all,
          flags: json.flags.map((f) => ({
            participantId: f.participant_id as string,
            displayName: f.display_name as string,
            lap: f.lap as number,
            holeNumber: f.hole_number as number,
            lat: f.lat as number,
            lng: f.lng as number,
            onGreen: f.on_green as boolean,
            distanceToPinCm: f.distance_to_pin_cm as number | null,
          })),
        })
      })
      .catch(() => {})
    return () => {
      cancelled = true
    }
  }, [roundId, refreshKey])

  // Ingen synlig seksjon i det hele tatt når bryteren er av OG tilskueren
  // (naturligvis) ikke har noe eget flagg -- ikke en tom/forvirrende boks.
  if (!data || (!data.visible_to_all && data.flags.length === 0)) return null

  return (
    <div className="flex flex-col gap-3 rounded-3xl border border-border bg-card p-4 shadow-md shadow-black/8">
      <button
        type="button"
        onClick={() => setExpanded((v) => !v)}
        className="flex min-h-11 items-center justify-between gap-2 text-left"
        aria-expanded={expanded}
      >
        <span className="text-base font-bold text-foreground">Kartoversikt over flagg</span>
        <span className="text-sm font-semibold text-primary">{expanded ? "Skjul" : "Vis kart"}</span>
      </button>
      {expanded && (
        <div className="h-80 overflow-hidden rounded-xl border border-border">
          <FlagMapOverviewLazy flags={data.flags} visibleToAll={data.visible_to_all} />
        </div>
      )}
    </div>
  )
}

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

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
  owner_user_id: string
  participants: ApiPublicParticipant[]
  sides: ApiSide[]
}

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

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)",
  chapman: "Chapman",
  copenhagen: "Københavner",
  bbb: "Bingo Bango Bongo",
  flag: "Flaggturnering",
  shamble: "Shamble",
  money_ball: "Money Ball",
  high_low_high: "High-low-high",
  scramble_solo: "Scramble mot enkeltspiller",
  scramble_solo_match: "Scramble mot enkeltspiller (matchspill)",
}

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

export function WatchRound({ roundId }: { roundId: string }) {
  const [round, setRound] = useState<ApiRound | null>(null)
  const [leaderboard, setLeaderboard] = useState<ApiLeaderboard | null>(null)
  const [flightGroup, setFlightGroup] = useState<{ flight_group_id: string | null; flights: ApiFlightSummary[] } | null>(null)
  const [error, setError] = useState<string | null>(null)
  const [refreshKey, setRefreshKey] = useState(0)
  // Innlogget bruker (kan være anonym -- se moduldoc). Kun brukt til
  // RoundMessages sin slett-knapp-synlighet; "" er trygt som fallback
  // siden ingen ekte author_user_id/eier-id noensinne er en tom streng.
  const [viewerId, setViewerId] = useState<string | null>(null)

  useEffect(() => {
    let cancelled = false
    fetch("/auth/me", { credentials: "include" })
      .then((res) => (res.ok ? res.json() : null))
      .then((data: { id: string } | null) => {
        if (!cancelled && data) setViewerId(data.id)
      })
      .catch(() => {})
    return () => {
      cancelled = true
    }
  }, [])

  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)

      const [lbRes, flightRes] = await Promise.all([
        fetch(`/public/rounds/${roundId}/leaderboard`, { credentials: "include" }),
        fetch(`/public/rounds/${roundId}/flight-group`, { credentials: "include" }),
      ])
      if (lbRes.ok && !cancelled) setLeaderboard(await lbRes.json())
      if (flightRes.ok && !cancelled) setFlightGroup(await flightRes.json())
    }
    void load()
    return () => {
      cancelled = true
    }
  }, [roundId, refreshKey])

  // Anker-scroll til kommentarseksjonen (ADR-047) -- se samme mønster/
  // begrunnelse i round-detail.tsx.
  useEffect(() => {
    if (!round) return
    if (window.location.hash !== "#kommentarer") return
    document.getElementById("kommentarer")?.scrollIntoView({ block: "start" })
  }, [round])

  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>
        <WatchTabs roundId={roundId} active="score" />
      </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>

        <WatchPlayers
          participants={round.participants}
          leaderboardEntries={leaderboard?.entries ?? []}
          flightGroup={flightGroup}
        />

        {round.play_format === "flag" && <WatchFlagMap roundId={roundId} refreshKey={refreshKey} />}

        {/* Kommentarer/bilder (ADR-044) -- BUG funnet 2026-08-06: fantes
            aldri her, kun på round-detail.tsx sin egen "Score"-fane. En
            person runden er delt med hadde dermed ingen vei til å se eller
            delta i samtalen. `GET/POST /rounds/{id}/messages` er allerede
            synlighets-gatet (_can_view_round, ikke eier/deltaker-only), så
            samme endepunkt gjenbrukes uendret -- ingen ny backend-kode. */}
        {/* Anker-mål for "Kommentarer"-lenken fra leaderboardets utvidede
            rader (round-leaderboard.tsx) -- samme seksjon, ikke en duplikat. */}
        <div id="kommentarer" className="scroll-mt-20">
          <RoundMessages
            roundId={roundId}
            currentUserId={viewerId ?? ""}
            roundOwnerUserId={round.owner_user_id}
            refreshKey={refreshKey}
          />
        </div>
      </main>
    </div>
  )
}
