// Delte typer + fetch-funksjoner for de fire utskriftssidene
// (print-scorecard/print-startlist/print-cart-tags/print-resultlist).
// Ekte reell gjenbruk på tvers av alle fire (samme runde-/økt-/deltaker-
// endepunkter trengs flere steder), ikke en tidlig abstraksjon -- se
// ARCHITECTURE_DECISIONS.md ADR-097.

async function getJson<T>(url: string): Promise<T> {
  const res = await fetch(url, { credentials: "include" })
  if (!res.ok) throw new Error(`${url}: ${res.status}`)
  return res.json() as Promise<T>
}

export function tournamentBase(org: string, tournamentId: string) {
  return `/orgs/${org}/tournaments/${tournamentId}`
}

export type ApiTournament = {
  id: string
  name: string
  status: string
  format_type: "team" | "individual"
  scoring_method: string | null
  cut_after_round: number | null
  cut_size: number | null
}

export type ApiRound = {
  id: string
  tournament_id: string
  sequence: number
  name: string
  hole_config: "full_18" | "front_9" | "back_9"
  course_id: string
  course_name: string
  scheduled_at: string | null
  tee_interval_minutes: number | null
  start_hole: number
  start_mode: "consecutive" | "shotgun"
}

export type ApiRoundGroupParticipant = { round_participant_id: string; player_name: string }
export type ApiRoundGroup = {
  id: string | null
  sequence: number
  tee_time: string | null
  tee_time_override: string | null
  start_hole: number | null
  participants: ApiRoundGroupParticipant[]
}
export type ApiRoundGroups = { groups: ApiRoundGroup[]; ungrouped: ApiRoundGroupParticipant[] }

export type ApiRoundParticipant = {
  id: string
  tournament_participant_id: string
  player_name: string
  tee_id: string | null
  tee_name: string | null
  course_handicap: number | null
  playing_handicap: number | null
  stat_level: "strokes_only" | "strokes_and_putts" | "full"
}

export type ApiTournamentParticipant = {
  id: string
  player_id: string
  player_name: string
  handicap_index_snapshot: number | null
  class_id: string | null
  class_name: string | null
  stat_level: string
  status: "active" | "dsq" | "rtd" | "dnf" | "dns"
}

export type ApiCourseHole = { hole_number: number; par: number; stroke_index: number }
export type ApiCourse = { id: string; name: string; source: string }

export type ApiSession = {
  id: string
  sequence: number
  name: string
  format: string
  hole_config: "full_18" | "front_9" | "back_9"
  course_id: string
  points_per_match: number
  scoring_mode: "stroke" | "hole_result"
  scheduled_at: string | null
  tee_interval_minutes: number | null
  start_hole: number
  start_mode: "consecutive" | "shotgun"
  locked_team_ids: string[]
  revealed: boolean
}

export type ApiMatchParticipant = {
  id: string
  team_side: "a" | "b"
  team_roster_id: string
  player_name: string
  tee_id: string | null
  tee_name: string | null
  playing_handicap: number | null
  lineup_order: number | null
}
export type ApiMatch = {
  id: string
  sequence: number
  team_a_id: string
  team_b_id: string
  status_text: string | null
  points_side_a: number | null
  points_side_b: number | null
  leading_side: "a" | "b" | null
  tee_time: string | null
  start_hole: number | null
  participants: ApiMatchParticipant[]
}

export type ApiTeam = { id: string; name: string; color: string | null }
export type ApiRosterEntry = {
  id: string
  player_id: string
  display_name: string
  handicap_index_snapshot: number | null
  is_captain: boolean
  class_id: string | null
  class_name: string | null
}

export type ApiLeaderboardEntry = {
  tournament_participant_id: string
  player_id: string
  player_name: string
  rounds_played: number
  gross_total: number | null
  net_total: number | null
  stableford_total: number | null
  class_id: string | null
  class_name: string | null
  position: string | null
  total_label: string | null
  rank: number | null
  cut: boolean
  status: "active" | "dsq" | "rtd" | "dnf" | "dns"
  rounds: { round_number: number; label: string | null; tone: "under" | "even" | "over" | null }[]
}

export type ApiCupLeaderboard = {
  teams: { team_id: string; team_name: string; color: string | null; points: number; projected_points: number }[]
  matches_total: number
  matches_decided: number
  sessions: {
    session_id: string
    sequence: number
    name: string | null
    points_by_team: Record<string, number>
    projected_points_by_team: Record<string, number>
    matches_total: number
    matches_decided: number
  }[]
}

export type ApiPlayer = {
  id: string
  display_name: string
  handicap_index: number | null
  gender: "m" | "f" | "x" | null
  club: string | null
}

export async function fetchTournament(org: string, tournamentId: string): Promise<ApiTournament | null> {
  const list = await getJson<ApiTournament[]>(`/orgs/${org}/tournaments`)
  return list.find((t) => t.id === tournamentId) ?? null
}

export function fetchRounds(org: string, tournamentId: string) {
  return getJson<ApiRound[]>(`${tournamentBase(org, tournamentId)}/rounds`)
}

export function fetchRoundGroups(org: string, tournamentId: string, roundId: string) {
  return getJson<ApiRoundGroups>(`${tournamentBase(org, tournamentId)}/rounds/${roundId}/groups`)
}

export function fetchRoundParticipants(org: string, tournamentId: string, roundId: string) {
  return getJson<ApiRoundParticipant[]>(`${tournamentBase(org, tournamentId)}/rounds/${roundId}/participants`)
}

export function fetchTournamentParticipants(org: string, tournamentId: string) {
  return getJson<ApiTournamentParticipant[]>(`${tournamentBase(org, tournamentId)}/participants`)
}

export function fetchCourseHoles(org: string, courseId: string) {
  return getJson<ApiCourseHole[]>(`/orgs/${org}/courses/${courseId}/holes`)
}

export function fetchCourses(org: string) {
  return getJson<ApiCourse[]>(`/orgs/${org}/courses`)
}

export function fetchSessions(org: string, tournamentId: string) {
  return getJson<ApiSession[]>(`${tournamentBase(org, tournamentId)}/sessions`)
}

export function fetchMatches(org: string, sessionId: string) {
  return getJson<ApiMatch[]>(`/orgs/${org}/sessions/${sessionId}/matches`)
}

export function fetchTeams(org: string, tournamentId: string) {
  return getJson<ApiTeam[]>(`${tournamentBase(org, tournamentId)}/teams`)
}

export function fetchRoster(org: string, teamId: string) {
  return getJson<ApiRosterEntry[]>(`/orgs/${org}/teams/${teamId}/roster`)
}

export function fetchIndividualLeaderboard(org: string, tournamentId: string) {
  return getJson<ApiLeaderboardEntry[]>(`${tournamentBase(org, tournamentId)}/individual-leaderboard`)
}

export function fetchCupLeaderboard(org: string, tournamentId: string) {
  return getJson<ApiCupLeaderboard>(`${tournamentBase(org, tournamentId)}/leaderboard`)
}

export function fetchPlayers(org: string) {
  return getJson<ApiPlayer[]>(`/orgs/${org}/players`)
}

// Ingen `color`-kolonne finnes på `tee` (kun `name`, verifisert mot skjema)
// -- norsk klubbkonvensjon er at navnet ER fargen. Kun til en liten
// fargeprikk i utskrift, faller tilbake til nøytral grå for ukjente navn.
const TEE_COLOR_BY_NAME: Record<string, string> = {
  gul: "#eab308",
  rød: "#dc2626",
  hvit: "#f5f5f4",
  blå: "#2563eb",
  sølv: "#94a3b8",
  oransje: "#f97316",
  svart: "#171717",
  grønn: "#16a34a",
}
export function teeColor(teeName: string | null | undefined): string {
  if (!teeName) return "#a3a3a3"
  const key = teeName.trim().toLowerCase().split(/\s+/)[0]
  return TEE_COLOR_BY_NAME[key] ?? "#a3a3a3"
}

export function formatTeeTime(iso: string | null): string {
  if (!iso) return "–"
  const d = new Date(iso)
  if (Number.isNaN(d.getTime())) return "–"
  return d.toLocaleTimeString("no-NO", { hour: "2-digit", minute: "2-digit" })
}

export function formatDate(iso: string | null): string {
  if (!iso) return "–"
  const d = new Date(iso)
  if (Number.isNaN(d.getTime())) return "–"
  return d.toLocaleDateString("no-NO", { day: "numeric", month: "long", year: "numeric" })
}

// Realistisk hull-lengde finnes ikke i datamodellen ennå (bevisst utsatt,
// se FEATURE_BACKLOG.md "utskrift av turneringsdokumenter"-planlegging
// 2026-08-21) -- mockes med plausible tall her, akkurat som i selve
// V0-utskriftspromptene. Deterministisk fra par + hullnummer, ikke
// tilfeldig, så tallet er stabilt mellom rendringer av samme hull.
export function mockHoleLength(par: number, holeNumber: number): number {
  const base = par === 3 ? 150 : par === 5 ? 480 : 350
  return base + ((holeNumber * 17) % 40) - 20
}
