#!/usr/bin/env bash
# Auftragsbuch: einen Vorschlags-Branch ANNEHMEN — der letzte Meter des propose-only-Kreislaufs.
# Werkstatt/Orchestrator liefern Branches (wartung/*, orchestrator/*), der Commander klickt in
# der Zentrale „Annehmen" → dieses Skript macht die bisherige Git-Handarbeit: Merge im
# isolierten Worktree (Lehre: NIE im Live-Checkout arbeiten) → Push nach main → Deploy →
# Health-Check → bei Rot automatischer Revert + Redeploy + Alarm.
#
# WICHTIG: läuft als EIGENE systemd-Unit (systemd-run, startet routers/auftragsbuch.py),
# NICHT als Kind des Backends — deploy.sh startet mission-control-2 neu und würde sonst
# den eigenen Eltern-Prozess mitten im Lauf töten. Außerdem wird es vom Backend als
# /tmp-KOPIE gestartet (deploy.sh macht git reset --hard → die Datei unter den Füßen
# eines laufenden bash zu tauschen korrumpiert das Skript, bekannte Falle).
#
# Nutzung: auftrag-annehmen.sh <branch>     (z. B. wartung/saubere-zusammenfassung)
set -uo pipefail

BRANCH="${1:?Nutzung: auftrag-annehmen.sh <branch>}"
SRC="${MC2_SRC:-$HOME/mission-control-v2}"
STATUS="${MC2_AUFTRAG_STATUS:-/srv/models/mc2-auftragsbuch.json}"
API="${MC_API:-http://127.0.0.1:9001}"
SLUG="$(echo "$BRANCH" | tr '/' '-')"
WT="/tmp/annahme-$SLUG"
LOG="/tmp/annahme-$SLUG.log"

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" "$BRANCH" "$1" "$2" <<'PY'
import json, os, sys, time
p, branch, state, detail = sys.argv[1:5]
try:
    d = json.load(open(p, encoding="utf-8"))
except Exception:
    d = {}
d.setdefault("branches", {})[branch] = {"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
}

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

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

status "laeuft" "Merge wird vorbereitet"
cd "$SRC" || fail "Live-Checkout $SRC fehlt"
git fetch -q origin || fail "git fetch (Gitea) fehlgeschlagen"
git rev-parse --verify -q "refs/remotes/origin/$BRANCH" >/dev/null \
  || fail "Branch origin/$BRANCH existiert nicht (schon gemergt/gelöscht?)"

PRE="$(git rev-parse origin/main)"

# Kaputt aufgesetzte Branches (Worker machte git init/Shallow statt zu klonen) haben KEINEN
# gemeinsamen Vorfahren — git verweigert den Merge immer. Ehrlich sagen statt „Konflikt".
git 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"

# Isolierter Worktree — der Live-Checkout bleibt bis zum Deploy unberührt.
cleanup_wt
git worktree add --detach "$WT" origin/main >/dev/null 2>&1 || fail "Worktree konnte nicht angelegt werden"
MERGE_MSG="Auftragsbuch: '$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 (zweiter Worktree am
  # Branch-Kopf). Klappt das sauber, wird der rebasede Stand gemergt — kein PC nötig.
  status "laeuft" "Merge-Konflikt — Auto-Rebase wird versucht"
  WT2="/tmp/annahme-rebase-$SLUG"
  git worktree remove --force "$WT2" 2>/dev/null || true
  REBASED=""
  if git 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 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

# py_compile-Gate über die durch den Merge geänderten Python-Dateien (AGENTS.md-Regel).
PYS="$(git -C "$WT" diff --name-only "$PRE"..HEAD -- '*.py' 2>/dev/null | tr '\n' ' ')"
if [ -n "${PYS// /}" ]; then
  PYBIN="$SRC/backend/.venv/bin/python"; [ -x "$PYBIN" ] || PYBIN="python3"
  # shellcheck disable=SC2086
  ( cd "$WT" && "$PYBIN" -m py_compile $PYS ) >>"$LOG" 2>&1 || fail "py_compile-Gate rot — der Patch enthält kaputtes Python"
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

status "laeuft" "Deploy läuft — die Zentrale startet gleich kurz neu"
notify "Vorschlag '$BRANCH' angenommen: Merge auf main ist durch, Deploy läuft. Die Zentrale ist gleich kurz weg."

# deploy.sh als Kopie ausführen (Selbst-Reset-Falle: es resettet das Repo, in dem es liegt).
cp "$SRC/deploy/deploy.sh" "/tmp/annahme-deploy-$SLUG.sh"
DEPLOY_OK=1
bash "/tmp/annahme-deploy-$SLUG.sh" >>"$LOG" 2>&1 || DEPLOY_OK=0

# Health-Check mit Geduld (Dienst-Neustart + Warmup brauchen einen Moment).
HEALTH=0
if [ "$DEPLOY_OK" = 1 ]; then
  for _ in $(seq 1 18); do
    curl -sf -m 5 "$API/api/health" >/dev/null 2>&1 && { HEALTH=1; break; }
    sleep 5
  done
fi

if [ "$HEALTH" = 1 ]; then
  # Gemergt + live + grün → der Remote-Branch hat seinen Zweck erfüllt.
  git -C "$SRC" push origin --delete "$BRANCH" >>"$LOG" 2>&1 || true
  git -C "$SRC" fetch -q --prune origin 2>/dev/null || true
  status "eingespielt" "Deploy grün, Health-Check bestanden"
  notify "Vorschlag '$BRANCH' ist LIVE — Deploy grün, Health-Check bestanden. ✅"
  exit 0
fi

# ── Rollback: Merge revertieren, main zurückschieben, neu deployen, Alarm ──
status "rollback" "Health rot — automatischer Revert läuft"
git fetch -q origin || true
cleanup_wt
if git 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
  cp "$SRC/deploy/deploy.sh" "/tmp/annahme-rollback-$SLUG.sh"
  bash "/tmp/annahme-rollback-$SLUG.sh" >>"$LOG" 2>&1 || true
  R=0
  for _ in $(seq 1 12); do
    curl -sf -m 5 "$API/api/health" >/dev/null 2>&1 && { R=1; break; }
    sleep 5
  done
  if [ "$R" = 1 ]; then
    status "zurueckgerollt" "Health blieb rot — Merge automatisch revertiert, Box läuft wieder"
    notify "Vorschlag '$BRANCH' hat den Health-Check GERISSEN. Automatisch zurückgerollt — die Box läuft wieder auf dem alten Stand. Der Branch bleibt zur Analyse liegen. Log: $LOG"
    exit 1
  fi
fi
cleanup_wt
status "kritisch" "Rollback fehlgeschlagen — Box braucht Hilfe"
curl -sf -m 5 -X POST "$API/api/alarm" -H 'Content-Type: application/json' \
  --data "{\"subject\":\"[Auftragsbuch]\",\"text\":\"KRITISCH: Annehmen von $BRANCH UND Rollback fehlgeschlagen — Zentrale prüfen. Log: $LOG\"}" >/dev/null 2>&1 \
  || notify "KRITISCH: Annehmen von '$BRANCH' UND Rollback fehlgeschlagen — bitte Box prüfen (restore.sh liegt bereit). Log: $LOG"
exit 2
