#!/usr/bin/env bash
# scripts/manual/run_google_meet_observer_probe.sh
# Manual: Google Meet observer-path probe; not part of CI.
#
# Why this exists: Google Meet blocks reliable unattended automation, but we
# still need repeatable evidence about whether distortion appears after raw
# Lesavka UVC/UAC output. This harness leaves Meet joining and recording to a
# human operator, then injects the same synthetic bundled media used by the
# client-to-RCT probe and analyzes the observer-side recording when provided.

set -euo pipefail

SCRIPT_DIR="$(cd -- "$(dirname "${BASH_SOURCE[0]}")" >/dev/null 2>&1 && pwd)"
REPO_ROOT="$(cd -- "${SCRIPT_DIR}/../.." >/dev/null 2>&1 && pwd)"

LESAVKA_SERVER_ADDR=${LESAVKA_SERVER_ADDR:-https://38.28.125.112:50051}
LESAVKA_TLS_DOMAIN=${LESAVKA_TLS_DOMAIN:-lesavka-server}
LESAVKA_GOOGLE_MEET_URL=${LESAVKA_GOOGLE_MEET_URL:-}
LESAVKA_MEET_OPEN_URL=${LESAVKA_MEET_OPEN_URL:-0}
LESAVKA_MEET_SKIP_PROMPTS=${LESAVKA_MEET_SKIP_PROMPTS:-0}
LESAVKA_MEET_START_DELAY_SECONDS=${LESAVKA_MEET_START_DELAY_SECONDS:-0}
LESAVKA_MEET_OBSERVER_CAPTURE=${LESAVKA_MEET_OBSERVER_CAPTURE:-}
LESAVKA_MEET_ANALYSIS_REQUIRED=${LESAVKA_MEET_ANALYSIS_REQUIRED:-0}
LESAVKA_MEET_LOCAL_REVIEW=${LESAVKA_MEET_LOCAL_REVIEW:-1}

PROBE_DURATION_SECONDS=${PROBE_DURATION_SECONDS:-20}
PROBE_WARMUP_SECONDS=${PROBE_WARMUP_SECONDS:-4}
PROBE_PULSE_PERIOD_MS=${PROBE_PULSE_PERIOD_MS:-1000}
PROBE_PULSE_WIDTH_MS=${PROBE_PULSE_WIDTH_MS:-120}
PROBE_MARKER_TICK_PERIOD=${PROBE_MARKER_TICK_PERIOD:-5}
PROBE_EVENT_WIDTH_CODES=${PROBE_EVENT_WIDTH_CODES:-1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16}

LOCAL_OUTPUT_DIR=${LOCAL_OUTPUT_DIR:-/tmp}
STAMP="$(date +%Y%m%d-%H%M%S)"
ARTIFACT_DIR="${LOCAL_OUTPUT_DIR%/}/lesavka-google-meet-observer-probe-${STAMP}"
RUN_LOG="${ARTIFACT_DIR}/google-meet-observer-run.log"
VERSION_TXT="${ARTIFACT_DIR}/lesavka-versions.txt"
OPERATOR_CHECKLIST="${ARTIFACT_DIR}/operator-checklist.txt"
MANUAL_TIMING_JSON="${ARTIFACT_DIR}/manual-timing.json"
CLIENT_TIMELINE_JSON="${ARTIFACT_DIR}/client-transport-timeline.json"
OBSERVER_CAPTURE_LOCAL=""
ANALYSIS_DIR="${ARTIFACT_DIR}/observer-analysis"

mkdir -p "${ARTIFACT_DIR}"
exec > >(tee -a "${RUN_LOG}") 2>&1

json_now_ns() {
  python3 - <<'PY'
import time
print(time.time_ns())
PY
}

prompt_or_sleep() {
  local message=$1
  local default_sleep=$2
  printf '\a'
  if [[ "${LESAVKA_MEET_SKIP_PROMPTS}" == "1" ]]; then
    echo "==> ${message}; sleeping ${default_sleep}s because prompts are disabled"
    sleep "${default_sleep}"
    return 0
  fi
  if [[ -t 0 ]]; then
    echo
    echo "==> ${message}"
    read -r -p "Press Enter when ready to continue..." _
  else
    echo "==> ${message}; stdin is not interactive, sleeping ${default_sleep}s"
    sleep "${default_sleep}"
  fi
}

write_operator_checklist() {
  cat >"${OPERATOR_CHECKLIST}" <<EOF
Google Meet observer probe checklist

Goal:
  Determine whether audio/video corruption starts inside Google Meet/WebRTC,
  after raw Lesavka UVC/UAC output has already been proven clean.

Manual setup:
  1. On the RCT/Tethys browser, join the Meet using Lesavka Camera and Lesavka Microphone.
  2. On this workstation, join the same Meet as an observer: muted mic, camera off.
  3. Pin or spotlight the RCT/Lesavka participant so the synthetic flash video is large.
  4. Disable captions and any visual overlays that could cover the tile.
  5. Start an observer-side recording that captures both Meet video and Meet audio.
  6. Return to this terminal and continue the probe.

Preferred observer recording:
  A local screen/tab recording from this workstation is best. Google cloud
  recording is usable, but it adds another processing layer.

Analysis:
  If LESAVKA_MEET_OBSERVER_CAPTURE is set, this script copies and analyzes it.
  Otherwise, rerun or invoke lesavka-sync-analyze manually against the recording.

Meet URL:
  ${LESAVKA_GOOGLE_MEET_URL:-not provided}
EOF
}

build_probe_tools() {
  echo "==> prebuilding Meet observer probe tools"
  (
    cd "${REPO_ROOT}"
    cargo build -p lesavka_client \
      --bin lesavka-sync-probe \
      --bin lesavka-sync-analyze \
      --bin lesavka-relayctl
  )
}

print_versions() {
  echo "==> Lesavka versions under test"
  local status=0
  (
    cd "${REPO_ROOT}"
    LESAVKA_TLS_DOMAIN="${LESAVKA_TLS_DOMAIN}" \
      "${REPO_ROOT}/target/debug/lesavka-relayctl" \
      --server "${LESAVKA_SERVER_ADDR}" \
      version
  ) >"${VERSION_TXT}" 2>&1 || status=$?
  sed 's/^/   ↪ /' "${VERSION_TXT}" || true
  return "${status}"
}

maybe_open_meet_url() {
  if [[ -z "${LESAVKA_GOOGLE_MEET_URL}" ]]; then
    return 0
  fi
  echo "==> Meet URL: ${LESAVKA_GOOGLE_MEET_URL}"
  if [[ "${LESAVKA_MEET_OPEN_URL}" == "1" ]]; then
    xdg-open "${LESAVKA_GOOGLE_MEET_URL}" >/dev/null 2>&1 || true
  fi
}

validate_start_delay() {
  if ! [[ "${LESAVKA_MEET_START_DELAY_SECONDS}" =~ ^[0-9]+$ ]]; then
    echo "LESAVKA_MEET_START_DELAY_SECONDS must be a non-negative integer" >&2
    exit 2
  fi
}

run_synthetic_probe() {
  echo "==> running synthetic bundled media through Google Meet path"
  local probe_started_ns probe_finished_ns
  probe_started_ns="$(json_now_ns)"
  (
    cd "${REPO_ROOT}"
    LESAVKA_TLS_DOMAIN="${LESAVKA_TLS_DOMAIN}" \
      "${REPO_ROOT}/target/debug/lesavka-sync-probe" \
      --server "${LESAVKA_SERVER_ADDR}" \
      --duration-seconds "${PROBE_DURATION_SECONDS}" \
      --warmup-seconds "${PROBE_WARMUP_SECONDS}" \
      --pulse-period-ms "${PROBE_PULSE_PERIOD_MS}" \
      --pulse-width-ms "${PROBE_PULSE_WIDTH_MS}" \
      --marker-tick-period "${PROBE_MARKER_TICK_PERIOD}" \
      --event-width-codes "${PROBE_EVENT_WIDTH_CODES}" \
      --timeline-json "${CLIENT_TIMELINE_JSON}"
  )
  probe_finished_ns="$(json_now_ns)"
  python3 - "${MANUAL_TIMING_JSON}" "${probe_started_ns}" "${probe_finished_ns}" <<'PY'
import json
import sys
import time

path = sys.argv[1]
payload = {}
try:
    with open(path, "r", encoding="utf-8") as handle:
        payload = json.load(handle)
except FileNotFoundError:
    pass
payload.update({
    "probe_started_unix_ns": int(sys.argv[2]),
    "probe_finished_unix_ns": int(sys.argv[3]),
    "timing_note": (
        "Observer capture times are operator-confirmed, so freshness from a "
        "manual recording is approximate unless the recorder supplies its own "
        "wall-clock start timestamp."
    ),
    "updated_at_unix_ns": time.time_ns(),
})
with open(path, "w", encoding="utf-8") as handle:
    json.dump(payload, handle, indent=2, sort_keys=True)
    handle.write("\n")
PY
}

record_operator_ready_time() {
  local ready_ns
  ready_ns="$(json_now_ns)"
  python3 - "${MANUAL_TIMING_JSON}" "${ready_ns}" <<'PY'
import json
import sys
import time

path = sys.argv[1]
ready_ns = int(sys.argv[2])
payload = {
    "observer_recording_confirmed_unix_ns": ready_ns,
    "created_at_unix_ns": time.time_ns(),
}
with open(path, "w", encoding="utf-8") as handle:
    json.dump(payload, handle, indent=2, sort_keys=True)
    handle.write("\n")
PY
}

copy_observer_capture_if_present() {
  if [[ -z "${LESAVKA_MEET_OBSERVER_CAPTURE}" ]]; then
    return 0
  fi
  if [[ ! -f "${LESAVKA_MEET_OBSERVER_CAPTURE}" ]]; then
    echo "observer recording not found: ${LESAVKA_MEET_OBSERVER_CAPTURE}" >&2
    exit 1
  fi
  local ext
  ext="${LESAVKA_MEET_OBSERVER_CAPTURE##*.}"
  if [[ "${ext}" == "${LESAVKA_MEET_OBSERVER_CAPTURE}" ]]; then
    ext="mkv"
  fi
  OBSERVER_CAPTURE_LOCAL="${ARTIFACT_DIR}/observer-google-meet-capture.${ext}"
  cp "${LESAVKA_MEET_OBSERVER_CAPTURE}" "${OBSERVER_CAPTURE_LOCAL}"
  echo "   ↪ observer_capture=${OBSERVER_CAPTURE_LOCAL}"
}

prompt_for_observer_capture_path() {
  if [[ -n "${LESAVKA_MEET_OBSERVER_CAPTURE}" ]]; then
    return 0
  fi
  if [[ "${LESAVKA_MEET_SKIP_PROMPTS}" == "1" || ! -t 0 ]]; then
    return 0
  fi
  echo
  read -r -p "Path to observer recording for analysis (blank to skip): " LESAVKA_MEET_OBSERVER_CAPTURE
}

analyze_observer_capture() {
  if [[ -z "${OBSERVER_CAPTURE_LOCAL}" ]]; then
    echo "==> observer capture analysis skipped"
    echo "   ↪ set LESAVKA_MEET_OBSERVER_CAPTURE=/path/to/recording.webm and rerun analysis"
    return 0
  fi

  echo "==> analyzing observer-side Meet recording"
  mkdir -p "${ANALYSIS_DIR}"
  local status=0
  (
    cd "${REPO_ROOT}"
    "${REPO_ROOT}/target/debug/lesavka-sync-analyze" \
      --event-width-codes "${PROBE_EVENT_WIDTH_CODES}" \
      --report-dir "${ANALYSIS_DIR}" \
      "${OBSERVER_CAPTURE_LOCAL}"
  ) || status=$?

  if (( status != 0 )); then
    echo "   ↪ analyzer failed for observer recording; status=${status}"
    if [[ "${LESAVKA_MEET_ANALYSIS_REQUIRED}" == "1" ]]; then
      exit "${status}"
    fi
    return 0
  fi
  echo "   ↪ observer_report=${ANALYSIS_DIR}/report.txt"
}

maybe_open_local_review() {
  if [[ "${LESAVKA_MEET_LOCAL_REVIEW}" != "1" ]]; then
    return 0
  fi
  if [[ -n "${OBSERVER_CAPTURE_LOCAL}" ]]; then
    xdg-open "${OBSERVER_CAPTURE_LOCAL}" >/dev/null 2>&1 || true
  fi
  if [[ -f "${ANALYSIS_DIR}/report.txt" ]]; then
    xdg-open "${ANALYSIS_DIR}/report.txt" >/dev/null 2>&1 || true
  fi
}

main() {
  validate_start_delay
  write_operator_checklist

  echo "==> Google Meet observer probe"
  echo "   ↪ server_addr=${LESAVKA_SERVER_ADDR}"
  echo "   ↪ meet_url=${LESAVKA_GOOGLE_MEET_URL:-manual}"
  echo "   ↪ artifact_dir=${ARTIFACT_DIR}"
  echo "   ↪ run_log=${RUN_LOG}"
  echo "   ↪ no Google credentials, sudo, or browser automation are used"

  build_probe_tools
  print_versions || true
  maybe_open_meet_url

  if (( LESAVKA_MEET_START_DELAY_SECONDS > 0 )); then
    echo "==> start delay: ${LESAVKA_MEET_START_DELAY_SECONDS}s"
    sleep "${LESAVKA_MEET_START_DELAY_SECONDS}"
  fi

  echo "==> operator checklist written"
  sed 's/^/   | /' "${OPERATOR_CHECKLIST}"
  prompt_or_sleep "Join Meet on RCT, join as observer here, pin the RCT tile, and start observer recording" 30
  record_operator_ready_time
  run_synthetic_probe
  prompt_or_sleep "Stop/save the observer recording now" 5
  prompt_for_observer_capture_path
  copy_observer_capture_if_present
  analyze_observer_capture
  maybe_open_local_review

  echo "==> done"
  echo "artifact_dir: ${ARTIFACT_DIR}"
  echo "operator_checklist: ${OPERATOR_CHECKLIST}"
  echo "manual_timing_json: ${MANUAL_TIMING_JSON}"
  echo "client_timeline_json: ${CLIENT_TIMELINE_JSON}"
  [[ -n "${OBSERVER_CAPTURE_LOCAL}" ]] && echo "observer_capture: ${OBSERVER_CAPTURE_LOCAL}"
  [[ -f "${ANALYSIS_DIR}/report.txt" ]] && echo "observer_report: ${ANALYSIS_DIR}/report.txt"
}

main "$@"
