#!/usr/bin/env bash
# smoke-linux-driver.sh — Lumotia Linux UI smoke driver
#
# Automates more cells of the smoke-test matrix than smoke-linux.sh by driving
# the X11 UI via xdotool + reading the SQLite store directly for History
# assertions.
#
# Prereqs:
#   - xdotool (apt/dnf/pacman: xdotool)
#   - sqlite3 CLI (apt/dnf/pacman: sqlite or sqlite3)
#   - X11 session (Wayland users: launch with GDK_BACKEND=x11 — already set by run.sh)
#   - Optional: virtual audio source (see docs/release/virtual-audio-setup.md) for the
#     Capture cell. Without it, Capture stays MANUAL.
#
# Usage:
#   ./scripts/smoke-linux-driver.sh [/path/to/lumotia-0.1.0-linux-x86_64.AppImage]
#
# If no argument is given, the script builds a debug binary via cargo and tests
# against that instead.
#
# Exit codes:
#   0  all automated cells passed (manual cells still need human sign-off)
#   1  one or more automated cells failed

set -euo pipefail

# ── helpers ──────────────────────────────────────────────────────────────────

RED='\033[0;31m'
GREEN='\033[0;32m'
YELLOW='\033[1;33m'
BOLD='\033[1m'
RESET='\033[0m'

REPO_ROOT="$(git -C "$(dirname "$0")" rev-parse --show-toplevel)"
cd "$REPO_ROOT"

APPIMAGE="${1:-}"
BINARY=""
USE_APPIMAGE=false

CELL_PASS=0
CELL_FAIL=0
CELL_MANUAL=0

# Track whether Capture succeeded so dependent cells know whether to run
CAPTURE_RAN=false
CAPTURE_STARTED_AT=""

cell_header() {
  printf "\n${BOLD}[CELL %s] %s${RESET}\n" "$1" "$2"
}
cell_pass() {
  CELL_PASS=$((CELL_PASS + 1))
  printf "${GREEN}  ✓ PASS${RESET}  %s\n" "$1"
}
cell_fail() {
  CELL_FAIL=$((CELL_FAIL + 1))
  printf "${RED}  ✗ FAIL${RESET}  %s\n" "$1"
}
cell_manual() {
  CELL_MANUAL=$((CELL_MANUAL + 1))
  printf "${YELLOW}  ⚠ MANUAL${RESET}  %s\n" "$1"
}

# ── Capability checks ─────────────────────────────────────────────────────────

HAS_XDOTOOL=false
HAS_SQLITE3=false
HAS_VIRTUAL_AUDIO=false

if command -v xdotool >/dev/null 2>&1; then
  HAS_XDOTOOL=true
fi

if command -v sqlite3 >/dev/null 2>&1; then
  HAS_SQLITE3=true
fi

# Check for virtual audio source named "lumotia-test"
if command -v pactl >/dev/null 2>&1; then
  if pactl list sources short 2>/dev/null | grep -q "lumotia-test"; then
    HAS_VIRTUAL_AUDIO=true
  fi
fi

if ! $HAS_XDOTOOL; then
  printf "${YELLOW}${BOLD}xdotool not found.${RESET} Falling back to smoke-linux.sh behaviour for UI-dependent cells.\n"
  printf "  Install xdotool (apt/dnf/pacman: xdotool) to enable UI automation.\n"
  printf "  Cells 2–6 will be MANUAL except Install and the dogfood drill.\n\n"
fi

if ! $HAS_SQLITE3; then
  printf "${YELLOW}${BOLD}sqlite3 not found.${RESET} History search cell (6/7) will be MANUAL.\n"
  printf "  Install sqlite3 (apt/dnf/pacman: sqlite or sqlite3) to enable SQLite automation.\n\n"
fi

# ── Resolve data dir ──────────────────────────────────────────────────────────

# Lumotia uses the platform data dir. On Linux this is ~/.local/share/lumotia.
DATA_DIR="${XDG_DATA_HOME:-$HOME/.local/share}/lumotia"
DB_PATH="$DATA_DIR/transcripts.db"

# ── Cell 1/7: Install ─────────────────────────────────────────────────────────

cell_header "1/7" "Install"

if [[ -n "$APPIMAGE" ]]; then
  if [[ ! -f "$APPIMAGE" ]]; then
    cell_fail "AppImage not found at: $APPIMAGE"
  elif [[ ! -x "$APPIMAGE" ]]; then
    printf "  AppImage is not executable — setting bit now...\n"
    chmod +x "$APPIMAGE"
    if [[ -x "$APPIMAGE" ]]; then
      BINARY="$APPIMAGE"
      USE_APPIMAGE=true
      cell_pass "AppImage executable bit set: $APPIMAGE"
    else
      cell_fail "chmod +x failed on: $APPIMAGE"
    fi
  else
    BINARY="$APPIMAGE"
    USE_APPIMAGE=true
    cell_pass "AppImage already executable: $APPIMAGE"
  fi
else
  printf "  No AppImage supplied — running cargo build (debug)...\n"
  if cargo build -p lumotia 2>&1; then
    BINARY="$REPO_ROOT/target/debug/lumotia"
    if [[ -f "$BINARY" ]]; then
      cell_pass "cargo build succeeded. Binary: $BINARY"
    else
      cell_fail "cargo build succeeded but binary not found at: $BINARY"
      BINARY=""
    fi
  else
    cell_fail "cargo build -p lumotia failed. Fix compilation errors before smoke-testing."
    BINARY=""
  fi
fi

# ── Cell 2/7: First-run ───────────────────────────────────────────────────────

cell_header "2/7" "First-run (launch + window detection)"

BINARY_PID=""

if [[ -z "$BINARY" ]]; then
  cell_fail "Skipping — no valid binary from Cell 1."
elif ! $HAS_XDOTOOL; then
  # Fallback: plain process-liveness check (same as smoke-linux.sh)
  LUMOTIA_SMOKE_MODE=1 \
    WEBKIT_DISABLE_DMABUF_RENDERER=1 \
    GDK_BACKEND=x11 \
    DISPLAY="${DISPLAY:-:99}" \
    "$BINARY" &>/tmp/lumotia-smoke-driver-launch.log &
  BINARY_PID=$!

  printf "  Waiting 10 seconds (PID %s)...\n" "$BINARY_PID"
  ALIVE=true
  for i in $(seq 1 10); do
    sleep 1
    if ! kill -0 "$BINARY_PID" 2>/dev/null; then
      ALIVE=false
      break
    fi
  done

  if kill -0 "$BINARY_PID" 2>/dev/null; then
    kill -TERM "$BINARY_PID" 2>/dev/null || true
    sleep 1
    kill -KILL "$BINARY_PID" 2>/dev/null || true
  fi
  wait "$BINARY_PID" 2>/dev/null || true
  BINARY_PID=""

  if $ALIVE; then
    cell_pass "Binary stayed alive 10 s (no xdotool — window title not verified)."
  else
    EXIT_LOG=/tmp/lumotia-smoke-driver-launch.log
    if grep -qiE 'panic|SIGSEGV|Segmentation fault|thread.*panicked' "$EXIT_LOG" 2>/dev/null; then
      cell_fail "Binary crashed within 10 s. See /tmp/lumotia-smoke-driver-launch.log"
    else
      cell_pass "Binary exited cleanly in headless mode. No panic in log."
    fi
  fi
else
  # xdotool available — launch and verify window title
  WEBKIT_DISABLE_DMABUF_RENDERER=1 \
    GDK_BACKEND=x11 \
    DISPLAY="${DISPLAY:-:0}" \
    "$BINARY" &>/tmp/lumotia-smoke-driver-launch.log &
  BINARY_PID=$!

  printf "  Waiting 5 s for window to appear (PID %s)...\n" "$BINARY_PID"
  FOUND_WINDOW=""
  for i in $(seq 1 5); do
    sleep 1
    if ! kill -0 "$BINARY_PID" 2>/dev/null; then
      break
    fi
    FOUND_WINDOW=$(DISPLAY="${DISPLAY:-:0}" xdotool search --name "Lumotia" 2>/dev/null | head -1 || true)
    if [[ -n "$FOUND_WINDOW" ]]; then
      break
    fi
  done

  if [[ -n "$FOUND_WINDOW" ]]; then
    cell_pass "Window 'Lumotia' found via xdotool (window ID: $FOUND_WINDOW)."
    # Leave the process running for Capture cell
  else
    # Process may still be alive but window not found — check for crash
    if ! kill -0 "$BINARY_PID" 2>/dev/null; then
      EXIT_LOG=/tmp/lumotia-smoke-driver-launch.log
      if grep -qiE 'panic|SIGSEGV|Segmentation fault|thread.*panicked' "$EXIT_LOG" 2>/dev/null; then
        cell_fail "Binary crashed before window appeared. See /tmp/lumotia-smoke-driver-launch.log"
      else
        cell_pass "Binary exited cleanly (headless/no-display mode). No panic in log."
      fi
      BINARY_PID=""
    else
      # Window not found but process alive — likely no DISPLAY or WebKit not ready
      cell_manual "Binary alive but 'Lumotia' window not detected within 5 s. Verify manually that the window opens and the app loads."
      # Kill it — Capture can't run without a confirmed window
      kill -TERM "$BINARY_PID" 2>/dev/null || true
      sleep 1
      kill -KILL "$BINARY_PID" 2>/dev/null || true
      wait "$BINARY_PID" 2>/dev/null || true
      BINARY_PID=""
    fi
  fi
fi

# ── Cell 3/7: Capture ─────────────────────────────────────────────────────────

cell_header "3/7" "Capture (record via hotkey)"

if ! $HAS_XDOTOOL; then
  printf "  MANUAL: Open the app, talk into the microphone for 5 seconds.\n"
  printf "          Confirm a live transcript appears in the dictation area.\n"
  cell_manual "xdotool not found — audio capture requires a human tester."
elif [[ -z "$BINARY_PID" ]]; then
  printf "  MANUAL: Cell 2 did not leave a running app window.\n"
  printf "          Open the app manually, record for 5 seconds, confirm a transcript appears.\n"
  cell_manual "No confirmed running window — Capture cell cannot be automated."
elif ! $HAS_VIRTUAL_AUDIO; then
  printf "  MANUAL: No virtual audio source named 'lumotia-test' detected.\n"
  printf "          Set one up (see docs/release/virtual-audio-setup.md), then in Lumotia →\n"
  printf "          Settings → Start Here → Microphone, pick 'lumotia-test'.\n"
  printf "          Once configured, re-run this script to automate the Capture cell.\n"
  cell_manual "Virtual audio source 'lumotia-test' not found — audio capture requires a human tester."
else
  # All prereqs met: focus the window and drive the hotkey
  # Default record hotkey is Super+Shift+Space; adjust if the user has changed it.
  RECORD_HOTKEY="${LUMOTIA_RECORD_HOTKEY:-super+shift+space}"

  FOUND_WINDOW=$(DISPLAY="${DISPLAY:-:0}" xdotool search --name "Lumotia" 2>/dev/null | head -1 || true)
  if [[ -z "$FOUND_WINDOW" ]]; then
    printf "  MANUAL: Could not re-locate the Lumotia window to send the hotkey.\n"
    cell_manual "xdotool search failed at Capture time — drive recording manually."
  else
    printf "  Focusing window and pressing record hotkey (%s)...\n" "$RECORD_HOTKEY"
    DISPLAY="${DISPLAY:-:0}" xdotool windowfocus --sync "$FOUND_WINDOW" 2>/dev/null || true
    sleep 0.5
    DISPLAY="${DISPLAY:-:0}" xdotool key --clearmodifiers "$RECORD_HOTKEY" 2>/dev/null || true

    printf "  Recording for 5 seconds...\n"
    CAPTURE_STARTED_AT="$(date +%s)"
    sleep 5

    printf "  Pressing record hotkey again to stop...\n"
    DISPLAY="${DISPLAY:-:0}" xdotool key --clearmodifiers "$RECORD_HOTKEY" 2>/dev/null || true

    printf "  Waiting up to 15 s for transcription to complete...\n"
    sleep 15

    CAPTURE_RAN=true
    cell_pass "Record hotkey sent twice (start + stop). Transcription settling time elapsed."
    printf "  Note: Actual transcript content is NOT printed here (privacy invariant).\n"
  fi
fi

# Tear down the app if it is still running and we own the PID
if [[ -n "$BINARY_PID" ]] && kill -0 "$BINARY_PID" 2>/dev/null; then
  kill -TERM "$BINARY_PID" 2>/dev/null || true
  sleep 1
  kill -KILL "$BINARY_PID" 2>/dev/null || true
  wait "$BINARY_PID" 2>/dev/null || true
fi

# ── Cell 4/7: Cleanup ─────────────────────────────────────────────────────────

cell_header "4/7" "Cleanup (LLM-cleaned transcript in DB)"

if ! $CAPTURE_RAN; then
  printf "  MANUAL: Stop recording. Confirm the cleaned transcript\n"
  printf "          appears beneath the raw transcript in the PostCaptureCard.\n"
  cell_manual "Capture cell did not run automatically — Cleanup requires a prior automated capture."
elif ! $HAS_SQLITE3; then
  printf "  MANUAL: sqlite3 not found — cannot query the database directly.\n"
  printf "          Inspect the PostCaptureCard in the app to confirm cleaned text is present.\n"
  cell_manual "sqlite3 not found — Cleanup cell assertion requires manual verification."
elif [[ ! -f "$DB_PATH" ]]; then
  printf "  Database not found at: %s\n" "$DB_PATH"
  cell_fail "transcripts.db not found — was the app launched with the correct data dir?"
else
  # Poll for a transcript row created in the last 30 seconds with cleaned_text set
  printf "  Querying %s for a recent cleaned transcript...\n" "$DB_PATH"
  THIRTY_SECONDS_AGO=$(( $(date +%s) - 30 ))
  # SQLite stores timestamps as ISO-8601 text. We compare as strings (they sort correctly).
  THRESHOLD_ISO=$(date -u -d "@$THIRTY_SECONDS_AGO" '+%Y-%m-%dT%H:%M:%S' 2>/dev/null \
    || date -u -r "$THIRTY_SECONDS_AGO" '+%Y-%m-%dT%H:%M:%S' 2>/dev/null \
    || date -u '+%Y-%m-%dT%H:%M:%S' --date="-30 seconds" 2>/dev/null \
    || echo "")

  if [[ -z "$THRESHOLD_ISO" ]]; then
    cell_manual "Could not compute ISO timestamp threshold — Cleanup assertion skipped."
  else
    CLEANED_COUNT=$(sqlite3 "$DB_PATH" \
      "SELECT COUNT(*) FROM transcripts WHERE created_at >= '$THRESHOLD_ISO' AND cleaned_text IS NOT NULL AND cleaned_text != '';" \
      2>/dev/null || echo "0")

    if [[ "$CLEANED_COUNT" -gt 0 ]]; then
      cell_pass "Found $CLEANED_COUNT transcript(s) with cleaned_text in the last 30 seconds."
    else
      RAW_COUNT=$(sqlite3 "$DB_PATH" \
        "SELECT COUNT(*) FROM transcripts WHERE created_at >= '$THRESHOLD_ISO';" \
        2>/dev/null || echo "0")
      if [[ "$RAW_COUNT" -gt 0 ]]; then
        cell_fail "Found $RAW_COUNT recent transcript(s) but cleaned_text is NULL — LLM cleanup may have failed."
      else
        cell_fail "No recent transcripts in the DB (threshold: $THRESHOLD_ISO). Capture may not have saved."
      fi
    fi
  fi
fi

# ── Cell 5/7: Export ──────────────────────────────────────────────────────────

cell_header "5/7" "Export (Markdown file on disk)"

if ! $CAPTURE_RAN; then
  printf "  MANUAL: From the PostCaptureCard or History, export the transcript\n"
  printf "          as Markdown via the native save dialog. Confirm the .md file\n"
  printf "          is created on disk with the expected content.\n"
  cell_manual "Capture cell did not run — Export requires a prior automated capture."
elif ! $HAS_XDOTOOL; then
  printf "  MANUAL: Use the app's export action to save the transcript as Markdown.\n"
  printf "          Confirm the .md file appears in your home directory.\n"
  cell_manual "xdotool not found — Export keystroke cannot be sent automatically."
else
  # The export shortcut is Ctrl+E (default). The save dialog is native OS — we cannot
  # drive it with xdotool reliably across all desktop environments. Instead, we check
  # whether any .md file was created in the last 30 seconds in the user's home directory.
  printf "  Checking for a Markdown export file created in the last 30 seconds...\n"
  EXPORT_FILE=$(find "$HOME" -maxdepth 3 -name "*.md" -newer /tmp/lumotia-smoke-driver-launch.log \
    2>/dev/null | head -1 || true)

  if [[ -n "$EXPORT_FILE" ]]; then
    # Verify frontmatter is present (non-empty --- block at the start of the file)
    if grep -q "^---" "$EXPORT_FILE" 2>/dev/null; then
      cell_pass "Export file found with frontmatter present."
      printf "  Path redacted (privacy invariant). Filename suffix: …%s\n" "${EXPORT_FILE: -20}"
    else
      cell_fail "Export file found but no YAML frontmatter (--- block) detected at the start."
    fi
  else
    printf "  No .md file found. If the native save dialog appeared, accept it and re-run.\n"
    printf "  MANUAL: In Lumotia → PostCaptureCard, press the Export button (or Ctrl+E),\n"
    printf "          save the file, then re-run this script to check Cell 5.\n"
    cell_manual "No .md export file detected — Export cell requires manual action."
  fi
fi

# ── Cell 6/7: History search ──────────────────────────────────────────────────

cell_header "6/7" "History search (FTS5 index)"

if ! $HAS_SQLITE3; then
  printf "  MANUAL: Open History (sidebar). Type a word from your dictation\n"
  printf "          in the search box. Confirm the transcript appears in results.\n"
  cell_manual "sqlite3 not found — FTS5 search requires manual verification."
elif [[ ! -f "$DB_PATH" ]]; then
  printf "  Database not found at: %s\n" "$DB_PATH"
  if $CAPTURE_RAN; then
    cell_fail "transcripts.db not found after an automated capture completed — data dir may be wrong."
  else
    printf "  No capture has run yet. Complete a recording first to populate the index.\n"
    cell_manual "No database found and no capture ran — History search cannot be verified automatically."
  fi
else
  # We cannot read transcript text (privacy invariant). Instead we verify:
  # 1. The FTS5 virtual table exists.
  # 2. At least one row exists in the index (implying the index is populated).
  printf "  Checking FTS5 index in %s...\n" "$DB_PATH"

  FTS_TABLE=$(sqlite3 "$DB_PATH" \
    "SELECT name FROM sqlite_master WHERE type='table' AND name LIKE '%fts%' LIMIT 1;" \
    2>/dev/null || echo "")

  if [[ -z "$FTS_TABLE" ]]; then
    cell_fail "No FTS5 table found in the database. History search is likely broken."
  else
    FTS_ROW_COUNT=$(sqlite3 "$DB_PATH" \
      "SELECT COUNT(*) FROM \"$FTS_TABLE\";" \
      2>/dev/null || echo "0")

    if [[ "$FTS_ROW_COUNT" -gt 0 ]]; then
      cell_pass "FTS5 table '$FTS_TABLE' exists and contains $FTS_ROW_COUNT indexed row(s)."
    elif $CAPTURE_RAN; then
      cell_fail "FTS5 table '$FTS_TABLE' exists but is empty after a capture was completed — indexing may be broken."
    else
      printf "  FTS5 table exists but is empty (no capture ran to populate it).\n"
      printf "  MANUAL: After completing a recording, verify that History search returns it.\n"
      cell_manual "FTS5 table is empty — no capture ran to populate the index."
    fi
  fi
fi

# ── Cell 7/7: Uninstall + reinstall preserves transcripts ────────────────────

cell_header "7/7" "Uninstall + reinstall preserves transcripts (dogfood rebrand drill)"

DRILL="$REPO_ROOT/scripts/dogfood-rebrand-drill.sh"
if [[ ! -f "$DRILL" ]]; then
  cell_fail "scripts/dogfood-rebrand-drill.sh not found — restore it before smoke-testing."
elif [[ ! -x "$DRILL" ]]; then
  cell_fail "scripts/dogfood-rebrand-drill.sh is not executable — run: chmod +x scripts/dogfood-rebrand-drill.sh"
else
  if bash "$DRILL" >/tmp/lumotia-smoke-driver-drill.log 2>&1; then
    cell_pass "dogfood-rebrand-drill.sh passed — data-dir migration + preservation verified (8/8 probes)."
  else
    cell_fail "dogfood-rebrand-drill.sh reported failures. See /tmp/lumotia-smoke-driver-drill.log for details."
    tail -20 /tmp/lumotia-smoke-driver-drill.log | sed 's/^/  /' || true
  fi
fi

# ── Summary ───────────────────────────────────────────────────────────────────

TOTAL=$((CELL_PASS + CELL_FAIL + CELL_MANUAL))

printf "\n"
printf "${BOLD}── Smoke driver summary ──────────────────────────────────────────────${RESET}\n"
printf "  Automated PASS : %d / %d\n" "$CELL_PASS" "$TOTAL"
printf "  MANUAL         : %d / %d\n" "$CELL_MANUAL" "$TOTAL"
printf "  FAIL           : %d / %d\n" "$CELL_FAIL" "$TOTAL"

if $HAS_VIRTUAL_AUDIO && $HAS_XDOTOOL && $HAS_SQLITE3; then
  printf "\n  All prereqs present. Cells closed automatically: Install, First-run,\n"
  printf "  Capture, Cleanup, History search, Uninstall+reinstall (6/7 when audio\n"
  printf "  source is wired to the app). Export is semi-automated (file detection).\n"
else
  printf "\n  Missing prereqs:\n"
  $HAS_XDOTOOL || printf "    • xdotool — enables First-run window detection + Capture hotkey driving\n"
  $HAS_SQLITE3 || printf "    • sqlite3  — enables Cleanup + History search assertions\n"
  $HAS_VIRTUAL_AUDIO || printf "    • lumotia-test audio source — see docs/release/virtual-audio-setup.md\n"
fi

printf "\n"

if [[ $CELL_FAIL -eq 0 ]]; then
  printf "${GREEN}${BOLD}✓ Linux smoke-driver complete: %d/%d automated PASS, %d/%d require manual verification.${RESET}\n\n" \
    "$CELL_PASS" "$TOTAL" "$CELL_MANUAL" "$TOTAL"
  exit 0
else
  printf "${RED}${BOLD}✗ Linux smoke-driver: %d/%d PASS, %d/%d FAILED, %d/%d manual.${RESET}\n\n" \
    "$CELL_PASS" "$TOTAL" "$CELL_FAIL" "$TOTAL" "$CELL_MANUAL" "$TOTAL"
  exit 1
fi
