#!/bin/sh
# Single-emulator self-mirror E2E.
#
# Boot an AOSP API-35 emulator, root it, install the app, let it
# generate its keypair, copy that pubkey into /data/misc/adb/adb_keys
# so the app can connect to its own host's adbd over TCP, launch
# Mirror against 127.0.0.1:5555, wait for the first video frame in
# logcat, screencap, assert the frame is non-uniform.
#
# Runs inside the test image; orchestrated by ../test.

set -eu

ROOT=/work
# Debug applicationId (note the .debug suffix). Activity classes live in
# the invalid.lena.scrcpy namespace, which carries no suffix.
PKG=invalid.lena.scrcpy.debug
AVD=scrcpy-test
SERIAL=emulator-5554
APK=$ROOT/app/build/outputs/apk/debug/app-debug.apk
TMPDIR=$ROOT/.tools/e2e
mkdir -p "$TMPDIR"

log() { printf 'e2e: %s\n' "$*" >&2; }

# ---- 0. server jar ----
[ -f "$ROOT/app/src/main/assets/scrcpy-server.jar" ] || "$ROOT/scripts/update-server"

# ---- 1. build APK ----
log 'gradle :app:assembleDebug'
"$ROOT/gradlew" --no-daemon -q :app:assembleDebug

# ---- 2. AVD + boot ----
if ! avdmanager list avd | grep -q "Name: $AVD$"; then
    log "creating avd $AVD"
    echo no | avdmanager create avd -n "$AVD" -k 'system-images;android-35;default;x86_64' -d pixel >/dev/null
fi

# Clean stale lock files from a previously aborted run; otherwise the
# emulator refuses to start ("Running multiple emulators with the same AVD").
AVD_DIR="$ANDROID_AVD_HOME/$AVD.avd"
rm -f "$AVD_DIR"/multiinstance.lock "$AVD_DIR"/hardware-qemu.ini.lock 2>/dev/null || true
rm -rf "$HOME/.android/avd/running" 2>/dev/null || true

if ! pgrep -f "emulator.*-avd $AVD" >/dev/null; then
    log 'booting emulator (no window, no snapshot)'
    emulator -avd "$AVD" -no-window -no-audio -no-snapshot -gpu swiftshader_indirect \
             -no-boot-anim -accel on >"$TMPDIR/emulator.log" 2>&1 &
fi

log 'wait-for-device'
adb -s "$SERIAL" wait-for-device
log 'wait for boot'
until [ "$(adb -s "$SERIAL" shell getprop sys.boot_completed | tr -d '\r')" = 1 ]; do
    sleep 2
done

# ---- 3. root (emulator adbd already listens on TCP 5555) ----
log 'adb root'
adb -s "$SERIAL" root
adb -s "$SERIAL" wait-for-device

# ---- 4. install ----
log "install $APK"
adb -s "$SERIAL" install -r "$APK" >/dev/null

# ---- 5. let the app generate its keypair ----
log "launching Main once so Adb.java writes filesDir/adbkey"
adb -s "$SERIAL" shell am start -W -n "$PKG/invalid.lena.scrcpy.Main" >/dev/null
# Adb.java writes the keypair inside its constructor, before setContentView
sleep 1

# ---- 6. extract pubkey and authorise ----
log 'reading filesDir/adbkey via run-as'
adb -s "$SERIAL" shell "run-as $PKG cat files/adbkey" > "$TMPDIR/adbkey.der"
if [ ! -s "$TMPDIR/adbkey.der" ]; then
    log 'adbkey was empty - did Adb.java run?'
    adb -s "$SERIAL" logcat -d -t 200 -s scrcpy-android >&2 || true
    exit 1
fi

log 'computing android pubkey blob'
java "$ROOT/test-rig/Keygen.java" "$TMPDIR/adbkey.der" > "$TMPDIR/adb_keys.line"

log 'appending to /data/misc/adb/adb_keys'
adb -s "$SERIAL" push "$TMPDIR/adb_keys.line" /sdcard/adb_keys.line >/dev/null
adb -s "$SERIAL" shell "cat /sdcard/adb_keys.line >> /data/misc/adb/adb_keys \
                        && chown system:shell /data/misc/adb/adb_keys \
                        && chmod 640 /data/misc/adb/adb_keys \
                        && rm /sdcard/adb_keys.line"

# adbd rereads /data/misc/adb/adb_keys on every AUTH challenge,
# so no daemon restart is necessary. Restarting it would put the
# host's adb client into 'offline' state and force a reconnect dance.

# ---- 7. trigger Mirror ----
log 'starting Mirror -> 127.0.0.1:5555'
adb -s "$SERIAL" logcat -c
adb -s "$SERIAL" shell am start -n "$PKG/invalid.lena.scrcpy.Mirror" \
        --es host 127.0.0.1 --ei port 5555 >/dev/null

# ---- 8. wait for first frame, fail on session give-up ----
# Server's openAbstract budget (Server.OPEN_DEADLINE_MS) must stay
# shorter than this deadline; otherwise our retries finish before
# we've given the wire a chance.
deadline=$(( $(date +%s) + ${E2E_DEADLINE:-60} ))
ok=
while [ "$(date +%s)" -lt "$deadline" ]; do
    line=$(adb -s "$SERIAL" logcat -d -s scrcpy-android | tail -200)
    if printf '%s' "$line" | grep -q 'video frame n=1'; then
        ok=1; break
    fi
    if printf '%s' "$line" | grep -q 'session: gave up'; then
        log 'session gave up; logcat:'
        printf '%s\n' "$line" | tail -50 >&2
        exit 1
    fi
    sleep 1
done
if [ -z "$ok" ]; then
    log 'timed out waiting for video frame n=1'
    log "full app log: $TMPDIR/logcat.scrcpy"
    adb -s "$SERIAL" logcat -d -s scrcpy-android > "$TMPDIR/logcat.scrcpy" 2>&1 || true
    log "full system log: $TMPDIR/logcat.full"
    adb -s "$SERIAL" logcat -d > "$TMPDIR/logcat.full" 2>&1 || true
    log 'last 80 scrcpy-android lines:'
    tail -80 "$TMPDIR/logcat.scrcpy" >&2 || true
    exit 1
fi
log 'video frame n=1 - proceeding to screencap'

# Give the decoder a moment to actually render to the surface.
sleep 1

# ---- 9. screencap + pixhash ----
adb -s "$SERIAL" exec-out screencap -p > "$TMPDIR/shot.png"
log "screencap $(wc -c <"$TMPDIR/shot.png") bytes"
java "$ROOT/test-rig/Pixhash.java" "$TMPDIR/shot.png" --min 5

# ---- 9b. mid-session disconnect -> auto-reconnect ----
# Kill the scrcpy server on the target out from under the app. The video
# socket dies; Session.run() must detect it, rerun the bring-up ladder,
# and a fresh VideoStream must log 'video frame n=1' again. Clear logcat
# first so the only frame we can match is the post-reconnect one.
log 'forcing a mid-session disconnect (pkill scrcpy server on target)'
adb -s "$SERIAL" logcat -c
adb -s "$SERIAL" shell 'pkill -f com.genymobile.scrcpy.Server' || true

rdeadline=$(( $(date +%s) + ${E2E_RECONNECT_DEADLINE:-60} ))
relink=
while [ "$(date +%s)" -lt "$rdeadline" ]; do
    if adb -s "$SERIAL" logcat -d -s scrcpy-android | grep -q 'video frame n=1'; then
        relink=1; break
    fi
    sleep 1
done
if [ -z "$relink" ]; then
    log 'timed out waiting for auto-reconnect (no fresh video frame n=1)'
    adb -s "$SERIAL" logcat -d -s scrcpy-android > "$TMPDIR/logcat.reconnect" 2>&1 || true
    log "full app log: $TMPDIR/logcat.reconnect"
    tail -80 "$TMPDIR/logcat.reconnect" >&2 || true
    exit 1
fi
log 'auto-reconnect ok - fresh video frame n=1 after link loss'

# ---- 10. cleanup ----
log "full app log: $TMPDIR/logcat.scrcpy"
adb -s "$SERIAL" logcat -d -s scrcpy-android > "$TMPDIR/logcat.scrcpy" 2>&1 || true
log 'adb emu kill'
adb -s "$SERIAL" emu kill || true

log 'e2e: pass'
