/** Championship lobby helpers for the TV: when the show starts, and how big its name can be. */

/** A start time further away than this is no use to a room waiting in the lobby. */
export const LOBBY_COUNTDOWN_WINDOW_MS = 60 * 60_000;
/**
 * Championships are started by the host, so the scheduled time can pass with the lobby still open.
 * For this long after it, "any moment" is honest; after that the host is clearly running late.
 */
export const LOBBY_DUE_GRACE_MS = 30 * 60_000;

export type LobbyStart =
  /** Within the hour: count down to `startsAt`. */
  | { kind: 'countdown'; startsAt: number }
  /** The scheduled time has just come; the host will start any moment. */
  | { kind: 'due' }
  /** Unscheduled, far off (a lobby opened the day before) or long overdue: it starts when the host starts it. */
  | { kind: 'host' };

/** What the lobby says about the start, from the active event's scheduled start (server ms) and server now. */
export function lobbyStart(scheduledAt: number | null | undefined, now: number): LobbyStart {
  if (scheduledAt === null || scheduledAt === undefined || !Number.isFinite(scheduledAt)) return { kind: 'host' };
  const ahead = scheduledAt - now;
  if (ahead > LOBBY_COUNTDOWN_WINDOW_MS) return { kind: 'host' };
  if (ahead > 0) return { kind: 'countdown', startsAt: scheduledAt };
  return -ahead <= LOBBY_DUE_GRACE_MS ? { kind: 'due' } : { kind: 'host' };
}

/**
 * Title sizes on the 1920×1080 stage: one line from 76 px down to 60, then two lines from 68 down to
 * 40 (capped lower so a two-line header doesn't squeeze the tables panel below it).
 */
export const LOBBY_TITLE_MAX = 76;
export const LOBBY_TITLE_ONE_LINE_MIN = 60;
export const LOBBY_TITLE_TWO_LINE_MAX = 68;
export const LOBBY_TITLE_MIN = 40;
/**
 * Advance of one character of the title face (Unbounded extra-bold at -0.03em tracking), in em.
 * Measured in the browser per glyph and grouped, each group rounded up to its widest common member,
 * so the estimate runs a little wide ("Friday Night Championship" ≈ 17.1 em, measured 16.7) and an
 * ALL-CAPS name (≈ 30% wider than mixed case) gets a smaller size instead of overflowing.
 */
function glyphEm(ch: string): number {
  if (ch === ' ') return 0.22;
  if (/[iIjl.,:;!'’·|]/.test(ch)) return 0.33;
  if (/[-frt1()]/.test(ch)) return 0.6;
  if (ch === 'W') return 1.35;
  if (/[mwM@%]/.test(ch)) return 1.25;
  if (/[A-Z0-9&#?]/.test(ch)) return 0.92;
  if (/[a-z]/.test(ch)) return 0.78;
  // Accented letters, other scripts, emoji: assume wide.
  return 0.95;
}

/** Estimated width of `text` in em of the title face. */
export function textEm(text: string): number {
  let em = 0;
  for (const ch of text) em += glyphEm(ch);
  return em;
}

/** Lines a greedy word wrap needs for lines `maxEm` wide; Infinity when one word alone is wider than a line. */
export function wrappedLines(text: string, maxEm: number): number {
  const words = text.trim().split(/\s+/).filter(Boolean);
  if (words.length === 0) return 1;
  const space = glyphEm(' ');
  let lines = 1;
  let used = 0;
  for (const word of words) {
    const em = textEm(word);
    if (em > maxEm) return Number.POSITIVE_INFINITY;
    if (used === 0) used = em;
    else if (used + space + em <= maxEm) used += space + em;
    else {
      lines++;
      used = em;
    }
  }
  return lines;
}

/**
 * Font size (px) and line count for the event name in the lobby header, so names fit `width`
 * without truncating: one line while it can stay large, else the largest size that fits two lines.
 * Mixed-case names over ~70 characters reach the floor (and may wrap to a third line there).
 */
export function lobbyTitleFit(name: string, width: number): { size: number; lines: 1 | 2 } {
  const fits = (size: number, lines: number) => wrappedLines(name, width / size) <= lines;
  for (let size = LOBBY_TITLE_MAX; size >= LOBBY_TITLE_ONE_LINE_MIN; size -= 2) {
    if (fits(size, 1)) return { size, lines: 1 };
  }
  for (let size = LOBBY_TITLE_TWO_LINE_MAX; size >= LOBBY_TITLE_MIN; size -= 2) {
    if (fits(size, 2)) return { size, lines: 2 };
  }
  return { size: LOBBY_TITLE_MIN, lines: 2 };
}
