// KueSync — video clock (TRT / elapsed / remaining)
// © 2026 Krometis Analytics. All rights reserved.
//
// Pure, deterministic timer used for the Companion video-time variables. The "total running time"
// (TRT) comes from one of two sources, chosen by the caller:
//   • MEASURED  — read from PowerPoint on Windows (the real clip length). Exact.
//   • PLANNED   — the length the operator typed in the cue sheet (used on macOS / Keynote, where the
//                 OS does not expose a video's length or playhead to any external tool).
// The live position is KueSync's own countdown from that length, so "time remaining" works on both
// platforms; it is a true measurement on Windows and a scheduled countdown on Mac.

/** Format milliseconds as M:SS (or H:MM:SS past an hour). Negative/NaN clamp to 0:00. */
export function fmtClock(ms) {
  let n = Number(ms)
  if (!Number.isFinite(n) || n < 0) n = 0
  const total = Math.round(n / 1000)
  const s = total % 60
  const m = Math.floor(total / 60) % 60
  const h = Math.floor(total / 3600)
  const pad = (x) => String(x).padStart(2, '0')
  return h > 0 ? `${h}:${pad(m)}:${pad(s)}` : `${m}:${pad(s)}`
}

// `active` (not startedAt truthiness) marks a clock that has been started — so it works even at t=0.

/** A stopped clock (no video / armed but not yet started). */
export function stopClock() {
  return { trtMs: 0, active: false, playing: false, startedAt: 0, accumPausedMs: 0, pausedAt: 0 }
}

/** Start counting a clip of trtMs from `now`. */
export function startClock(trtMs, now) {
  return { trtMs: Math.max(0, Number(trtMs) || 0), active: true, playing: true, startedAt: now, accumPausedMs: 0, pausedAt: 0 }
}

/** Freeze the countdown (operator paused the video). */
export function pauseClock(m, now) {
  if (!m || !m.active || !m.playing) return m
  return { ...m, playing: false, pausedAt: now }
}

/** Resume after a pause, not counting the paused gap. */
export function resumeClock(m, now) {
  if (!m || !m.active || m.playing) return m
  const gap = m.pausedAt ? Math.max(0, now - m.pausedAt) : 0
  return { ...m, playing: true, pausedAt: 0, accumPausedMs: (m.accumPausedMs || 0) + gap }
}

/** Jump to the end (video finished): remaining = 0, holds TRT for display. */
export function finishClock(m, now) {
  if (!m || !m.trtMs) return m
  return { ...m, active: true, playing: false, startedAt: now - m.trtMs, accumPausedMs: 0, pausedAt: 0 }
}

/** Read elapsed / remaining at time `now`. Clamps elapsed to [0, trt]. */
export function clockReadout(m, now) {
  const trt = Math.max(0, (m && m.trtMs) || 0)
  if (!m || !m.active) return { trtMs: trt, elapsedMs: 0, remainingMs: trt }
  if (!trt) {
    // COUNT-UP stopwatch (v6.4.7): no known clip length — elapsed runs, remaining stays 0.
    const ref = m.playing ? now : (m.pausedAt || now)
    return { trtMs: 0, elapsedMs: Math.max(0, ref - m.startedAt - (m.accumPausedMs || 0)), remainingMs: 0 }
  }
  const ref = m.playing ? now : (m.pausedAt || now)
  let elapsed = ref - m.startedAt - (m.accumPausedMs || 0)
  if (elapsed < 0) elapsed = 0
  if (elapsed > trt) elapsed = trt
  return { trtMs: trt, elapsedMs: elapsed, remainingMs: Math.max(0, trt - elapsed) }
}

/** Human label for where the TRT came from (shown to the operator so planned ≠ measured). */
export function sourceLabel(source) {
  if (source === 'measured') return 'measured'
  if (source === 'planned') return 'planned (cue sheet)'
  return 'not available — enter TRT in cue sheet'
}
