#!/bin/bash
# KAR-759 — Risk-stratifizierter Auto-Merge-Gate fuer Aria-Auto-PRs.
#
# Klassifiziert einen PR anhand (geaenderte Pfade + Delta-LOC + CI-Status) als
# AUTO-MERGE-faehig oder BLOCK (Stop-and-ask). Guardrail bleibt hart:
# Migrationen/authz/RLS/API/Secrets -> IMMER BLOCK.
#
# DRY-RUN ist Default: loggt nur die Entscheidung, merged NICHT. Echtes Merge
# nur mit --execute (gh-CLI ist aktuell kaputt -> dann via GitHub-MCP durch Aria).
#
# Scope-Entscheidung Kais 2026-06-21: aria-brain zuerst, Whitelist md/Wissen/
# reports/deps, LOC < 80, Start als Dry-Run.
#
# Usage:
#   aria-pr-risk-gate.sh --files <pathlist> --loc <n> --ci <pass|fail|unknown> [--execute]
#   aria-pr-risk-gate.sh --self-test
#   (pathlist: Datei mit je einem geaenderten Pfad pro Zeile, oder '-' fuer stdin)
#
# Exit: 0 = MERGE-Entscheidung, 10 = BLOCK, 2 = Fehler/Selbsttest-Fail.
# KAR: 759

set -uo pipefail

LOC_LIMIT="${PR_GATE_LOC_LIMIT:-80}"
LOG="/root/aria/logs/pr-risk-gate.log"

# Harte Block-Patterns (Guardrail — niemals auto-mergen)
SENSITIVE='(^|/)(migrations?|supabase/migrations)/|\.sql$|(^|/)api/|auth|authz|rls|policy|(^|/)\.env|secret|token|settings(\.local)?\.json$|\.tf$|tfvars|terraform'
# Whitelist (nur diese Pfade duerfen auto-mergen)
WHITELIST='(\.md$|^02-Wissen/|-reports/|^docs/|(^|/)package(-lock)?\.json$|\.lock$|requirements\.txt$|(^|/)CHANGELOG)'

log() { echo "$(date -u +%Y-%m-%dT%H:%M:%SZ) $*" >> "$LOG" 2>/dev/null || true; }

# classify <ci> <loc> <<<filelist (newline) ; echo "MERGE" | "BLOCK:<reason>"
classify() {
    local ci="$1" loc="$2" files="$3" f
    if [ "$ci" != "pass" ]; then echo "BLOCK:ci-not-green($ci)"; return; fi
    while IFS= read -r f; do
        [ -z "$f" ] && continue
        if echo "$f" | grep -qiE "$SENSITIVE"; then echo "BLOCK:sensitive-path($f)"; return; fi
    done <<< "$files"
    if [ "$loc" -ge "$LOC_LIMIT" ] 2>/dev/null; then echo "BLOCK:loc>=$LOC_LIMIT($loc)"; return; fi
    while IFS= read -r f; do
        [ -z "$f" ] && continue
        if ! echo "$f" | grep -qiE "$WHITELIST"; then echo "BLOCK:non-whitelist($f)"; return; fi
    done <<< "$files"
    echo "MERGE"
}

self_test() {
    local rc=0 d
    d=$(classify pass 20 $'02-Wissen/foo.md\nREADME.md')
    [ "$d" = "MERGE" ] && echo "PASS low-risk -> MERGE" || { echo "FAIL low-risk got: $d"; rc=2; }
    d=$(classify pass 10 $'supabase/migrations/001_init.sql')
    [[ "$d" == BLOCK:sensitive* ]] && echo "PASS migration -> $d" || { echo "FAIL migration got: $d"; rc=2; }
    d=$(classify pass 200 $'02-Wissen/big.md')
    [[ "$d" == BLOCK:loc* ]] && echo "PASS big-loc -> $d" || { echo "FAIL big-loc got: $d"; rc=2; }
    d=$(classify fail 5 $'docs/x.md')
    [[ "$d" == BLOCK:ci* ]] && echo "PASS ci-red -> $d" || { echo "FAIL ci-red got: $d"; rc=2; }
    d=$(classify pass 5 $'src/app.ts')
    [[ "$d" == BLOCK:non-whitelist* ]] && echo "PASS code-file -> $d" || { echo "FAIL code-file got: $d"; rc=2; }
    return $rc
}

main() {
    local files_src="" loc="" ci="unknown" execute=0
    while [ $# -gt 0 ]; do
        case "$1" in
            --self-test) self_test; exit $? ;;
            --files) files_src="$2"; shift 2 ;;
            --loc) loc="$2"; shift 2 ;;
            --ci) ci="$2"; shift 2 ;;
            --execute) execute=1; shift ;;
            *) echo "unknown arg: $1" >&2; exit 2 ;;
        esac
    done
    [ -z "$files_src" ] && { echo "need --files" >&2; exit 2; }
    local files
    if [ "$files_src" = "-" ]; then files=$(cat); else files=$(cat "$files_src"); fi
    [ -z "$loc" ] && loc=$(echo "$files" | grep -c . )

    local decision; decision=$(classify "$ci" "$loc" "$files")
    log "decision=$decision ci=$ci loc=$loc execute=$execute files=[$(echo "$files" | tr '\n' ',')]"

    if [[ "$decision" == "MERGE" ]]; then
        if [ "$execute" = "1" ]; then
            echo "MERGE-OK — echtes Merge: gh-CLI kaputt, via GitHub-MCP ausfuehren (nicht hier). Entscheidung geloggt."
            exit 0
        fi
        echo "DRY-RUN: WUERDE MERGEN (low-risk). ci=$ci loc=$loc"
        exit 0
    else
        echo "BLOCK ($decision) — Stop-and-ask. ci=$ci loc=$loc"
        exit 10
    fi
}

main "$@"
