#!/usr/bin/env bash
# Mokosh Phase 1 — D-12 ffprobe acceptance gate smoke test.
#
# Architecture:
#   - Launches Chrome with a DEDICATED `/tmp/mokosh-smoke-profile` user-data-dir
#     so we don't interfere with your daily Chrome session.
#   - Opens a data: URL with title "Mokosh Smoke Test" as the share target.
#   - Passes `--auto-select-desktop-capture-source="Mokosh Smoke Test"` so the
#     getDisplayMedia picker auto-accepts that tab — no manual pick.
#   - Logs Chrome stderr/stdout to /tmp/mokosh-chrome.log.
#   - Polls ~/Downloads for the new session_report_*.zip.
#   - Runs ffprobe gate, stages fixture, opens WebM in Chrome for visual check.
#
# Chrome 148+ removed `--load-extension`, so the extension load is the ONE
# manual step that has to happen each time the smoke profile is fresh. (Once
# loaded, it persists in the profile until the dir is wiped — see KEEP_PROFILE.)
#
# What YOU do (~3 clicks total):
#   1. Run this script.
#   2. In the Chrome window that opens, address-bar → chrome://extensions
#      → toggle "Developer mode" ON → "Load unpacked" → select
#      /home/parf/projects/work/repremium/dist (only needed if profile is fresh).
#   3. Click the extension icon (puzzle-piece menu if not pinned).
#      The screen-share picker auto-accepts the "Mokosh Smoke Test" tab.
#   4. Wait ~35 seconds (or move mouse / scroll the smoke tab for frame deltas).
#   5. Click the icon again → click "Сохранить отчёт об ошибке".
#   This script handles everything after that.
#
# Env knobs:
#   CHROME_BIN     — Chrome binary (default: /usr/bin/google-chrome-stable)
#   KEEP_PROFILE=1 — don't wipe the smoke profile, so extension stays loaded
#                    across runs (default: wipe, fresh-load each run)
#   POLL_TIMEOUT   — max seconds to wait for the download (default: 900 = 15m)

set -euo pipefail

REPO_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
DIST_DIR="${REPO_DIR}/dist"
PROFILE_DIR="/tmp/mokosh-smoke-profile"
DOWNLOADS_DIR="${HOME}/Downloads"
FIXTURE_DEST="${REPO_DIR}/tests/fixtures/last_30sec.webm"
WEBM_TMP="/tmp/mokosh-last_30sec.webm"
CHROME_LOG="/tmp/mokosh-chrome.log"
# Plan 01-09 D-15-display-surface: SHARE_TARGET must match the OS-locale-
# specific name Chrome's picker uses for entire-screen selection. Known
# strings (Chrome stable, observed at plan-write time):
#   English: "Entire screen"
#   Russian: "Весь экран"
#   German:  "Gesamter Bildschirm"
#   French:  "Ecran entier"
# Authoritative source: Chromium's grit resource definitions in
# chrome/app/generated_resources.grd (per-locale .xtb translations under
# chrome/app/resources/). The IDS_DESKTOP_MEDIA_PICKER_SOURCE_TYPE_SCREEN
# identifier lives in the .grd, NOT in the .cc — per-locale translations
# drift across Chrome major versions, so the only reliable check is to
# run the picker once and inspect the source label in Chrome's UI.
# If --auto-select-desktop-capture-source="${SHARE_TARGET}" fails to
# auto-accept on the operator's Chrome locale, the operator picks the
# screen manually one time; KEEP_PROFILE=1 on subsequent runs carries
# the picker's last-pick memory across re-runs, sidestepping the
# auto-select string altogether.
SHARE_TARGET="Entire screen"
CHROME_BIN="${CHROME_BIN:-/usr/bin/google-chrome-stable}"
KEEP_PROFILE="${KEEP_PROFILE:-0}"
POLL_TIMEOUT="${POLL_TIMEOUT:-900}"

red()    { printf '\033[31m%s\033[0m\n' "$*"; }
green()  { printf '\033[32m%s\033[0m\n' "$*"; }
yellow() { printf '\033[33m%s\033[0m\n' "$*"; }
blue()   { printf '\033[34m%s\033[0m\n' "$*"; }

echo
blue "==> Mokosh Phase 1 smoke test (D-12 ffprobe gate)"
echo

# --- pre-flight ---
[[ -d "${DIST_DIR}" ]] || { red "FAIL: ${DIST_DIR} missing — run \`npm run build\` first"; exit 1; }
[[ -x "${CHROME_BIN}" ]] || { red "FAIL: ${CHROME_BIN} not found (set CHROME_BIN=...)"; exit 1; }
command -v ffprobe >/dev/null || { red "FAIL: ffprobe not installed"; exit 1; }
command -v unzip >/dev/null || { red "FAIL: unzip not installed"; exit 1; }
# WR-04 fix: python3 is REQUIRED for URL encoding of the smoke-tab data: URL.
# Previously a fallback `|| printf '%s' "${SMOKE_HTML}"` would emit raw HTML
# into the data URL on python3-missing systems — Chrome silently failed to
# parse those URLs (containing literal `<`, `>`, spaces, quotes) and the
# operator saw a blank tab with no diagnostic. Better to fail loud early.
command -v python3 >/dev/null || { red "FAIL: python3 not installed (needed for URL encoding the smoke tab data URL)"; exit 1; }
grep -q '"desktopCapture"' "${DIST_DIR}/manifest.json" || { red "FAIL: dist/manifest.json missing desktopCapture"; exit 1; }
! grep -q '"tabCapture"' "${DIST_DIR}/manifest.json" || { red "FAIL: dist/manifest.json still has tabCapture"; exit 1; }
green "✓ pre-flight checks passed"
echo "  chrome:    ${CHROME_BIN} ($("${CHROME_BIN}" --version 2>/dev/null || echo 'unknown'))"
echo "  dist:      ${DIST_DIR}"
echo "  profile:   ${PROFILE_DIR} (KEEP_PROFILE=${KEEP_PROFILE})"
echo "  log:       ${CHROME_LOG}"
echo "  downloads: ${DOWNLOADS_DIR}"
echo

# --- snapshot Downloads ---
# WR-05 fix: snapshot the FULL list of pre-existing zips, not just the
# count. The count-only approach falsely succeeded when an unrelated
# session_report appeared in Downloads (operator running the extension
# in another window, etc.) — the script would then ffprobe the WRONG
# file. comm -13 against the post-recording list yields the genuinely
# new file by identity. The mtime sort below still picks the latest if
# multiple new zips appear (unlikely but defensive).
BEFORE_ZIPS=$(find "${DOWNLOADS_DIR}" -maxdepth 1 -name 'session_report_*.zip' 2>/dev/null | sort)
BEFORE_COUNT=$(printf '%s\n' "${BEFORE_ZIPS}" | grep -c . || true)
echo "  existing session_report_*.zip in Downloads: ${BEFORE_COUNT}"
echo

# --- profile prep ---
PROFILE_HAS_EXTENSION=0
if [[ "${KEEP_PROFILE}" != "1" ]]; then
  rm -rf -- "${PROFILE_DIR}"
fi
mkdir -p -- "${PROFILE_DIR}"
# Detect if a previous run already loaded the extension into this profile
if [[ -d "${PROFILE_DIR}/Default/Extensions" ]] && \
   find "${PROFILE_DIR}/Default/Extensions" -maxdepth 3 -name 'manifest.json' 2>/dev/null | head -1 | xargs -r grep -q 'AI Call Recorder' 2>/dev/null; then
  PROFILE_HAS_EXTENSION=1
  green "✓ extension already loaded in profile from previous KEEP_PROFILE=1 run"
fi

# --- compose the smoke tab data URL ---
read -r -d '' SMOKE_HTML <<'EOF' || true
<title>Mokosh Smoke Test — monitor mode</title>
<style>
body{font-family:sans-serif;background:#222;color:#eee;padding:40px;line-height:1.5}
code{background:#444;padding:2px 6px;border-radius:3px}
ol li{margin:6px 0}
.flash{animation:flash 1s infinite;background:#0a4;padding:4px 8px;display:inline-block}
@keyframes flash{0%,100%{opacity:1}50%{opacity:.4}}
/* Diagnostic timer overlay — high-contrast monospace pinned top-right so it appears in every
   recorded frame. T+ counts seconds since page load (matches the moment Mokosh starts recording);
   wall is HH:MM:SS local time for cross-referencing with SW console logs. The visible value
   in the last frame of the saved video minus the value at save-click time = the operator-visible
   "stale gap" the D-13 architecture leaks. */
#mokosh-timer{position:fixed;top:12px;right:12px;background:#000;color:#0f0;padding:10px 16px;
  border:2px solid #0f0;border-radius:6px;font-family:'Courier New',monospace;font-size:28px;
  font-weight:bold;line-height:1.15;text-align:right;z-index:9999;box-shadow:0 2px 8px rgba(0,0,0,.6)}
#mokosh-timer .lbl{font-size:11px;color:#0a0;letter-spacing:.05em}
#mokosh-timer .val{font-variant-numeric:tabular-nums}
</style>
<body>
<div id="mokosh-timer">
  <div><span class="lbl">T+</span> <span class="val" id="t-elapsed">0.0s</span></div>
  <div><span class="lbl">wall</span> <span class="val" id="t-wall">--:--:--</span></div>
</div>
<h1>🧵 Mokosh Smoke Test</h1>
<p>Plan 01-09: this tab is <em>informational</em>; the picker shares the whole monitor (D-15-display-surface charter). The picker auto-accepts the entire-screen source matching <code>--auto-select-desktop-capture-source="Entire screen"</code> (locale-specific — see SHARE_TARGET comment block in smoke.sh).</p>
<h2>Steps:</h2>
<ol>
<li><strong class="flash">First time only:</strong> Go to <code>chrome://extensions</code> → toggle <strong>Developer mode</strong> ON → <strong>Load unpacked</strong> → select <code>/home/parf/projects/work/repremium/dist</code>.<br>(Set <code>KEEP_PROFILE=1</code> when re-running this script to skip the reload.)</li>
<li>Click the <strong>AI Call Recorder</strong> toolbar icon (or puzzle-piece menu).</li>
<li>The picker auto-accepts <em>the entire screen</em> (not this tab — the new Plan 01-09 D-15-display-surface charter constrains to monitor mode). Confirm Chrome's "Sharing your screen" indicator appears.</li>
<li>Wait <strong>≥ 35 seconds</strong>. <em>Note the timer value in the corner</em>. Move the mouse around or scroll this page so vp9 has frame deltas.</li>
<li>Click the toolbar icon again → click <strong>Сохранить отчёт об ошибке</strong>. <em>Note T+ and wall at the moment you click — compare to the LAST visible timer values in the saved video. Gap = operator-visible "stale" window.</em></li>
</ol>
<p>The script in your terminal will detect the download and finish the ffprobe gate automatically.</p>
<script>
(function(){
  var t0 = performance.now();
  var el = document.getElementById('t-elapsed');
  var wallEl = document.getElementById('t-wall');
  function pad(n){return String(n).padStart(2,'0');}
  function tick(){
    var dt = (performance.now() - t0) / 1000;
    el.textContent = dt.toFixed(1) + 's';
    var now = new Date();
    wallEl.textContent = pad(now.getHours()) + ':' + pad(now.getMinutes()) + ':' + pad(now.getSeconds());
  }
  tick();
  setInterval(tick, 100);
})();
</script>
</body>
EOF
# WR-04 fix: python3 is required (asserted in pre-flight). NO fallback —
# the previous `|| printf '%s' "${SMOKE_HTML}"` would emit unencoded HTML
# into the data URL, causing Chrome to fail to parse the URL silently and
# the operator to see a blank tab. Fail loudly if URL encoding fails.
SMOKE_DATA_URL="data:text/html,$(printf '%s' "${SMOKE_HTML}" | python3 -c 'import sys,urllib.parse;print(urllib.parse.quote(sys.stdin.read(), safe=""))')"

# --- launch Chrome ---
blue "==> launching Chrome with smoke profile + auto-accept picker..."
"${CHROME_BIN}" \
  --user-data-dir="${PROFILE_DIR}" \
  --auto-select-desktop-capture-source="${SHARE_TARGET}" \
  --no-first-run \
  --no-default-browser-check \
  --new-window \
  "${SMOKE_DATA_URL}" \
  > "${CHROME_LOG}" 2>&1 &
CHROME_PID=$!
echo "  Chrome PID: ${CHROME_PID}"
echo "  Tail with: tail -f ${CHROME_LOG}"
sleep 4

if ! ps -p "${CHROME_PID}" >/dev/null 2>&1; then
  # Chrome may have exec'd into a singleton; check if any chrome procs are running with our profile dir
  if ! pgrep -f "${PROFILE_DIR}" >/dev/null 2>&1; then
    red "FAIL: Chrome exited within 4 seconds"
    echo "  Last 30 lines of ${CHROME_LOG}:"
    tail -30 "${CHROME_LOG}" 2>/dev/null || true
    exit 3
  fi
fi
green "✓ Chrome running"
echo

# --- prompt ---
if [[ ${PROFILE_HAS_EXTENSION} -eq 1 ]]; then
  yellow "==> Extension is already loaded. Just click the icon → wait 35s → click save."
else
  yellow "==> In the Chrome window:"
  echo "    1. chrome://extensions → Developer mode ON → Load unpacked → ${DIST_DIR}"
  echo "    2. Confirm 'AI Call Recorder' appears with no red error."
  echo "    3. Click the extension icon."
  echo "    4. WAIT >= 35 seconds."
  echo "    5. Click the icon again → 'Сохранить отчёт об ошибке'."
fi
echo
blue "==> waiting for a new session_report_*.zip to appear..."
echo "    (Ctrl+C aborts. Auto-detects, ffprobes, stages fixture, opens WebM.)"
echo

# --- poll Downloads ---
# WR-05 fix: detect by IDENTITY via `comm -13 <before> <after>`, not by
# count comparison. The count approach false-positives when ANY
# session_report appears (e.g. the operator's daily extension in another
# window). `comm -13` returns lines present in <after> but not in
# <before> — the genuine new file(s). We still apply mtime sort + head -1
# to pick the latest if multiple new zips materialize (e.g., overlapping
# operator activity), but the candidate set is now restricted to actually-new
# files.
NEW_ARCHIVE=""
WAITED=0
while [[ ${WAITED} -lt ${POLL_TIMEOUT} ]]; do
  AFTER_ZIPS=$(find "${DOWNLOADS_DIR}" -maxdepth 1 -name 'session_report_*.zip' 2>/dev/null | sort)
  # comm requires sorted streams; both inputs above are pre-sorted.
  # `-13` keeps only lines unique to file2 (AFTER), suppressing common
  # lines and lines unique to BEFORE.
  NEW_ZIPS=$(comm -13 <(printf '%s\n' "${BEFORE_ZIPS}") <(printf '%s\n' "${AFTER_ZIPS}") | grep -v '^$' || true)
  if [[ -n "${NEW_ZIPS}" ]]; then
    sleep 2  # let the download settle
    # Re-snapshot after settle, recompute identity diff, pick latest by mtime
    AFTER_ZIPS=$(find "${DOWNLOADS_DIR}" -maxdepth 1 -name 'session_report_*.zip' 2>/dev/null | sort)
    NEW_ZIPS=$(comm -13 <(printf '%s\n' "${BEFORE_ZIPS}") <(printf '%s\n' "${AFTER_ZIPS}") | grep -v '^$' || true)
    if [[ -n "${NEW_ZIPS}" ]]; then
      # Pick the latest among the genuinely-new zips by mtime. Quoting note:
      # NEW_ZIPS is a newline-separated list of full paths from `find`; we
      # iterate via `while read` to preserve paths with embedded spaces.
      LATEST=""
      LATEST_MTIME=0
      while IFS= read -r zip_path; do
        [[ -z "${zip_path}" ]] && continue
        mtime=$(stat -c %Y -- "${zip_path}" 2>/dev/null || echo 0)
        if [[ "${mtime}" -gt "${LATEST_MTIME}" ]]; then
          LATEST="${zip_path}"
          LATEST_MTIME="${mtime}"
        fi
      done <<<"${NEW_ZIPS}"
      if [[ -n "${LATEST}" ]]; then
        NEW_ARCHIVE="${LATEST}"
        break
      fi
    fi
  fi
  sleep 1
  WAITED=$((WAITED + 1))
  if [[ $((WAITED % 30)) -eq 0 ]]; then
    after_count=$(printf '%s\n' "${AFTER_ZIPS}" | grep -c . || true)
    yellow "   ...still waiting (${WAITED}s elapsed, count=${after_count}/baseline=${BEFORE_COUNT})"
  fi
done

if [[ -z "${NEW_ARCHIVE}" ]]; then
  red "FAIL: no new archive appeared in ${POLL_TIMEOUT}s"
  echo "  Chrome log tail:"
  tail -30 "${CHROME_LOG}" 2>/dev/null || true
  echo "  Chrome still running — close manually or: kill ${CHROME_PID}"
  exit 4
fi

green "✓ archive detected: ${NEW_ARCHIVE}"
echo

# --- extract + ffprobe gate ---
# Bash-style sweep: pass `--` to terminate options on file-taking commands
# that accept user-controlled paths (Google shell style guide §"Special
# considerations" — defensive against filenames starting with `-`).
unzip -p -- "${NEW_ARCHIVE}" video/last_30sec.webm > "${WEBM_TMP}"
SIZE_BYTES=$(stat -c %s -- "${WEBM_TMP}")
SIZE_HUMAN=$(ls -lh -- "${WEBM_TMP}" | awk '{print $5}')
echo "  WebM size: ${SIZE_HUMAN} (${SIZE_BYTES} bytes)"
if [[ ${SIZE_BYTES} -lt 100000 ]]; then
  yellow "⚠ WebM is smaller than 100 KB — buffer may not have rotated; capture longer"
fi

echo
blue "==> D-12 ACCEPTANCE GATE — ffprobe -v error"
echo "---"
# The `&& GATE=0 || GATE=$?` chain is correct: under `set -e`, ffprobe's
# non-zero exit doesn't terminate the script because it's followed by `||`.
# When ffprobe succeeds, `GATE=0` (an assignment returning 0) is executed
# and the `||` branch is skipped. When ffprobe fails, the `&&` chain is
# bypassed and `GATE=$?` captures ffprobe's exit. The earlier review note
# WR-04 confirmed this is NOT broken.
ffprobe -v error -f matroska -i "${WEBM_TMP}" && GATE=0 || GATE=$?
echo "---"
echo "ffprobe exit: ${GATE}"

if [[ ${GATE} -eq 0 ]]; then
  green "✓ D-12 ACCEPTANCE GATE PASSED"
else
  red "✗ D-12 ACCEPTANCE GATE FAILED — D-13 fallback (restart-segments) required"
  yellow "==> diagnostic for D-13 escalation:"
  ffprobe -v error -show_packets -i "${WEBM_TMP}" 2>&1 | head -50 || true
fi

echo
blue "==> stream / format dump (paste this back to the orchestrator):"
echo "---"
ffprobe -v error -show_format -show_streams "${WEBM_TMP}" 2>&1 | head -30 || true
echo "---"
echo

# --- stage fixture ---
if [[ ${GATE} -eq 0 ]]; then
  mkdir -p -- "$(dirname -- "${FIXTURE_DEST}")"
  cp -- "${WEBM_TMP}" "${FIXTURE_DEST}"
  green "✓ fixture staged: ${FIXTURE_DEST} ($(ls -lh -- "${FIXTURE_DEST}" | awk '{print $5}'))"
fi

# --- open the WebM for visual check ---
echo
blue "==> opening the WebM for visual playback (SPEC §10 #7)..."
"${CHROME_BIN}" --user-data-dir="${PROFILE_DIR}" --new-window "file://${WEBM_TMP}" >/dev/null 2>&1 &

echo
green "==> smoke complete."
echo "    Chrome (smoke profile) PID ${CHROME_PID} still running."
echo "    Kill when done:  kill ${CHROME_PID}"
echo "    To keep the extension loaded across runs:  KEEP_PROFILE=1 ./smoke.sh"
echo
if [[ ${GATE} -eq 0 ]]; then
  green "==> NEXT: reply 'approved' to the orchestrator with the stream/format dump."
else
  red "==> NEXT: reply 'ffprobe-failed' with the show_packets diagnostic above."
fi
exit "${GATE}"
