// KueSync — cue-sheet helpers
// © 2026 Krometis Analytics. All rights reserved.
//
// A cue sheet maps slide number -> dwell time (seconds). Timing can come from:
//   • a per-action "default seconds" + "per-slide overrides" (the button's own settings), or
//   • the connection's fallback cue-sheet text field.
// Both share the same parsing.

// Parse "7=120, 12=30" or one-per-line "7=120\n12=30" into { 7:120, 12:30 }.
export function parsePerSlide(text) {
  const map = {}
  if (!text) return map
  for (const part of String(text).split(/[\n,;]+/)) {
    const m = part.trim().match(/^(\d+)\s*=\s*(\d+(?:\.\d+)?)$/)
    if (m) map[Number(m[1])] = Number(m[2])
  }
  return map
}

// Full text cue sheet: lines like "default=10", "7=120". '#' lines and blanks ignored.
export function parseCueSheet(text) {
  const out = { default: 10, map: {} }
  if (!text) return out
  for (const rawLine of String(text).split(/\r?\n/)) {
    const line = rawLine.trim()
    if (!line || line.startsWith('#')) continue
    const m = line.match(/^(\w+)\s*=\s*(\d+(?:\.\d+)?)$/)
    if (!m) continue
    const [, key, val] = m
    const seconds = Number(val)
    if (key.toLowerCase() === 'default') out.default = seconds
    else if (/^\d+$/.test(key)) out.map[Number(key)] = seconds
  }
  return out
}

/**
 * Build the cue used by a Run-cue action.
 *   defaultDwell  seconds for slides without an override (0/blank -> use fallback)
 *   perSlideText  "7=120, 12=30" overrides
 *   fallbackText  connection-level cue sheet, used only when the action gives no timing
 */
export function buildCue({ defaultDwell, perSlideText, fallbackText }) {
  const hasDefault = Number(defaultDwell) > 0
  const overrides = parsePerSlide(perSlideText)
  const hasOverrides = Object.keys(overrides).length > 0
  if (hasDefault || hasOverrides) {
    return { default: hasDefault ? Number(defaultDwell) : 10, map: overrides }
  }
  return parseCueSheet(fallbackText)
}

/** Dwell (seconds) for a given slide number. */
export function dwellFor(cue, slide) {
  return cue.map[slide] != null ? cue.map[slide] : cue.default
}

/**
 * Next slide when a cue advance fires.
 * Returns the next slide number, or null to stop (when not looping at the end).
 */
export function nextCueSlide(current, total, loop) {
  const n = current + 1
  if (total && n > total) return loop ? 1 : null
  return n
}
