#!/usr/bin/env bash
set -euo pipefail

DURATION="${1:-3600}"
OUTDIR="${OUTDIR:-./recordings}"
RUN_STAMP="${RUN_STAMP:-$(date +%Y%m%d_%H%M%S)}"
RUN_DIR="$OUTDIR/$RUN_STAMP"
mkdir -p "$RUN_DIR"

end_ts=$(( $(date +%s) + DURATION ))
monitor_interval=60

KEYS=(
  us_cnn_international_hd
  usa_cnni_hd_east
  pluto_germany_cnni
  pluto_uk_cnni
)

declare -A LABELS=(
  [us_cnn_international_hd]='US: CNN INTERNATIONAL HD'
  [usa_cnni_hd_east]='USA: CNNi HD East'
  [pluto_germany_cnni]='(PLUTO Germany) CNNi'
  [pluto_uk_cnni]='(PLUTO UK) CNNi'
)

declare -A GATEWAY_URLS=(
  [us_cnn_international_hd]='https://gohyperspeed.com/700418314/M1gbkj9t55/400124875'
  [usa_cnni_hd_east]='https://gohyperspeed.com/700418314/M1gbkj9t55/600006103'
  [pluto_germany_cnni]='https://gohyperspeed.com/700418314/M1gbkj9t55/700017805'
  [pluto_uk_cnni]='https://gohyperspeed.com/700418314/M1gbkj9t55/700017469'
)

declare -A SEED_FINAL_URLS=(
  [us_cnn_international_hd]=''
  [usa_cnni_hd_east]='https://deepwater.space/live/700418314/M1gbkj9t55/600006103'
  [pluto_germany_cnni]='https://thehoppers.online/live/700418314/M1gbkj9t55/700017805'
  [pluto_uk_cnni]='https://myboosters.online/live/700418314/M1gbkj9t55/700017469'
)

declare -A PIDS=()
declare -A ATTEMPTS=()
declare -A ACTIVE_URLS=()
declare -A NEXT_RETRY_TS=()
declare -A LAST_FILE=()
declare -A LAST_SIZE=()
declare -A STALE_COUNT=()
declare -A FAIL_COUNT=()

log() {
  printf '[%s] %s\n' "$(date --iso-8601=seconds)" "$*" | tee -a "$RUN_DIR/supervisor.log"
}

resolve_final_url() {
  local url="$1"
  curl -fsSIL --max-time 20 -o /dev/null -w '%{url_effective}' "$url" 2>/dev/null || true
}

probe_url() {
  local url="$1"
  timeout 15 ffmpeg -nostdin -hide_banner -loglevel error -t 2 -i "$url" -f null - >/dev/null 2>&1
}

retry_delay() {
  local key="$1"
  local fails="${FAIL_COUNT[$key]:-0}"
  local base=120
  case "$key" in
    us_cnn_international_hd|usa_cnni_hd_east) base=120 ;;
    pluto_germany_cnni|pluto_uk_cnni) base=180 ;;
  esac
  local delay=$(( base * (fails + 1) ))
  if (( delay > 600 )); then delay=600; fi
  echo "$delay"
}

record_attempt() {
  local key="$1"
  local source_url="$2"
  local attempt="$3"
  local key_dir="$RUN_DIR/$key"
  local file_tag
  file_tag=$(printf 'attempt_%02d' "$attempt")
  mkdir -p "$key_dir"

  local mp4="$key_dir/${file_tag}.mp4"
  local logf="$key_dir/${file_tag}.log"
  local txt="$key_dir/${file_tag}.txt"

  {
    echo "label=${LABELS[$key]}"
    echo "gateway_url=${GATEWAY_URLS[$key]}"
    echo "source_url=${source_url}"
    echo "attempt=${attempt}"
    echo "started_at=$(date --iso-8601=seconds)"
  } > "$txt"

  (
    exec ffmpeg -y -nostdin -hide_banner -loglevel warning \
      -reconnect 1 \
      -reconnect_at_eof 1 \
      -reconnect_streamed 1 \
      -reconnect_on_network_error 1 \
      -reconnect_on_http_error 4xx,5xx \
      -rw_timeout 15000000 \
      -i "$source_url" \
      -map 0 \
      -c copy \
      -movflags +faststart \
      -bsf:a aac_adtstoasc \
      "$mp4"
  ) > "$logf" 2>&1 &

  PIDS[$key]="$!"
  ACTIVE_URLS[$key]="$source_url"
  LAST_FILE[$key]="$mp4"
  LAST_SIZE[$key]=0
  STALE_COUNT[$key]=0
  log "started key=$key pid=${PIDS[$key]} attempt=$attempt url=$source_url output=$mp4"
}

start_channel() {
  local key="$1"
  local now
  now=$(date +%s)
  local next_retry="${NEXT_RETRY_TS[$key]:-0}"
  if (( now < next_retry )); then
    return 0
  fi

  local attempt=$(( ${ATTEMPTS[$key]:-0} + 1 ))
  ATTEMPTS[$key]="$attempt"

  local candidates=()
  if [[ -n "${SEED_FINAL_URLS[$key]:-}" ]]; then
    candidates+=("${SEED_FINAL_URLS[$key]}")
  fi

  if [[ "$key" == "us_cnn_international_hd" || ${FAIL_COUNT[$key]:-0} -gt 0 ]]; then
    local resolved
    resolved="$(resolve_final_url "${GATEWAY_URLS[$key]}")"
    if [[ -n "$resolved" && "$resolved" != "${GATEWAY_URLS[$key]}" ]]; then
      candidates+=("$resolved")
      SEED_FINAL_URLS[$key]="$resolved"
    fi
  fi

  candidates+=("${GATEWAY_URLS[$key]}")

  local chosen=''
  local candidate
  for candidate in "${candidates[@]}"; do
    [[ -n "$candidate" ]] || continue
    if probe_url "$candidate"; then
      chosen="$candidate"
      break
    fi
  done

  if [[ -z "$chosen" ]]; then
    FAIL_COUNT[$key]=$(( ${FAIL_COUNT[$key]:-0} + 1 ))
    local delay
    delay="$(retry_delay "$key")"
    NEXT_RETRY_TS[$key]=$(( now + delay ))
    log "deferred key=$key reason=probe_failed retry_in=${delay}s"
    return 1
  fi

  FAIL_COUNT[$key]=0
  NEXT_RETRY_TS[$key]=0
  record_attempt "$key" "$chosen" "$attempt"
}

stop_channel() {
  local key="$1"
  local pid="${PIDS[$key]:-}"
  [[ -n "$pid" ]] || return 0
  if kill -0 "$pid" 2>/dev/null; then
    kill -INT "$pid" 2>/dev/null || true
    wait "$pid" 2>/dev/null || true
  fi
  unset PIDS[$key]
  log "stopped key=$key"
}

stop_all() {
  for key in "${KEYS[@]}"; do
    stop_channel "$key"
  done
  log "finished run_dir=$RUN_DIR"
}

trap 'stop_all; exit 0' INT TERM

log "run_dir=$RUN_DIR duration=${DURATION}s"
log "priority_order=${KEYS[*]}"

for key in "${KEYS[@]}"; do
  start_channel "$key" || true
  sleep 4
done

while (( $(date +%s) < end_ts )); do
  sleep "$monitor_interval"
  now=$(date +%s)

  for key in "${KEYS[@]}"; do
    local_pid="${PIDS[$key]:-}"
    current_file="${LAST_FILE[$key]:-}"

    if [[ -n "$local_pid" ]] && kill -0 "$local_pid" 2>/dev/null; then
      size=0
      if [[ -n "$current_file" && -f "$current_file" ]]; then
        size=$(stat -c '%s' "$current_file" 2>/dev/null || echo 0)
      fi
      prev="${LAST_SIZE[$key]:-0}"
      if [[ "$size" == "$prev" && "$size" != "0" ]]; then
        STALE_COUNT[$key]=$(( ${STALE_COUNT[$key]:-0} + 1 ))
      else
        STALE_COUNT[$key]=0
      fi
      LAST_SIZE[$key]="$size"
      log "progress key=$key pid=$local_pid size_bytes=$size stale=${STALE_COUNT[$key]}"

      if (( ${STALE_COUNT[$key]:-0} >= 2 )); then
        log "restarting key=$key reason=stalled"
        stop_channel "$key"
        start_channel "$key" || true
      fi
    else
      if [[ -n "$local_pid" ]]; then
        wait "$local_pid" 2>/dev/null || true
        unset PIDS[$key]
        log "exited key=$key"
      fi
      start_channel "$key" || true
    fi
  done
done

stop_all
