#!/usr/bin/env bash
# Auftragsbuch: einen LUCY-Vorschlags-Branch ANNEHMEN — das PC-Gegenstück zu auftrag-annehmen.sh.
# Lucy (Electron) lebt auf dem Windows-PC (F:\Coding Stuff\lucy); dist liegt NICHT im Repo.
# Annehmen heißt darum: Merge auf main (hier, Box) → der PC zieht main, baut dist neu und
# startet Lucy neu, WENN sie lief (User-Entscheid: Lucy startet nur, wenn der Commander sie will).
# Schlägt am PC irgendetwas fehl, wird der Merge auf main automatisch revertiert — die laufende
# Lucy bleibt die alte (der PC-Runner stellt dist aus seinem Backup wieder her).
#
# Der PC wird über den PC-Executor (client/hermes-pc/executor.py, :7777, Bearer-Token aus
# ~/.hermes/config.yaml) gesteuert. /shell hat 60 s Timeout → der Build läuft DETACHED
# (deploy/lucy-annahme.ps1 im Lucy-Repo schreibt eine Status-Datei, wir pollen sie).
#
# Läuft wie der MC2-Runner als EIGENE systemd-Unit und als /tmp-Kopie (Selbst-Reset-Falle).
# Status-Schlüssel in der Auftragsbuch-JSON: "lucy:<branch>".
#
# Nutzung: lucy-annahme.sh <branch>     (z. B. wartung/turncheck-default-aus)
set -uo pipefail

BRANCH="${1:?Nutzung: lucy-annahme.sh <branch>}"
SRC="${MC2_SRC:-$HOME/mission-control-v2}"
LUCY="${MC2_LUCY_DIR:-$HOME/lucy}"
STATUS="${MC2_AUFTRAG_STATUS:-/srv/models/mc2-auftragsbuch.json}"
HERMES_CONF="${HERMES_CONF:-$HOME/.hermes/config.yaml}"
SLUG="lucy-$(echo "$BRANCH" | tr '/' '-')"
WT="/tmp/annahme-$SLUG"
LOG="/tmp/annahme-$SLUG.log"

# Windows-Seite (Pfade im PC-Dateisystem; einfach gehalten — EIN PC, EIN Checkout).
PC_REPO='F:\Coding Stuff\lucy'
PC_STATUSFILE='F:\Coding Stuff\lucy\.lucy-annahme.json'
PC_RUNNER='F:\Coding Stuff\lucy\deploy\lucy-annahme.ps1'
BUILD_TIMEOUT_S=1500   # 25 min Deckel für npm ci + tsc + electron-builder + Stimm-Warmup

notify(){ bash "$SRC/deploy/notify.sh" -s "[Auftragsbuch]" "$1" || true; }

# Status-Fortschritt für die UI (atomar via tmp+replace; die API liest die Datei nur).
status(){  # $1=state  $2=detail
  python3 - "$STATUS" "lucy:$BRANCH" "$1" "$2" <<'PY'
import json, os, sys, time
p, key, state, detail = sys.argv[1:5]
try:
    d = json.load(open(p, encoding="utf-8"))
except Exception:
    d = {}
d.setdefault("branches", {})[key] = {"state": state, "detail": detail, "ts": time.time()}
tmp = p + ".tmp"
json.dump(d, open(tmp, "w", encoding="utf-8"), ensure_ascii=False)
os.replace(tmp, p)
PY
}

# PC-Executor: PowerShell-Kommando ausführen. stdout des PCs → stdout; rc 0 nur wenn
# Transport UND Kommando grün. Token/URL kommen aus der Hermes-Config (kein zweiter Ablageort).
PC_URL="$(sed -n 's/^[[:space:]]*PC_EXECUTOR_URL:[[:space:]]*//p' "$HERMES_CONF" | head -1 | tr -d "\"'" | tr -d '[:space:]')"
PC_TOKEN="$(sed -n 's/^[[:space:]]*PC_EXECUTOR_TOKEN:[[:space:]]*//p' "$HERMES_CONF" | head -1 | tr -d "\"'" | tr -d '[:space:]')"
pc_shell(){  # $1 = PowerShell-Kommando
  python3 - "$PC_URL" "$PC_TOKEN" "$1" <<'PY'
import json, sys, urllib.request
url, token, cmd = sys.argv[1:4]
req = urllib.request.Request(url + "/shell", data=json.dumps({"command": cmd}).encode(),
                             headers={"Authorization": "Bearer " + token,
                                      "Content-Type": "application/json"})
try:
    r = json.load(urllib.request.urlopen(req, timeout=58))
except Exception as e:
    print(f"(PC-Executor nicht erreichbar: {e})")
    sys.exit(2)
out = (r.get("stdout") or "").strip()
if out:
    print(out)
err = (r.get("stderr") or "").strip()
if err:
    print(err, file=sys.stderr)
sys.exit(0 if r.get("returncode") == 0 else 1)
PY
}

cleanup_wt(){ git -C "$LUCY" worktree remove --force "$WT" 2>/dev/null || true; }

fail(){
  status "fehlgeschlagen" "$1"
  notify "Lucy-Vorschlag '$BRANCH' konnte NICHT eingespielt werden: $1 — nichts wurde verändert, der Branch bleibt liegen."
  cleanup_wt
  exit 1
}

# Revert nach schon gepushtem Merge (PC-Phase rot): main zurückdrehen, PC-Checkout nachziehen.
revert_main(){  # $1 = Grund für die Meldung
  status "rollback" "PC-Phase rot — Merge wird automatisch zurückgedreht"
  git -C "$LUCY" fetch -q origin || true
  cleanup_wt
  if git -C "$LUCY" worktree add --detach "$WT" origin/main >/dev/null 2>&1 \
     && git -C "$WT" -c user.name="Auftragsbuch" -c user.email="auftragsbuch@box.local" \
          revert -m 1 --no-edit HEAD >>"$LOG" 2>&1 \
     && git -C "$WT" push origin HEAD:main >>"$LOG" 2>&1; then
    cleanup_wt
    # PC-Checkout best-effort auf den revertierten Stand nachziehen (Quelle = laufende Lucy).
    pc_shell "git -C '$PC_REPO' fetch origin main 2>&1; git -C '$PC_REPO' merge --ff-only FETCH_HEAD 2>&1" >>"$LOG" 2>&1 || true
    status "zurueckgerollt" "$1 — Merge automatisch revertiert, Lucy läuft in der alten Version weiter"
    notify "Lucy-Vorschlag '$BRANCH' hat den PC-Build/Neustart GERISSEN: $1. Merge automatisch zurückgedreht — Lucy läuft in der alten Version weiter. Der Branch bleibt zur Analyse liegen. Log: $LOG"
    exit 1
  fi
  cleanup_wt
  status "kritisch" "Revert fehlgeschlagen — Lucy-Repo und PC von Hand prüfen"
  notify "KRITISCH: Lucy-Annahme '$BRANCH' scheiterte UND der automatische Revert schlug fehl — bitte Lucy-Repo (Gitea main) und PC prüfen. Log: $LOG"
  exit 2
}

[ -n "$PC_URL" ] && [ -n "$PC_TOKEN" ] || fail "PC-Executor-Zugang fehlt in $HERMES_CONF (PC_EXECUTOR_URL/TOKEN)"

# ── Vorprüfungen am PC (VOR dem Merge — solange ist nichts kaputtzumachen) ──
status "laeuft" "Vorprüfung: ist der PC bereit?"
curl -sf -m 8 "$PC_URL/health" >/dev/null 2>&1 \
  || fail "PC-Executor nicht erreichbar — Lucy-Annahme braucht den eingeschalteten PC (Executor-Task läuft bei Anmeldung)"

PC_BRANCH="$(pc_shell "git -C '$PC_REPO' rev-parse --abbrev-ref HEAD" 2>>"$LOG")" \
  || fail "PC-Arbeitskopie nicht lesbar (git am PC): $PC_BRANCH"
[ "$PC_BRANCH" = "main" ] || fail "PC-Arbeitskopie steht auf '$PC_BRANCH' statt main — bitte am PC aufräumen"

PC_DIRTY="$(pc_shell "git -C '$PC_REPO' status --porcelain -uno" 2>>"$LOG")" \
  || fail "PC-Arbeitskopie nicht prüfbar"
[ -z "$PC_DIRTY" ] || fail "PC-Arbeitskopie hat ungespeicherte Änderungen — bitte erst am PC committen/aufräumen: $(echo "$PC_DIRTY" | head -3 | tr '\n' ' ')"

WAS_RUNNING="$(pc_shell "if (Get-Process Lucy -ErrorAction SilentlyContinue) { '1' } else { '0' }" 2>>"$LOG")" || WAS_RUNNING="0"
case "$WAS_RUNNING" in 1|0) ;; *) WAS_RUNNING="0" ;; esac

# ── Merge auf main (Box, isolierter Worktree — wie beim MC2-Runner) ─────────
status "laeuft" "Merge wird vorbereitet"
git -C "$LUCY" fetch -q origin || fail "git fetch (Gitea) fehlgeschlagen"
git -C "$LUCY" rev-parse --verify -q "refs/remotes/origin/$BRANCH" >/dev/null \
  || fail "Branch origin/$BRANCH existiert nicht (schon gemergt/gelöscht?)"

# Kaputt aufgesetzte Branches (kein gemeinsamer Vorfahre) → Merge kann NIE gelingen.
git -C "$LUCY" merge-base origin/main "origin/$BRANCH" >/dev/null 2>&1 \
  || fail "Branch hat keinen gemeinsamen Ursprung mit main (kaputt aufgesetzt, z. B. git init statt Klonen) — bitte ablehnen (mit Grund) und die Idee neu in die Queue geben"

cleanup_wt
git -C "$LUCY" worktree add --detach "$WT" origin/main >/dev/null 2>&1 || fail "Worktree konnte nicht angelegt werden"
MERGE_MSG="Auftragsbuch: Lucy-Vorschlag '$BRANCH' angenommen (Ein-Klick-Gate)"
if ! git -C "$WT" -c user.name="Auftragsbuch" -c user.email="auftragsbuch@box.local" \
     merge --no-ff "origin/$BRANCH" -m "$MERGE_MSG" >>"$LOG" 2>&1; then
  git -C "$WT" merge --abort 2>/dev/null || true
  # Selbstheilung: veralteten Branch mechanisch auf main rebasen (wie im MC2-Runner).
  status "laeuft" "Merge-Konflikt — Auto-Rebase wird versucht"
  WT2="/tmp/annahme-rebase-$SLUG"
  git -C "$LUCY" worktree remove --force "$WT2" 2>/dev/null || true
  REBASED=""
  if git -C "$LUCY" worktree add --detach "$WT2" "origin/$BRANCH" >/dev/null 2>&1 \
     && git -C "$WT2" -c user.name="Auftragsbuch" -c user.email="auftragsbuch@box.local" \
          rebase origin/main >>"$LOG" 2>&1; then
    REBASED="$(git -C "$WT2" rev-parse HEAD)"
  else
    git -C "$WT2" rebase --abort 2>/dev/null || true
  fi
  git -C "$LUCY" worktree remove --force "$WT2" 2>/dev/null || true
  [ -n "$REBASED" ] || fail "Merge-Konflikt mit main, Auto-Rebase scheiterte ebenfalls — echter Inhaltskonflikt; am einfachsten ablehnen und die Idee neu in die Queue geben (frischer Branch von aktuellem main)"
  git -C "$WT" -c user.name="Auftragsbuch" -c user.email="auftragsbuch@box.local" \
      merge --no-ff "$REBASED" -m "$MERGE_MSG — auto-rebased (Branch war veraltet)" >>"$LOG" 2>&1 \
    || { git -C "$WT" merge --abort 2>/dev/null || true; fail "Merge nach Auto-Rebase fehlgeschlagen (unerwartet) — Log: $LOG"; }
fi

status "laeuft" "Push nach main läuft"
PUSHED=0
for _ in 1 2 3; do
  git -C "$WT" push origin HEAD:main >>"$LOG" 2>&1 && { PUSHED=1; break; }
  sleep 5
done
[ "$PUSHED" = 1 ] || fail "Push nach main fehlgeschlagen (Gitea nicht erreichbar / Token?)"
cleanup_wt

# ── PC: main ziehen, Build detached starten ─────────────────────────────────
status "laeuft" "PC zieht den neuen Stand"
pc_shell "git -C '$PC_REPO' fetch origin main 2>&1; if (\$LASTEXITCODE -ne 0) { exit 1 }; git -C '$PC_REPO' merge --ff-only FETCH_HEAD 2>&1" >>"$LOG" 2>&1 \
  || revert_main "PC konnte main nicht ziehen (git fetch/merge am PC rot)"

pc_shell "if (Test-Path '$PC_RUNNER') { exit 0 } else { exit 1 }" >>"$LOG" 2>&1 \
  || revert_main "PC-Runner-Skript fehlt im Lucy-Repo (deploy/lucy-annahme.ps1)"

# WICHTIG: -File-Pfad MUSS eingebettete Anführungszeichen tragen — Start-Process fügt
# die ArgumentList-Elemente OHNE Quoting zusammen; 'F:\Coding Stuff\…' zerbricht sonst am
# Leerzeichen und die gespawnte powershell stirbt still (erster Live-Lauf, 12.07.).
pc_shell "Remove-Item -Force '$PC_STATUSFILE' -ErrorAction SilentlyContinue; Start-Process powershell -WindowStyle Hidden -ArgumentList '-NoProfile','-ExecutionPolicy','Bypass','-File','\"$PC_RUNNER\"','-WasRunning','$WAS_RUNNING'" >>"$LOG" 2>&1 \
  || revert_main "PC-Build ließ sich nicht starten"

# ── Status-Datei pollen, Fortschritt in die UI spiegeln ─────────────────────
status "laeuft" "PC baut Lucy (dist) — das dauert ein paar Minuten"
DEADLINE=$(( $(date +%s) + BUILD_TIMEOUT_S ))
LAST_DETAIL=""
FINAL=""
while [ "$(date +%s)" -lt "$DEADLINE" ]; do
  sleep 10
  RAW="$(pc_shell "if (Test-Path '$PC_STATUSFILE') { Get-Content -Raw '$PC_STATUSFILE' }" 2>>"$LOG")" || continue
  [ -n "$RAW" ] || continue
  # Parse OHNE f-String-Escapes: \" in f-String-Ausdruecken ist seit Python 3.12/3.14
  # ein SyntaxError (alter Pre-3.12-Stil) — genau das legte den ersten Live-Lauf lahm.
  PARSED="$(printf '%s' "$RAW" | python3 -c '
import json, sys
try:
    d = json.loads(sys.stdin.read())
except Exception:
    sys.exit(0)
detail = str(d.get("detail", "")).replace("|", "/").replace("\n", " ")
done = "1" if d.get("done") else "0"
ok = "1" if d.get("ok") else "0"
print(done + "|" + ok + "|" + detail)
')"
  [ -n "$PARSED" ] || continue
  DONE="${PARSED%%|*}"; REST="${PARSED#*|}"; OK="${REST%%|*}"; DETAIL="${REST#*|}"
  if [ "$DETAIL" != "$LAST_DETAIL" ] && [ -n "$DETAIL" ]; then
    LAST_DETAIL="$DETAIL"
    status "laeuft" "PC: $DETAIL"
  fi
  if [ "$DONE" = "1" ]; then FINAL="$OK"; break; fi
done

[ -n "$FINAL" ] || revert_main "PC-Build-Timeout nach $((BUILD_TIMEOUT_S/60)) Minuten (Status-Datei blieb offen)"
[ "$FINAL" = "1" ] || revert_main "${LAST_DETAIL:-PC meldet Fehler ohne Detail}"

# ── Grün: Branch aufräumen, ehrlich melden ──────────────────────────────────
git -C "$LUCY" push origin --delete "$BRANCH" >>"$LOG" 2>&1 || true
git -C "$LUCY" fetch -q --prune origin 2>/dev/null || true
status "eingespielt" "${LAST_DETAIL:-Build grün}"
if [ "$WAS_RUNNING" = "1" ]; then
  notify "Lucy-Vorschlag '$BRANCH' ist LIVE — dist am PC neu gebaut, Lucy neu gestartet, Stimme meldet sich. ✅"
else
  notify "Lucy-Vorschlag '$BRANCH' ist eingespielt — dist am PC neu gebaut. Lucy war aus und bleibt aus; die neue Version startet beim nächsten Öffnen. ✅"
fi
exit 0
