#!/usr/bin/env bash
# Lance / arrête l'émulateur iPod Touch 2G (qemu-ios, N72AP).
set -euo pipefail

TOOLS_DIR=$(cd -- "$(dirname -- "${BASH_SOURCE[0]}")" && pwd)
DEFAULT_EMU_HOME="$HOME/ipod-emu"
# Les outils peuvent être utilisés directement depuis un home de toolchain déplacé.
[ ! -d "$TOOLS_DIR/../images" ] || DEFAULT_EMU_HOME=$(cd "$TOOLS_DIR/.." && pwd)
EMU_HOME="${IPOD_EMU_HOME:-$DEFAULT_EMU_HOME}"
QEMU="${IPOD_QEMU:-$(dirname "$EMU_HOME")/qemu-ios/build/qemu-system-arm}"
QEMU_DATA="${IPOD_QEMU_DATA:-$(dirname "$(dirname "$QEMU")")/pc-bios}"
FW="${IPOD_FW:-5H11a}"              # dossier $EMU_HOME/images/<FW>/ : bootrom, nor.bin, nand/ (5H11a = 2.2.1, 5F138 = 2.1.1)
RUN="$EMU_HOME/run"
VNC="${IPOD_VNC:-127.0.0.1:0}"      # :0 => port 5900

usage() {
    cat <<USAGE
Usage : ipod-emu start [-f] [-W] [-w FW]   démarre (headless, VNC $VNC, QMP $RUN/qmp.sock)
          -f     repart d'une NAND vierge (sinon garde l'état de la session précédente)
          -W     attend que SpringBoard soit prêt à recevoir des touches
          -w FW  firmware à utiliser (défaut : $FW ; dispo : $(ls "$EMU_HOME/images" 2>/dev/null | tr '\n' ' '))
        ipod-emu wait [SECONDES]    attend SpringBoard (défaut 300 s) — n'envoyez PAS de touch avant :
                                    le pilote tactile doit avoir terminé son démarrage
        ipod-emu stop | status | log | console
Pilotage (écran, touch, boutons) : ipod-qmp --help
USAGE
    exit "${1:-0}"
}

ready() {
    local n; n=$(grep -ac "AppleMultitouchSPIUserClient::attach" "$RUN/serial.log" 2>/dev/null); [ "${n:-0}" -ge 2 ] &&
        grep -aq 'SCHelper.*"EXIT"' "$RUN/serial.log"
}

wait_ready() {
    local t=${1:-300} s=$SECONDS
    # Le RTC D1759 fournit l'heure avant le démarrage des services iOS.
    until ready; do
        [ -n "$(pid)" ] || { echo "L'émulateur s'est arrêté (voir $RUN/qemu.log)" >&2; return 1; }
        grep -aq 'Fatal Exception\|MACH Reboot' "$RUN/serial.log" && { echo "Kernel panic / reboot (voir $RUN/serial.log)" >&2; return 1; }
        [ $((SECONDS - s)) -lt "$t" ] || { echo "Timeout : SpringBoard pas prêt après ${t}s" >&2; return 1; }
        sleep 2
    done
    sleep 3
    "$(dirname "$0")/ipod-agent" unlock
    echo "SpringBoard prêt et déverrouillé ($((SECONDS - s)) s)"
}

pid() { [ -f "$RUN/qemu.pid" ] && kill -0 "$(cat "$RUN/qemu.pid")" 2>/dev/null && cat "$RUN/qemu.pid"; }

stop_netd() {
    local netd_pid
    netd_pid=$(cat "$RUN/netd.pid" 2>/dev/null || true)
    if [ -n "$netd_pid" ] && [ -r "/proc/$netd_pid/comm" ] &&
       [ "$(cat "/proc/$netd_pid/comm")" = "ipod-netd" ]; then
        kill "$netd_pid" 2>/dev/null || true
    fi
    rm -f "$RUN/netd.pid"
}

cmd=${1:-}; shift || true
case $cmd in
start)
    fresh=0 waitr=0
    while getopts "fWw:" o; do case $o in f) fresh=1 ;; W) waitr=1 ;; w) FW=$OPTARG ;; *) usage 1 ;; esac; done
    img="$EMU_HOME/images/$FW"
    [ -d "$img" ] || { echo "Firmware inconnu : $img" >&2; exit 1; }
    if [ -n "$(pid)" ]; then
        echo "Déjà lancé (pid $(pid))"
        [ $waitr = 0 ] || wait_ready
        exit 0
    fi
    [ -x "$QEMU" ] || { echo "QEMU introuvable : $QEMU (définir IPOD_QEMU)" >&2; exit 1; }
    [ -r "$img/bootrom" ] || { echo "BootROM introuvable : $img/bootrom (vérifier les liens après déplacement du home)" >&2; exit 1; }
    [ -x "$EMU_HOME/netd/ipod-netd" ] || { echo "Relais réseau introuvable : $EMU_HOME/netd/ipod-netd" >&2; exit 1; }
    "$QEMU" --version >/dev/null
    qemu_data_args=()
    [ ! -d "$QEMU_DATA/keymaps" ] || qemu_data_args=(-L "$QEMU_DATA")
    mkdir -p "$RUN"
    if [ $fresh = 1 ] || [ ! -d "$RUN/nand" ] || [ "$(cat "$RUN/fw" 2>/dev/null)" != "$FW" ]; then
        rm -rf "$RUN/nand"; cp -rL "$img/nand" "$RUN/nand"; echo "$FW" > "$RUN/fw"
    fi
    stop_netd
    rm -f "$RUN/qmp.sock" "$RUN/serial.log"
    mopts=$(cat "$img/machine-opts" 2>/dev/null || true)   # ex. ",legacy-nor=off"
    if [[ "$mopts" == *",nand-write=on"* ]] &&
       [ "$(cat "$RUN/nand/.ipod-nand-format" 2>/dev/null || true)" != "vsvfl-production-v1" ]; then
        echo "NAND incompatible avec les écritures : reconstruire l'image avec ipod-mkimage / ipod-build-fw, puis démarrer avec -f." >&2
        exit 1
    fi
    nohup setsid "$QEMU" -M "iPod-Touch,bootrom=$img/bootrom,nand=$RUN/nand,nor=$img/nor.bin$mopts" \
        "${qemu_data_args[@]}" -cpu max -m 2G -serial "file:$RUN/serial.log" -serial "unix:$RUN/uart1.sock,server=on,wait=off" \
        -display none -vnc "$VNC" -qmp "unix:$RUN/qmp.sock,server,nowait" \
        -pidfile "$RUN/qemu.pid" ${IPOD_QEMU_EXTRA:-} > "$RUN/qemu.log" 2>&1 &
    qemu_pid=$!
    for _ in $(seq 50); do
        if ! kill -0 "$qemu_pid" 2>/dev/null; then
            echo "Échec du démarrage de QEMU :" >&2
            cat "$RUN/qemu.log" >&2
            exit 1
        fi
        [ ! -S "$RUN/qmp.sock" ] || [ -z "$(pid)" ] || break
        sleep 0.2
    done
    if [ ! -S "$RUN/qmp.sock" ] || [ -z "$(pid)" ]; then
        kill "$qemu_pid" 2>/dev/null || true
        echo "QEMU n'a pas ouvert son socket QMP (voir $RUN/qemu.log)" >&2
        exit 1
    fi
    # réseau : PPP sur l'UART1 -> slirp (NAT, DNS, 127.0.0.1:7788 -> agent de l'iPod)
    stop_netd
    nohup setsid "$EMU_HOME/netd/ipod-netd" -s "$RUN/uart1.sock" ${IPOD_NETD_FWD:-} > "$RUN/netd.log" 2>&1 &
    netd_pid=$!
    echo "$netd_pid" > "$RUN/netd.pid"
    sleep 0.3
    if ! kill -0 "$netd_pid" 2>/dev/null; then
        echo "Échec du relais réseau :" >&2
        cat "$RUN/netd.log" >&2
        "$(dirname "$0")/ipod-qmp" -s "$RUN/qmp.sock" quit 2>/dev/null || kill "$qemu_pid"
        stop_netd
        exit 1
    fi
    echo "Démarré ($FW) — pid $(pid), VNC $VNC. SpringBoard apparaît en ~1 min."
    echo "Logs iOS : $RUN/serial.log"
    [ $waitr = 0 ] || wait_ready
    ;;
wait) wait_ready "${1:-300}" ;;
stop)
    p=$(pid) || { stop_netd; echo "Pas lancé"; exit 0; }
    "$(dirname "$0")/ipod-qmp" -s "$RUN/qmp.sock" quit 2>/dev/null || kill "$p"
    for _ in $(seq 50); do kill -0 "$p" 2>/dev/null || break; sleep 0.2; done
    kill -0 "$p" 2>/dev/null && kill -9 "$p"
    stop_netd
    echo "Arrêté"
    ;;
status)
    if p=$(pid); then echo "En marche (pid $p, firmware $(cat "$RUN/fw"), VNC $VNC)"; else echo "Arrêté"; exit 1; fi
    ;;
log)     tail -f "$RUN/serial.log" ;;
console) tail -f "$RUN/qemu.log" ;;
-h|--help|help) usage ;;
*) usage 1 ;;
esac
