# ============================================================
# checkpoint.ps1
# ------------------------------------------------------------
# Wird von checkpoint.cmd aufgerufen. Liest
# .checkpoint-pending.txt, haengt einen Eintrag an changelog.md
# an (mit aktuellem Timestamp vom lokalen PC), fuehrt einen
# Git-Commit aus und loescht die Pending-Datei.
#
# Robust gegen problematische Eingabedaten:
# - Doppelte Anfuehrungszeichen in der Zusammenfassung werden
#   sauber durchgereicht, weil die Commit-Message via
#   "git commit -F <tempfile>" uebergeben wird (keine
#   Shell-Argument-Quoting-Probleme).
# - Pipe-Zeichen "|" in der Zusammenfassung werden abgelehnt,
#   weil sie mit dem Changelog-Format
#   Timestamp | Session | Summary kollidieren.
# - Whitespace und Zeilenumbrueche in der Zusammenfassung
#   werden zu einem Leerzeichen normalisiert.
# - Bei Fehler im Hauptablauf wird der Anhang an changelog.md
#   und die Index-Stagung von changelog.md zurueckgerollt,
#   sodass der naechste Lauf nicht doppelt anhaengt.
# - Eine verwaiste .git/index.lock wird vor dem Lauf erkannt
#   und mit klarer Anleitung gemeldet.
# ============================================================

$ErrorActionPreference = 'Stop'

# --- Pfade -------------------------------------------------
$repoRoot = $PSScriptRoot
Set-Location $repoRoot

$pendingFile   = Join-Path $repoRoot '.checkpoint-pending.txt'
$changelogFile = Join-Path $repoRoot 'changelog.md'
$gitDir        = Join-Path $repoRoot '.git'
$indexLock     = Join-Path $gitDir   'index.lock'

$utf8NoBom = New-Object System.Text.UTF8Encoding $false

# --- Pre-flight Checks -------------------------------------
if (-not (Test-Path $pendingFile)) {
    Write-Error ".checkpoint-pending.txt nicht gefunden."
    exit 1
}
if (-not (Test-Path $changelogFile)) {
    Write-Error "changelog.md nicht gefunden."
    exit 1
}
if (-not (Test-Path $gitDir)) {
    Write-Error ".git-Verzeichnis nicht gefunden ($gitDir)."
    exit 1
}
if (Test-Path $indexLock) {
    Write-Error ".git/index.lock existiert bereits. Eine vorherige Git-Operation hat sich nicht aufgeraeumt. Falls kein Git-Prozess mehr laeuft, manuell loeschen: Remove-Item '$indexLock' -Force"
    exit 1
}

# changelog.md darf vor dem Lauf keine lokalen Aenderungen haben,
# damit ein eventueller Rollback eindeutig bleibt.
$clStatus = & git status --porcelain -- changelog.md 2>$null
if ($LASTEXITCODE -ne 0) {
    Write-Error "git status fehlgeschlagen (Exit Code $LASTEXITCODE). Liegt das Repo in einem konsistenten Zustand vor?"
    exit 1
}
if ($null -ne $clStatus -and ($clStatus -join '').Trim() -ne '') {
    Write-Error "changelog.md hat lokale Aenderungen. Bitte erst per Hand committen oder mit 'git checkout -- changelog.md' verwerfen, bevor checkpoint.cmd laeuft."
    exit 1
}

# --- Pending-Datei einlesen --------------------------------
$lines = Get-Content $pendingFile -Encoding UTF8
if ($lines.Count -lt 2) {
    Write-Error ".checkpoint-pending.txt muss mindestens 2 Zeilen enthalten (Session, Zusammenfassung)."
    exit 1
}

$session = $lines[0].Trim()
$summaryLines = $lines | Select-Object -Skip 1 | Where-Object { $_.Trim() -ne '' }
$summary = ($summaryLines -join ' ')
# Whitespace und Steuerzeichen normalisieren
$summary = ($summary -replace '\s+', ' ').Trim()

if ([string]::IsNullOrWhiteSpace($session)) {
    Write-Error "Session-Nummer (Zeile 1) ist leer."
    exit 1
}
if ($session -notmatch '^S\d{2,}$') {
    Write-Error "Session-Nummer '$session' hat nicht das Format S<NN> (z.B. S01, S12)."
    exit 1
}
if ([string]::IsNullOrWhiteSpace($summary)) {
    Write-Error "Zusammenfassung (Zeile 2+) ist leer."
    exit 1
}
if ($summary -match '\|') {
    Write-Error "Zusammenfassung enthaelt das Pipe-Zeichen '|', das mit dem Changelog-Format Timestamp | Session | Summary kollidiert. Bitte ersetzen."
    exit 1
}

# --- Timestamp und Eintrag bauen ---------------------------
$timestamp = Get-Date -Format 'yyyy-MM-dd HH:mm'
$entry     = "$timestamp | $session | $summary"
$commitMsg = "${session}: $summary"

Write-Host ""
Write-Host "[checkpoint] Neuer Eintrag:" -ForegroundColor Cyan
Write-Host "  $entry"
Write-Host ""

# --- Backup fuer Rollback und Temp-Message-Datei -----------
$originalChangelog = [System.IO.File]::ReadAllText($changelogFile, $utf8NoBom)
$tempMsgFile = Join-Path ([System.IO.Path]::GetTempPath()) ("checkpoint-msg-" + [guid]::NewGuid().ToString() + ".txt")

# --- Hauptablauf -------------------------------------------
$success  = $false
$errorMsg = $null
try {
    # 1. Sicherstellen, dass changelog.md mit Newline endet
    if ($originalChangelog.Length -gt 0 -and -not ($originalChangelog.EndsWith("`n"))) {
        [System.IO.File]::AppendAllText($changelogFile, "`r`n", $utf8NoBom)
    }

    # 2. Eintrag anhaengen
    [System.IO.File]::AppendAllText($changelogFile, $entry + "`r`n", $utf8NoBom)
    Write-Host "[checkpoint] An changelog.md angehaengt." -ForegroundColor Green

    # 3. Commit-Message-Datei schreiben (UTF-8 ohne BOM)
    [System.IO.File]::WriteAllText($tempMsgFile, $commitMsg + "`n", $utf8NoBom)

    # 4. git add -A
    & git add -A
    if ($LASTEXITCODE -ne 0) {
        throw "git add fehlgeschlagen (Exit Code $LASTEXITCODE)."
    }

    # 5. git commit -F <tempfile> (umgeht Shell-Argument-Quoting)
    & git commit -F $tempMsgFile
    if ($LASTEXITCODE -ne 0) {
        throw "git commit fehlgeschlagen (Exit Code $LASTEXITCODE)."
    }

    Write-Host "[checkpoint] Commit erstellt: $commitMsg" -ForegroundColor Green
    $success = $true
}
catch {
    $errorMsg = $_.Exception.Message
}
finally {
    # Temp-Message-Datei aufraeumen
    if (Test-Path $tempMsgFile) {
        Remove-Item $tempMsgFile -Force -ErrorAction SilentlyContinue
    }
}

if (-not $success) {
    Write-Host ""
    Write-Host "[checkpoint] FEHLER: $errorMsg" -ForegroundColor Red
    Write-Host "[checkpoint] Rollback wird ausgefuehrt..." -ForegroundColor Yellow

    # changelog.md auf Original-Stand zurueckschreiben
    try {
        [System.IO.File]::WriteAllText($changelogFile, $originalChangelog, $utf8NoBom)
        Write-Host "[checkpoint] changelog.md auf Original-Stand zurueckgerollt." -ForegroundColor Yellow
    } catch {
        Write-Host "[checkpoint] WARNUNG: Rollback von changelog.md fehlgeschlagen ($($_.Exception.Message))." -ForegroundColor Red
    }

    # Index-Stagung fuer changelog.md auf HEAD zuruecksetzen
    & git restore --staged -- changelog.md 2>$null | Out-Null
    if ($LASTEXITCODE -ne 0) {
        # Fallback fuer aelteres Git ohne 'restore'
        & git reset HEAD -- changelog.md 2>$null | Out-Null
    }

    Write-Host "[checkpoint] FEHLGESCHLAGEN - .checkpoint-pending.txt bleibt erhalten fuer einen erneuten Lauf." -ForegroundColor Red
    exit 1
}

# --- Pending-Datei loeschen (nicht fatal wenn das fehlschlaegt) ---
try {
    Remove-Item $pendingFile -Force
    Write-Host "[checkpoint] .checkpoint-pending.txt entfernt." -ForegroundColor Green
} catch {
    Write-Host "[checkpoint] WARNUNG: .checkpoint-pending.txt konnte nicht geloescht werden ($($_.Exception.Message)). Bitte manuell entfernen." -ForegroundColor Yellow
}
