#!/usr/bin/env bash
# =============================================================================
# TimeMaster – Migrations-Sync-Check
#
# Prüft ob der lokale Alembic-Head mit dem Stand auf dem Server übereinstimmt.
# Gibt aus: lokaler Head, Server-Head, ob Sync nötig ist.
#
# Usage:
#   ./scripts/check_migrations.sh [137|164|both]
#
# Argumente:
#   137     Nur Server 192.168.1.137 prüfen (Standard)
#   164     Nur Server 192.168.1.164 prüfen
#   both    Beide Server prüfen
#
# Exit-Codes:
#   0   Alles synchron (oder Dry-Run)
#   1   Mindestens ein Server ist nicht synchron oder Fehler
# =============================================================================

set -euo pipefail

# =============================================================================
# KONFIGURATION
# =============================================================================
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
PROJECT_DIR="$(cd "$SCRIPT_DIR/.." && pwd)"
BACKEND_DIR="$PROJECT_DIR/backend"

SERVER_137="root@192.168.1.137"
SERVER_164="root@192.168.1.164"
REMOTE_PATH="/opt/timemaster"
REMOTE_VENV="$REMOTE_PATH/backend/venv"

# =============================================================================
# FARBEN & AUSGABE
# =============================================================================
RED='\033[0;31m'
GREEN='\033[0;32m'
YELLOW='\033[1;33m'
BLUE='\033[0;34m'
BOLD='\033[1m'
RESET='\033[0m'

ok()   { echo -e "  ${GREEN}✓ $*${RESET}"; }
fail() { echo -e "  ${RED}✗ $*${RESET}"; }
warn() { echo -e "  ${YELLOW}⚠ $*${RESET}"; }
info() { echo -e "    $*"; }
step() { echo -e "\n${BLUE}${BOLD}▶ $*${RESET}"; }
hr()   { echo -e "${BOLD}━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━${RESET}"; }

die() {
    echo ""
    fail "$1"
    exit 1
}

# =============================================================================
# ARGUMENT-PARSING
# =============================================================================
TARGET="${1:-137}"

case "$TARGET" in
    137)  SERVERS=("$SERVER_137") ;;
    164)  SERVERS=("$SERVER_164") ;;
    both) SERVERS=("$SERVER_137" "$SERVER_164") ;;
    --help|-h)
        awk '/^#!/{next} /^#/{sub(/^# ?/,""); print; next} /^[^#]/{exit}' "$0"
        exit 0
        ;;
    *)
        die "Unbekanntes Argument: $TARGET  (Erwartet: 137, 164 oder both)"
        ;;
esac

# =============================================================================
# PRE-FLIGHT: Lokales Alembic verfügbar?
# =============================================================================
hr
echo -e "${BOLD}  TimeMaster – Migrations-Sync-Check${RESET}"
echo -e "  Datum: $(date '+%Y-%m-%d %H:%M:%S')"
echo -e "  Ziel-Server: ${SERVERS[*]}"
hr

# Prüfe ob alembic.ini vorhanden
if [[ ! -f "$BACKEND_DIR/alembic.ini" ]]; then
    die "alembic.ini nicht gefunden: $BACKEND_DIR/alembic.ini"
fi

# Prüfe ob migrations/versions/ vorhanden
if [[ ! -d "$BACKEND_DIR/migrations/versions" ]]; then
    die "Migrations-Verzeichnis nicht gefunden: $BACKEND_DIR/migrations/versions"
fi

# =============================================================================
# LOKALEN ALEMBIC-HEAD ERMITTELN
# =============================================================================
step "Lokalen Alembic-Head ermitteln"

# Lokaler Head aus den Migrations-Dateien extrahieren (ohne echte DB-Verbindung)
# Strategie: letzte Migration via "down_revision" Kette auflösen
#
# Schnellere Methode: Migrations-Datei mit der höchsten Revisions-ID finden,
# die keine "down_revision" von einer anderen Datei ist (also Head-Node).
# Wir suchen alle revision-IDs und down_revision-IDs und finden die,
# die keine down_revision einer anderen ist.

LOCAL_HEAD=""
LOCAL_HEAD_FILE=""

# Alle .py-Dateien in migrations/versions/ einlesen
declare -A REVISION_MAP   # revision_id → dateiname
declare -A DOWN_REVISION  # revision_id → down_revision

while IFS= read -r migration_file; do
    # Revision-ID extrahieren (Zeile: revision = 'XXXX')
    rev=$(grep -oP "^revision\s*=\s*['\"]?\K[a-f0-9]+" "$migration_file" 2>/dev/null | head -1 || true)
    down=$(grep -oP "^down_revision\s*=\s*['\"]?\K[a-f0-9]+" "$migration_file" 2>/dev/null | head -1 || true)

    if [[ -n "$rev" ]]; then
        REVISION_MAP["$rev"]="$(basename "$migration_file")"
        DOWN_REVISION["$rev"]="${down:-}"
    fi
done < <(find "$BACKEND_DIR/migrations/versions" -name "*.py" -not -name "__pycache__" | sort)

MIGRATION_COUNT=${#REVISION_MAP[@]}
info "Gefundene Migrations-Dateien: $MIGRATION_COUNT"

if [[ $MIGRATION_COUNT -eq 0 ]]; then
    warn "Keine Migrations-Dateien gefunden in $BACKEND_DIR/migrations/versions/"
else
    # Head-Revision finden: diejenige, die von keiner anderen als down_revision referenziert wird
    for rev in "${!REVISION_MAP[@]}"; do
        IS_HEAD=true
        for other_rev in "${!DOWN_REVISION[@]}"; do
            if [[ "${DOWN_REVISION[$other_rev]}" == "$rev" ]]; then
                IS_HEAD=false
                break
            fi
        done
        if $IS_HEAD; then
            LOCAL_HEAD="$rev"
            LOCAL_HEAD_FILE="${REVISION_MAP[$rev]}"
            break
        fi
    done

    if [[ -n "$LOCAL_HEAD" ]]; then
        ok "Lokaler Head: $LOCAL_HEAD"
        info "Datei: $LOCAL_HEAD_FILE"
    else
        warn "Lokaler Head konnte nicht ermittelt werden (zyklische Abhängigkeiten oder keine Dateien?)"
        info "Tipp: Prüfe manuell mit: cd $BACKEND_DIR && alembic heads"
    fi
fi

# Fallback: Neueste Datei nach Namenskonvention (Präfix wie 0022_)
if [[ -z "$LOCAL_HEAD" ]]; then
    LATEST_FILE=$(ls -1 "$BACKEND_DIR/migrations/versions/"*.py 2>/dev/null | \
        grep -v '__' | sort -t'_' -k1,1 -V | tail -1 || true)
    if [[ -n "$LATEST_FILE" ]]; then
        LATEST_REV=$(grep -oP "^revision\s*=\s*['\"]?\K[a-f0-9]+" "$LATEST_FILE" 2>/dev/null | head -1 || true)
        if [[ -n "$LATEST_REV" ]]; then
            LOCAL_HEAD="$LATEST_REV"
            LOCAL_HEAD_FILE="$(basename "$LATEST_FILE")"
            warn "Fallback: Letzte Datei: $LOCAL_HEAD_FILE → $LOCAL_HEAD"
        fi
    fi
fi

# =============================================================================
# ALLE VERFÜGBAREN MIGRATIONEN ANZEIGEN
# =============================================================================
step "Lokale Migrations-Kette"

# Kette von unten nach oben aufbauen
if [[ ${#REVISION_MAP[@]} -gt 0 ]]; then
    # Startnode finden (down_revision ist leer oder None)
    CHAIN_CURRENT=""
    for rev in "${!DOWN_REVISION[@]}"; do
        if [[ -z "${DOWN_REVISION[$rev]}" ]]; then
            CHAIN_CURRENT="$rev"
            break
        fi
    done

    # Kette traversieren
    CHAIN_COUNT=0
    while [[ -n "$CHAIN_CURRENT" ]]; do
        CHAIN_FILE="${REVISION_MAP[$CHAIN_CURRENT]:-unbekannt}"
        MARKER=""
        [[ "$CHAIN_CURRENT" == "$LOCAL_HEAD" ]] && MARKER=" ${GREEN}← HEAD${RESET}"
        info "$CHAIN_FILE ($CHAIN_CURRENT)$MARKER"
        (( CHAIN_COUNT++ ))

        # Nächsten Node finden (der diesen als down_revision hat)
        NEXT_REV=""
        for rev in "${!DOWN_REVISION[@]}"; do
            if [[ "${DOWN_REVISION[$rev]}" == "$CHAIN_CURRENT" ]]; then
                NEXT_REV="$rev"
                break
            fi
        done
        CHAIN_CURRENT="$NEXT_REV"
    done

    if [[ $CHAIN_COUNT -eq 0 ]]; then
        info "(keine lineare Kette gefunden)"
    fi
fi

# =============================================================================
# SERVER-HEADS PRÜFEN
# =============================================================================
EXIT_CODE=0
declare -A SERVER_HEADS

for server in "${SERVERS[@]}"; do
    SERVER_SHORT="${server##*@}"
    step "Server $server: aktuellen Migrations-Stand abrufen"

    # SSH-Erreichbarkeit prüfen
    if ! ssh -o ConnectTimeout=10 -o BatchMode=yes "$server" "true" 2>/dev/null; then
        fail "SSH-Verbindung zu $server fehlgeschlagen"
        warn "Prüfe: ssh $server"
        SERVER_HEADS["$SERVER_SHORT"]="FEHLER (SSH)"
        EXIT_CODE=1
        continue
    fi

    # alembic current auf dem Server ausführen
    ALEMBIC_CMD="cd $REMOTE_PATH/backend && source $REMOTE_VENV/bin/activate && alembic current 2>&1"

    ALEMBIC_OUTPUT=$(ssh -o ConnectTimeout=20 -o BatchMode=yes "$server" "$ALEMBIC_CMD" 2>&1) \
        && ALEMBIC_RC=0 || ALEMBIC_RC=$?

    if [[ $ALEMBIC_RC -ne 0 ]]; then
        fail "alembic current FEHLGESCHLAGEN auf $server (Exit-Code: $ALEMBIC_RC)"
        echo "$ALEMBIC_OUTPUT" | while IFS= read -r line; do info "$line"; done
        warn "Mögliche Ursachen:"
        info "  - venv nicht vorhanden: $REMOTE_VENV"
        info "  - alembic.ini nicht auf dem Server: $REMOTE_PATH/backend/alembic.ini"
        info "  - DB-Verbindung auf dem Server fehlgeschlagen"
        info "  - Diagnose: ssh $server 'cd $REMOTE_PATH/backend && source $REMOTE_VENV/bin/activate && alembic current'"
        SERVER_HEADS["$SERVER_SHORT"]="FEHLER (alembic)"
        EXIT_CODE=1
        continue
    fi

    # Revision aus alembic-Ausgabe extrahieren
    # alembic current gibt aus: "abcd1234 (head)" oder "abcd1234"
    SERVER_REV=$(echo "$ALEMBIC_OUTPUT" | grep -oP "^[a-f0-9]{4,}" | head -1 || true)
    SERVER_IS_HEAD=$(echo "$ALEMBIC_OUTPUT" | grep -c "(head)" || true)

    if [[ -z "$SERVER_REV" ]]; then
        # Möglicherweise leere Datenbank (keine Migrationen gelaufen)
        if echo "$ALEMBIC_OUTPUT" | grep -qi "no current"; then
            SERVER_REV="(keine Migration gelaufen)"
            warn "Server $server: Noch keine Migration ausgeführt"
        else
            SERVER_REV="(unbekannt)"
            warn "Server $server: Revision konnte nicht aus alembic-Ausgabe extrahiert werden"
            info "alembic-Ausgabe:"
            echo "$ALEMBIC_OUTPUT" | while IFS= read -r line; do info "  $line"; done
        fi
        SERVER_HEADS["$SERVER_SHORT"]="$SERVER_REV"
        EXIT_CODE=1
        continue
    fi

    SERVER_HEADS["$SERVER_SHORT"]="$SERVER_REV"

    info "alembic-Ausgabe: $ALEMBIC_OUTPUT"

    # Vergleich: lokaler Head vs. Server
    if [[ -n "$LOCAL_HEAD" ]]; then
        if [[ "$SERVER_REV" == "$LOCAL_HEAD" ]]; then
            ok "Server $server ist SYNCHRON"
            info "  Lokaler Head : $LOCAL_HEAD ($LOCAL_HEAD_FILE)"
            info "  Server-Stand : $SERVER_REV"
            if [[ "$SERVER_IS_HEAD" -gt 0 ]]; then
                info "  Status       : (head)"
            fi
        else
            fail "Server $server ist NICHT synchron – Migration nötig!"
            info "  Lokaler Head : $LOCAL_HEAD ($LOCAL_HEAD_FILE)"
            info "  Server-Stand : $SERVER_REV"
            echo ""
            echo -e "  ${YELLOW}Zum Synchronisieren:${RESET}"
            echo -e "    ${YELLOW}ssh $server 'cd $REMOTE_PATH/backend && source $REMOTE_VENV/bin/activate && alembic upgrade head'${RESET}"
            echo -e "    ${YELLOW}# oder: ./update.sh --no-tests --no-frontend --server ${SERVER_SHORT}${RESET}"
            EXIT_CODE=1
        fi
    else
        warn "Kein lokaler Head bekannt – kein Vergleich möglich"
        info "  Server-Stand : $SERVER_REV"
    fi
done

# =============================================================================
# ZUSAMMENFASSUNG
# =============================================================================
echo ""
hr
echo -e "${BOLD}  Zusammenfassung${RESET}"
hr
echo ""
if [[ -n "$LOCAL_HEAD" ]]; then
    echo -e "  ${BOLD}Lokaler Head:${RESET}  $LOCAL_HEAD"
    echo -e "                ($LOCAL_HEAD_FILE)"
else
    echo -e "  ${BOLD}Lokaler Head:${RESET}  ${YELLOW}(konnte nicht ermittelt werden)${RESET}"
fi
echo ""

for server in "${SERVERS[@]}"; do
    SERVER_SHORT="${server##*@}"
    server_rev="${SERVER_HEADS[$SERVER_SHORT]:-unbekannt}"

    if [[ -n "$LOCAL_HEAD" && "$server_rev" == "$LOCAL_HEAD" ]]; then
        echo -e "  ${GREEN}✓${RESET} ${BOLD}$server${RESET}  →  $server_rev  ${GREEN}(synchron)${RESET}"
    elif [[ "$server_rev" == FEHLER* ]]; then
        echo -e "  ${RED}✗${RESET} ${BOLD}$server${RESET}  →  ${RED}$server_rev${RESET}"
    else
        echo -e "  ${RED}✗${RESET} ${BOLD}$server${RESET}  →  $server_rev  ${YELLOW}(Migration nötig)${RESET}"
    fi
done

echo ""
if [[ $EXIT_CODE -eq 0 ]]; then
    echo -e "  ${GREEN}${BOLD}Alle geprüften Server sind synchron.${RESET}"
else
    echo -e "  ${YELLOW}${BOLD}Mindestens ein Server benötigt eine Migration oder hat Fehler.${RESET}"
    echo ""
    echo -e "  ${YELLOW}Schnell-Sync (nur Migration + Restart):${RESET}"
    case "$TARGET" in
        137)  echo -e "    ./update.sh --no-tests --no-frontend --server 137" ;;
        164)  echo -e "    ./update.sh --no-tests --no-frontend --server 164" ;;
        both) echo -e "    ./update.sh --no-tests --no-frontend --server both" ;;
    esac
fi
hr

exit $EXIT_CODE
