#!/usr/bin/env bash
# Regenerate the website capture assets: search.webm, manage-indexing.webm,
# duplicates.png, query-highlight.png — all landing in packaging/captures/
# (gitignored). Needs a graphical session (X11 or Wayland — screenshots and
# video frames are read back from the app's own framebuffer, so the display
# server does not matter) and ffmpeg with libx264rgb and libvpx-vp9.
#
# The app is built with the `capture` feature and drives itself through
# packaging/capture-scenario.txt (see crates/quicksearch-gui/src/capture.rs
# for the command grammar). It runs against a throwaway index of this
# repository plus ~/.cargo/registry/src, under scratch XDG dirs — the real
# ~/.config/quicksearch and index are never touched.
#
# The scratch dirs live OUTSIDE both index roots on purpose: the demo config
# has an empty ignore list, so a scratch index database inside an indexed
# tree would be indexed and watched by the very run that writes it.
set -euo pipefail

here="$(cd "$(dirname "$0")" && pwd)"
repo="$(dirname "$here")"
out="$here/captures"
work="${TMPDIR:-/tmp}/quicksearch-capture"

# --- preflight --------------------------------------------------------------
if [ -z "${DISPLAY:-}" ] && [ -z "${WAYLAND_DISPLAY:-}" ]; then
    echo "capture needs a graphical session (neither DISPLAY nor" \
         "WAYLAND_DISPLAY is set)" >&2
    exit 1
fi
for tool in ffmpeg ffprobe cargo; do
    command -v "$tool" >/dev/null || { echo "missing tool: $tool" >&2; exit 1; }
done
# The encoder list is captured first: `grep -q` closing the pipe early would
# make ffmpeg exit on SIGPIPE, which pipefail reports as failure.
encoders="$(ffmpeg -hide_banner -encoders 2>/dev/null)"
for enc in libx264rgb libvpx-vp9; do
    grep -q "$enc" <<< "$encoders" \
        || { echo "ffmpeg lacks the $enc encoder" >&2; exit 1; }
done
# A config.toml beside the binary would silently override the scratch XDG
# config entirely (portable mode) — refuse to run with one present.
if [ -e "$repo/target/release/config.toml" ]; then
    echo "remove $repo/target/release/config.toml first: portable mode would" \
         "override the capture config" >&2
    exit 1
fi
registry="$HOME/.cargo/registry/src"
[ -d "$registry" ] || { echo "missing demo index root: $registry" >&2; exit 1; }

# --- build + parser tests ---------------------------------------------------
cargo test --manifest-path "$repo/Cargo.toml" --release --locked \
    -p quicksearch-gui --features capture capture::
cargo build --manifest-path "$repo/Cargo.toml" --release --locked \
    -p quicksearch-gui --features capture

# --- scratch environment ----------------------------------------------------
# Fresh every run: no stale index, no schema-mismatch prompt, and a fresh
# app.ron so the window opens at its default 1000x700 geometry.
rm -rf "$work"
mkdir -p "$work/config/quicksearch" "$work/data" "$work/tmp" "$out"
cat > "$work/config/quicksearch/config.toml" <<EOF
# Generated by packaging/capture.sh — the demo config for capture runs.
[paths]
indexing_paths = ["$repo", "$registry"]

[indexing]
auto_index = true
include_hidden = true
ignore_patterns = []

[search]
# Off for the run: on, the watcher arms over the visible rows mid-recording,
# re-reads them from disk and hands the paths back for reindexing — index
# writes inside a clip that is supposed to be reproducible.
live_results = false

[search.columns]
# Exactly the four the captures are choreographed around: Name, Path, Content
# Match, Rank. Every one is pinned rather than defaulted — the scenario's
# window widths are chosen for this column set, and `hover_match` addresses
# Content Match cells by index, so a shipped default that moved would silently
# re-frame or break the clips.
#
# Path is absent because it is not optional: it is always drawn (see
# `ColumnsConfig`, which deliberately does not represent it).
name = true
content_match = true
rank = true
size = false
modified = false

# 1.25x zoom + proportionally larger windows (set in the scenario) render the
# same layout at ~1.25x the pixel density, for crisper website assets.
#
# No `tutorial_seen` key here, deliberately: absent it deserializes to `None`,
# which reads as "an installation that upgraded into this version". Writing
# `false` would open the first-run tour over the first capture and wedge the
# run.
[ui]
scale = 1.25
EOF

# --- run the scripted app ---------------------------------------------------
# The outer timeout catches a wedged run; the driver's own hard timeouts
# should fire well before it.
echo "Running the capture scenario (the initial index build takes minutes)..."
env XDG_CONFIG_HOME="$work/config" \
    XDG_DATA_HOME="$work/data" \
    QS_CAPTURE_SCRIPT="$here/capture-scenario.txt" \
    QS_CAPTURE_OUT="$work/tmp" \
    timeout 2400 "$repo/target/release/quicksearch" \
    || { code=$?; echo "capture run failed (exit $code; 2=script parse," \
         "3=wait timeout, 4=io/ffmpeg, 124=hung)" >&2; exit 1; }

# --- transcode the lossless intermediates to VP9 webm -----------------------
# The recording itself is lossless, so webm quality is decided entirely here.
# QS_WEBM_CRF is the knob: constant-quality factor, 0 (best) to 63; UI text
# stays crisp around 24-32, and each step of ~6 roughly halves/doubles the
# file size. QS_WEBM_CPU trades encode time for compression efficiency
# (0 slowest/best to 5 fastest).
crf="${QS_WEBM_CRF:-26}"
cpu="${QS_WEBM_CPU:-0}"
for clip in manage-indexing search; do
    [ -s "$work/tmp/$clip.cap.mkv" ] \
        || { echo "missing recording: $clip.cap.mkv" >&2; exit 1; }
    # The crop drops at most one row/column: yuv420p needs even dimensions,
    # and fractional display scaling can make the window an odd size.
    ffmpeg -y -hide_banner -loglevel warning -i "$work/tmp/$clip.cap.mkv" \
        -vf "crop=trunc(iw/2)*2:trunc(ih/2)*2" \
        -c:v libvpx-vp9 -b:v 0 -crf "$crf" -deadline good -cpu-used "$cpu" \
        -row-mt 1 -pix_fmt yuv420p -an "$out/$clip.webm"
done
mv "$work/tmp/query-highlight.png" "$work/tmp/duplicates.png" "$out/"

# --- verify -----------------------------------------------------------------
fail=0
for f in "$out/search.webm" "$out/manage-indexing.webm"; do
    codec=$(ffprobe -v error -select_streams v:0 \
        -show_entries stream=codec_name -of csv=p=0 "$f")
    dur=$(ffprobe -v error -show_entries format=duration -of csv=p=0 "$f")
    [ "$codec" = vp9 ] || { echo "FAIL: $f codec=$codec" >&2; fail=1; }
    awk -v d="$dur" 'BEGIN{exit !(d>=4 && d<=60)}' \
        || { echo "FAIL: $f duration=${dur}s (expected 4-60s)" >&2; fail=1; }
    echo "OK: $f (vp9, ${dur}s)"
done
for f in "$out/duplicates.png" "$out/query-highlight.png"; do
    dims=$(ffprobe -v error -select_streams v:0 \
        -show_entries stream=width,height -of csv=p=0 "$f")
    echo "OK: $f (${dims})"
done
[ "$fail" -eq 0 ]

# $work is kept for post-mortems (app stderr is on this terminal; the scratch
# index and raw .cap.mkv files live there) and recreated fresh next run.
echo
echo "Assets:"
ls -l "$out"/*.webm "$out"/*.png
