#!/usr/bin/env bash
#
# rebreak-supervise.sh
# --------------------
# Backup-Sandwich-Bootstrap für iPhone-Supervision ohne sichtbaren Daten-Verlust.
#
#   1. idevicebackup2 encrypted Backup  -> ~/.rebreak-supervise/backups/<UDID>/
#   2. cfgutil prepare --supervised      -> wiped iPhone, Supervised-Flag setzen
#   3. idevicebackup2 restore            -> Daten zurück, Supervised-Flag persistiert
#   4. cfgutil install-profile           -> ReBreak-Schutz-Profil installieren
#
# Voraussetzungen (siehe README.md):
#   - macOS
#   - Apple Configurator 2 (App Store) + cfgutil im PATH
#   - libimobiledevice (brew install libimobiledevice)
#   - Supervision-Identity einmalig generiert (siehe SUPERVISION-IDENTITY-SETUP.md)
#   - iPhone via USB-C verbunden, Find-My DEAKTIVIERT, Code entsperrt
#   - Vertrauenshandshake (Trust-Dialog auf iPhone) bestätigt
#
# CLI:
#   rebreak-supervise.sh [--dry-run] [--state-dir DIR] [--profile PATH] [--resume]
#
# Status: PROTOTYPE. Einige Steps (cfgutil-Aufruf, Verify-Pfad) sind erst auf
# physischem Test-iPhone final verifiziert. Markierungen "VERIFY ON DEVICE" im
# Code zeigen wo Hardware-in-Loop noch nachgehärtet werden muss.

set -euo pipefail

# ------------------------------------------------------------------------------
# Konfiguration + Defaults
# ------------------------------------------------------------------------------

STATE_DIR="${REBREAK_STATE_DIR:-$HOME/.rebreak-supervise}"
PROFILE_PATH_DEFAULT="$(cd "$(dirname "$0")/.." && pwd)/profiles/rebreak-iphone-protection.mobileconfig"
PROFILE_PATH=""
DRY_RUN=0
RESUME=0

CFGUTIL="/Applications/Apple Configurator.app/Contents/MacOS/cfgutil"
SUPERVISION_IDENTITY_P12="${SUPERVISION_IDENTITY_P12:-$STATE_DIR/supervision-identity.p12}"
SUPERVISION_IDENTITY_PASS_FILE="${SUPERVISION_IDENTITY_PASS_FILE:-$STATE_DIR/supervision-identity.pass}"

# Farben (nur wenn TTY)
if [[ -t 1 ]]; then
    C_RESET="\033[0m"; C_RED="\033[1;31m"; C_GREEN="\033[1;32m"
    C_YELLOW="\033[1;33m"; C_BLUE="\033[1;34m"; C_DIM="\033[2m"
else
    C_RESET=""; C_RED=""; C_GREEN=""; C_YELLOW=""; C_BLUE=""; C_DIM=""
fi

# ------------------------------------------------------------------------------
# Helpers: Logging
# ------------------------------------------------------------------------------

LOG_FILE=""

log()  { printf "%b\n" "$1" | tee -a "${LOG_FILE:-/dev/null}"; }
ok()   { log "${C_GREEN}✓${C_RESET} $1"; }
warn() { log "${C_YELLOW}⚠${C_RESET} $1"; }
err()  { log "${C_RED}✗${C_RESET} $1" >&2; }
info() { log "${C_BLUE}→${C_RESET} $1"; }
dim()  { log "${C_DIM}  $1${C_RESET}"; }

die() { err "$1"; exit "${2:-1}"; }

confirm() {
    local prompt="$1"
    [[ "$DRY_RUN" == 1 ]] && { dim "[dry-run] auto-yes: $prompt"; return 0; }
    read -r -p "$(printf "%b" "${C_YELLOW}?${C_RESET} $prompt [y/N] ")" reply
    [[ "$reply" =~ ^[yY]$ ]]
}

run() {
    # Wraps a command: in dry-run, just echo. Otherwise execute.
    if [[ "$DRY_RUN" == 1 ]]; then
        dim "[dry-run] $*"
        return 0
    fi
    "$@"
}

# ------------------------------------------------------------------------------
# State-Management: simples JSON-ähnliches Format pro UDID
#
# Datei: $STATE_DIR/state-<UDID>.env (key=value, source-bar)
# Keys:  STEP_PREFLIGHT_AT, STEP_BACKUP_AT, BACKUP_PATH,
#        STEP_SUPERVISE_AT, STEP_RESTORE_AT, STEP_PROFILE_AT
# ------------------------------------------------------------------------------

state_file_for() { printf "%s/state-%s.env" "$STATE_DIR" "$1"; }

state_load() {
    local f; f="$(state_file_for "$1")"
    if [[ -f "$f" ]]; then
        # shellcheck disable=SC1090
        source "$f"
    fi
}

state_set() {
    # state_set UDID KEY VALUE
    local f; f="$(state_file_for "$1")"
    local key="$2"; local val="$3"
    # In-Memory-Update
    eval "$key=\"\$val\""
    # Persist (re-write each time, ist klein)
    local tmpf="${f}.tmp"
    {
        for k in STEP_PREFLIGHT_AT STEP_BACKUP_AT BACKUP_PATH STEP_SUPERVISE_AT STEP_RESTORE_AT STEP_PROFILE_AT BACKUP_PASSWORD_FILE; do
            local v="${!k:-}"
            [[ -n "$v" ]] && printf "%s=%q\n" "$k" "$v"
        done
    } > "$tmpf"
    mv "$tmpf" "$f"
    chmod 600 "$f"
}

# ------------------------------------------------------------------------------
# Step 0: Argumente parsen
# ------------------------------------------------------------------------------

usage() {
    cat <<EOF
Usage: $(basename "$0") [options]

Options:
  --dry-run               Befehle nur loggen, nicht ausführen
  --state-dir DIR         State-Verzeichnis (default: \$HOME/.rebreak-supervise)
  --profile PATH          Pfad zur .mobileconfig (default: ../profiles/rebreak-iphone-protection.mobileconfig)
  --resume                Bei vorhandenem State: bereits-erledigte Steps überspringen
  -h, --help              Diese Hilfe

Environment:
  REBREAK_STATE_DIR       Wie --state-dir
  SUPERVISION_IDENTITY_P12   Pfad zur Supervision-Identity (default: STATE_DIR/supervision-identity.p12)
EOF
}

while [[ $# -gt 0 ]]; do
    case "$1" in
        --dry-run)    DRY_RUN=1; shift ;;
        --state-dir)  STATE_DIR="$2"; shift 2 ;;
        --profile)    PROFILE_PATH="$2"; shift 2 ;;
        --resume)     RESUME=1; shift ;;
        -h|--help)    usage; exit 0 ;;
        *)            err "Unbekannte Option: $1"; usage; exit 2 ;;
    esac
done

PROFILE_PATH="${PROFILE_PATH:-$PROFILE_PATH_DEFAULT}"

mkdir -p "$STATE_DIR"
chmod 700 "$STATE_DIR"

LOG_FILE="$STATE_DIR/log-$(date +%Y%m%d-%H%M%S).txt"
touch "$LOG_FILE"

log ""
log "${C_BLUE}═══════════════════════════════════════════════════${C_RESET}"
log "${C_BLUE}  ReBreak iPhone Supervise Bootstrap${C_RESET}"
log "${C_BLUE}═══════════════════════════════════════════════════${C_RESET}"
log "State-Dir: $STATE_DIR"
log "Profile:   $PROFILE_PATH"
log "Log:       $LOG_FILE"
[[ "$DRY_RUN" == 1 ]] && warn "DRY-RUN-Modus aktiv — keine Aktion wird durchgeführt"
log ""

# ------------------------------------------------------------------------------
# Step 1: PREFLIGHT — Dependencies, Identity, Profil, Device-Detection
# ------------------------------------------------------------------------------

info "[1/5] Preflight"

# Tools
for bin in idevice_id ideviceinfo idevicebackup2; do
    command -v "$bin" >/dev/null 2>&1 \
        || die "Fehlt: $bin   → brew install libimobiledevice"
done
ok "libimobiledevice tools im PATH"

[[ -x "$CFGUTIL" ]] || die "cfgutil nicht gefunden: $CFGUTIL   → Apple Configurator 2 aus App Store installieren"
ok "cfgutil gefunden"

# Supervision-Identity
if [[ ! -f "$SUPERVISION_IDENTITY_P12" ]]; then
    die "Supervision-Identity fehlt: $SUPERVISION_IDENTITY_P12
       → siehe SUPERVISION-IDENTITY-SETUP.md (einmaliger Setup-Step)"
fi
ok "Supervision-Identity vorhanden"

# Profil
[[ -f "$PROFILE_PATH" ]] || die "Profil nicht gefunden: $PROFILE_PATH"
if ! plutil -lint "$PROFILE_PATH" >/dev/null 2>&1; then
    die "Profil ist kein gültiges Plist: $PROFILE_PATH"
fi
ok "Profil ist gültig"

# Connected device(s)
UDIDS="$(idevice_id -l 2>/dev/null || true)"
if [[ -z "$UDIDS" ]]; then
    die "Kein iPhone via USB erkannt. Stelle sicher:
       - USB-C-Kabel ist eingesteckt
       - iPhone ist entsperrt
       - 'Diesem Computer vertrauen?' wurde auf dem iPhone bestätigt"
fi

# Bei mehreren: erste, ggf. später interaktiv erweitern
UDID="$(echo "$UDIDS" | head -n1)"
log ""
info "Gerät: $UDID"

DEVICE_NAME="$(ideviceinfo -u "$UDID" -k DeviceName 2>/dev/null || echo "?")"
IOS_VERSION="$(ideviceinfo -u "$UDID" -k ProductVersion 2>/dev/null || echo "?")"
ACTIVATION="$(ideviceinfo -u "$UDID" -k ActivationState 2>/dev/null || echo "?")"
log "Name:        $DEVICE_NAME"
log "iOS:         $IOS_VERSION"
log "Activation:  $ACTIVATION"

# Activation-Check
if [[ "$ACTIVATION" != "Activated" ]]; then
    warn "ActivationState ist '$ACTIVATION' — Backup könnte scheitern"
fi

# State laden falls --resume
state_load "$UDID"
if [[ "$RESUME" == 1 ]]; then
    [[ -n "${STEP_BACKUP_AT:-}" ]]    && ok "[resume] Backup bereits erledigt: $STEP_BACKUP_AT"
    [[ -n "${STEP_SUPERVISE_AT:-}" ]] && ok "[resume] Supervise bereits erledigt: $STEP_SUPERVISE_AT"
    [[ -n "${STEP_RESTORE_AT:-}" ]]   && ok "[resume] Restore bereits erledigt: $STEP_RESTORE_AT"
    [[ -n "${STEP_PROFILE_AT:-}" ]]   && ok "[resume] Profil bereits installiert: $STEP_PROFILE_AT"
fi

state_set "$UDID" STEP_PREFLIGHT_AT "$(date -Iseconds)"
log ""

# ------------------------------------------------------------------------------
# Step 2: BACKUP (encrypted)
# ------------------------------------------------------------------------------

if [[ "$RESUME" == 1 && -n "${STEP_BACKUP_AT:-}" ]]; then
    info "[2/5] Backup übersprungen (resume)"
else
    info "[2/5] Backup (idevicebackup2, encrypted)"

    BACKUP_ROOT="$STATE_DIR/backups/$UDID"
    mkdir -p "$BACKUP_ROOT"

    # Encryption-Passwort: generieren wenn nicht vorhanden, persistieren
    BACKUP_PASSWORD_FILE="${BACKUP_PASSWORD_FILE:-$STATE_DIR/backup-pass-$UDID.txt}"
    if [[ ! -f "$BACKUP_PASSWORD_FILE" ]]; then
        if [[ "$DRY_RUN" != 1 ]]; then
            openssl rand -base64 24 > "$BACKUP_PASSWORD_FILE"
            chmod 600 "$BACKUP_PASSWORD_FILE"
            ok "Backup-Passwort generiert: $BACKUP_PASSWORD_FILE"
            warn "WICHTIG: dieses Passwort wird zum Restore gebraucht. Sicher aufheben."
        else
            dim "[dry-run] würde openssl rand -base64 24 > $BACKUP_PASSWORD_FILE"
        fi
    fi
    BACKUP_PASSWORD="$([[ -f "$BACKUP_PASSWORD_FILE" ]] && cat "$BACKUP_PASSWORD_FILE" || echo "DRYRUN")"

    warn "Backup kann je nach iPhone-Größe 15-60 Minuten dauern."
    warn "Diese Session NICHT abbrechen, USB-Kabel NICHT abziehen."
    confirm "Backup jetzt starten?" || die "Abgebrochen vom User" 0

    # Encryption aktivieren falls noch nicht
    # idevicebackup2 will die Backup-Encryption-Konfiguration auf dem Gerät selbst setzen
    # VERIFY ON DEVICE: ob 'encryption on' idempotent ist oder vorher 'encryption off' nötig
    run idevicebackup2 -u "$UDID" -i backup encryption on "$BACKUP_PASSWORD" "$BACKUP_ROOT" \
        || warn "Encryption-Setup hat returned non-zero — möglicherweise bereits aktiv, fahre fort"

    # Backup
    run idevicebackup2 -u "$UDID" -i backup "$BACKUP_ROOT"

    state_set "$UDID" BACKUP_PATH "$BACKUP_ROOT"
    state_set "$UDID" BACKUP_PASSWORD_FILE "$BACKUP_PASSWORD_FILE"
    state_set "$UDID" STEP_BACKUP_AT "$(date -Iseconds)"
    ok "Backup fertig: $BACKUP_ROOT"
fi
log ""

# ------------------------------------------------------------------------------
# Step 3: SUPERVISE — WIPED das Gerät, setzt Supervised-Flag
# ------------------------------------------------------------------------------

if [[ "$RESUME" == 1 && -n "${STEP_SUPERVISE_AT:-}" ]]; then
    info "[3/5] Supervise übersprungen (resume)"
else
    info "[3/5] Supervise (cfgutil prepare)"

    warn "DIESER SCHRITT WIPED DAS GERÄT."
    warn "Backup MUSS in Step 2 erfolgreich gewesen sein."
    warn "Find-My ist deaktiviert? Apple-ID-Passwort eingegeben? Falls nein: JETZT abbrechen."
    confirm "Wirklich fortfahren mit Wipe+Supervise?" || die "Abgebrochen vom User" 0

    # cfgutil-Aufruf — VERIFY ON DEVICE: exakte Syntax + ECID vs UDID
    # Apple-Doku-Stand: cfgutil unterstützt --ecid; UDID-Filter via --ecid in 0x-Hex
    # Für unsupervised+activated devices ist der einfachste Weg: alle connected devices
    # (es sollte nur eins angeschlossen sein zu diesem Zeitpunkt)
    run "$CFGUTIL" \
        --foreach \
        prepare \
        --supervised \
        --organization-name "ReBreak" \
        --supervisor-host-certs "$SUPERVISION_IDENTITY_P12"

    state_set "$UDID" STEP_SUPERVISE_AT "$(date -Iseconds)"
    ok "Supervise-Aufruf abgesetzt. Gerät reboots gerade — warte auf Wieder-Verbindung."
fi
log ""

# ------------------------------------------------------------------------------
# Step 4: WAIT FOR RECONNECT + RESTORE
# ------------------------------------------------------------------------------

if [[ "$RESUME" == 1 && -n "${STEP_RESTORE_AT:-}" ]]; then
    info "[4/5] Restore übersprungen (resume)"
else
    info "[4/5] Restore (warte auf Re-Verbindung, dann idevicebackup2 restore)"

    if [[ "$DRY_RUN" != 1 ]]; then
        log "Warte auf iPhone-Reconnect (max 5 min)..."
        for i in $(seq 1 60); do
            if idevice_id -l 2>/dev/null | grep -q "$UDID"; then
                ok "iPhone ist wieder verbunden"
                break
            fi
            sleep 5
            [[ $i -eq 60 ]] && die "Timeout: iPhone nicht innerhalb 5 min wieder verbunden"
        done

        # iOS-Setup-Assistant muss der User auf dem iPhone bis zum Punkt "Vom Backup wiederherstellen?"
        # bringen — oder wir restoren direkt via libimobiledevice (was wir hier tun)
        # VERIFY ON DEVICE: ob restore direkt nach Wipe geht (vor Setup-Assistant) oder
        # erst nach Setup-Assistant + initial-activation
        warn "iPhone zeigt jetzt 'Hallo'/Setup-Assistant."
        warn "Folge der Anleitung in README.md → 'Post-Supervise iPhone-Setup'."
        warn "Sobald iPhone die 'Mit Computer verbinden'-Stage erreicht: hier weiter."
        confirm "iPhone ist im Recovery-Setup-Stadium und bereit für Restore?" \
            || die "Abgebrochen vom User" 0
    fi

    BACKUP_PASSWORD="$(cat "$BACKUP_PASSWORD_FILE")"

    # VERIFY ON DEVICE: '-i restore' nimmt $BACKUP_ROOT als positional arg
    # Encryption-Passwort wird via stdin oder Env erwartet — idevicebackup2 v1.3+ unterstützt --password
    run idevicebackup2 -u "$UDID" -i restore \
        --system --reboot \
        --password "$BACKUP_PASSWORD" \
        "$BACKUP_PATH"

    state_set "$UDID" STEP_RESTORE_AT "$(date -Iseconds)"
    ok "Restore abgesetzt. iPhone reboots."
fi
log ""

# ------------------------------------------------------------------------------
# Step 5: INSTALL PROFIL + VERIFY
# ------------------------------------------------------------------------------

info "[5/5] Profil installieren + Verify"

if [[ "$DRY_RUN" != 1 ]]; then
    log "Warte auf iPhone-Reconnect post-restore (max 10 min)..."
    for i in $(seq 1 120); do
        if idevice_id -l 2>/dev/null | grep -q "$UDID"; then
            ok "iPhone ist wieder verbunden"
            break
        fi
        sleep 5
        [[ $i -eq 120 ]] && die "Timeout: iPhone nicht innerhalb 10 min wieder verbunden"
    done

    warn "User muss iOS jetzt entsperren + Setup-Assistant abschließen falls noch nicht."
    confirm "iPhone ist entsperrt und im Home-Screen?" || die "Abgebrochen vom User" 0
fi

# Profil installieren via cfgutil
# VERIFY ON DEVICE: 'cfgutil install-profile <path>' Syntax
run "$CFGUTIL" --foreach install-profile "$PROFILE_PATH"

state_set "$UDID" STEP_PROFILE_AT "$(date -Iseconds)"

# Verify supervised
if [[ "$DRY_RUN" != 1 ]]; then
    IS_SUPERVISED="$("$CFGUTIL" --foreach get isSupervised 2>/dev/null || echo "?")"
    log "Supervised-State (cfgutil get isSupervised): $IS_SUPERVISED"
fi

log ""
log "${C_GREEN}═══════════════════════════════════════════════════${C_RESET}"
log "${C_GREEN}  Bootstrap fertig${C_RESET}"
log "${C_GREEN}═══════════════════════════════════════════════════${C_RESET}"
log ""
log "Manueller Verify auf dem iPhone:"
log "  1. Settings → Allgemein → Info  → 'Dieses iPhone wird beaufsichtigt' sichtbar?"
log "  2. Long-Press auf Rebreak-Icon  → kein 'App löschen' mehr?"
log "  3. Settings → VPN → Rebreak     → Toggle disabled?"
log "  4. Settings → Allgemein → VPN, DNS und Gerätemanagement → Profil 'Nicht entfernbar'?"
log ""
log "Backend-Enrollment (separater Step):"
log "  → in der Rebreak-App: Profil-Tab → 'Schutz aktivieren' → QR scannen"
log ""
log "Logs:        $LOG_FILE"
log "State:       $(state_file_for "$UDID")"
log "Backup:      $BACKUP_PATH"
log "Backup-Pass: $BACKUP_PASSWORD_FILE  ${C_YELLOW}(sicher aufheben!)${C_RESET}"
