# Woodpecker CI Main Pipeline
# BreakPilot PWA - CI/CD Pipeline
#
# Plattform: ARM64 (Apple Silicon Mac Mini)
#
# Strategie:
# - Tests laufen bei JEDEM Push/PR
# - Test-Ergebnisse werden an Dashboard gesendet
# - Builds/Scans laufen nur bei Tags oder manuell
# - Deployment nur manuell (Sicherheit)

when:
  - event: [push, pull_request, manual, tag]
    branch: [main, develop]

clone:
  git:
    image: woodpeckerci/plugin-git
    settings:
      depth: 1
    extra_hosts:
      - macmini:192.168.178.100

variables:
  - &golang_image golang:1.23-alpine
  - &python_image python:3.12-slim
  - &python_ci_image breakpilot/python-ci:3.12  # Custom image with WeasyPrint
  - &nodejs_image node:20-alpine
  - &docker_image docker:27-cli

steps:
  # ========================================
  # STAGE 1: Lint (nur bei PRs)
  # ========================================

  go-lint:
    image: golangci/golangci-lint:v1.55-alpine
    commands:
      - cd consent-service && golangci-lint run --timeout 5m ./...
      - cd ../billing-service && golangci-lint run --timeout 5m ./...
      - cd ../school-service && golangci-lint run --timeout 5m ./...
    when:
      event: pull_request

  python-lint:
    image: *python_image
    commands:
      - pip install --quiet ruff black
      - ruff check backend/ --output-format=github || true
      - black --check backend/ || true
    when:
      event: pull_request

  # ========================================
  # STAGE 2: Unit Tests mit JSON-Ausgabe
  # Ergebnisse werden im Workspace gespeichert (.ci-results/)
  # ========================================

  test-go-consent:
    image: *golang_image
    environment:
      CGO_ENABLED: "0"
    commands:
      - |
        set -euo pipefail
        apk add --no-cache jq bash
        mkdir -p .ci-results

        if [ ! -d "consent-service" ]; then
          echo '{"service":"consent-service","framework":"go","total":0,"passed":0,"failed":0,"skipped":0,"coverage":0}' > .ci-results/results-consent.json
          echo "WARNUNG: consent-service Verzeichnis nicht gefunden"
          exit 0
        fi

        cd consent-service
        set +e
        go test -v -json -coverprofile=coverage.out ./... 2>&1 | tee ../.ci-results/test-consent.json
        TEST_EXIT=$?
        set -e

        # JSON-Zeilen extrahieren und mit jq zählen
        JSON_FILE="../.ci-results/test-consent.json"
        if grep -q '^{' "$JSON_FILE" 2>/dev/null; then
          TOTAL=$(grep '^{' "$JSON_FILE" | jq -s '[.[] | select(.Action=="run" and .Test != null)] | length')
          PASSED=$(grep '^{' "$JSON_FILE" | jq -s '[.[] | select(.Action=="pass" and .Test != null)] | length')
          FAILED=$(grep '^{' "$JSON_FILE" | jq -s '[.[] | select(.Action=="fail" and .Test != null)] | length')
          SKIPPED=$(grep '^{' "$JSON_FILE" | jq -s '[.[] | select(.Action=="skip" and .Test != null)] | length')
        else
          echo "WARNUNG: Keine JSON-Zeilen in $JSON_FILE gefunden (Build-Fehler?)"
          TOTAL=0; PASSED=0; FAILED=0; SKIPPED=0
        fi

        COVERAGE=$(go tool cover -func=coverage.out 2>/dev/null | tail -1 | awk '{print $3}' | tr -d '%' || echo "0")
        [ -z "$COVERAGE" ] && COVERAGE=0

        echo "{\"service\":\"consent-service\",\"framework\":\"go\",\"total\":$TOTAL,\"passed\":$PASSED,\"failed\":$FAILED,\"skipped\":$SKIPPED,\"coverage\":$COVERAGE}" > ../.ci-results/results-consent.json
        cat ../.ci-results/results-consent.json

        # Backlog-Strategie: Fehler werden gemeldet aber Pipeline laeuft weiter
        if [ "$FAILED" -gt "0" ]; then
          echo "WARNUNG: $FAILED Tests fehlgeschlagen - werden ins Backlog geschrieben"
        fi

  test-go-billing:
    image: *golang_image
    environment:
      CGO_ENABLED: "0"
    commands:
      - |
        set -euo pipefail
        apk add --no-cache jq bash
        mkdir -p .ci-results

        if [ ! -d "billing-service" ]; then
          echo '{"service":"billing-service","framework":"go","total":0,"passed":0,"failed":0,"skipped":0,"coverage":0}' > .ci-results/results-billing.json
          echo "WARNUNG: billing-service Verzeichnis nicht gefunden"
          exit 0
        fi

        cd billing-service
        set +e
        go test -v -json -coverprofile=coverage.out ./... 2>&1 | tee ../.ci-results/test-billing.json
        TEST_EXIT=$?
        set -e

        # JSON-Zeilen extrahieren und mit jq zählen
        JSON_FILE="../.ci-results/test-billing.json"
        if grep -q '^{' "$JSON_FILE" 2>/dev/null; then
          TOTAL=$(grep '^{' "$JSON_FILE" | jq -s '[.[] | select(.Action=="run" and .Test != null)] | length')
          PASSED=$(grep '^{' "$JSON_FILE" | jq -s '[.[] | select(.Action=="pass" and .Test != null)] | length')
          FAILED=$(grep '^{' "$JSON_FILE" | jq -s '[.[] | select(.Action=="fail" and .Test != null)] | length')
          SKIPPED=$(grep '^{' "$JSON_FILE" | jq -s '[.[] | select(.Action=="skip" and .Test != null)] | length')
        else
          echo "WARNUNG: Keine JSON-Zeilen in $JSON_FILE gefunden (Build-Fehler?)"
          TOTAL=0; PASSED=0; FAILED=0; SKIPPED=0
        fi

        COVERAGE=$(go tool cover -func=coverage.out 2>/dev/null | tail -1 | awk '{print $3}' | tr -d '%' || echo "0")
        [ -z "$COVERAGE" ] && COVERAGE=0

        echo "{\"service\":\"billing-service\",\"framework\":\"go\",\"total\":$TOTAL,\"passed\":$PASSED,\"failed\":$FAILED,\"skipped\":$SKIPPED,\"coverage\":$COVERAGE}" > ../.ci-results/results-billing.json
        cat ../.ci-results/results-billing.json

        # Backlog-Strategie: Fehler werden gemeldet aber Pipeline laeuft weiter
        if [ "$FAILED" -gt "0" ]; then
          echo "WARNUNG: $FAILED Tests fehlgeschlagen - werden ins Backlog geschrieben"
        fi

  test-go-school:
    image: *golang_image
    environment:
      CGO_ENABLED: "0"
    commands:
      - |
        set -euo pipefail
        apk add --no-cache jq bash
        mkdir -p .ci-results

        if [ ! -d "school-service" ]; then
          echo '{"service":"school-service","framework":"go","total":0,"passed":0,"failed":0,"skipped":0,"coverage":0}' > .ci-results/results-school.json
          echo "WARNUNG: school-service Verzeichnis nicht gefunden"
          exit 0
        fi

        cd school-service
        set +e
        go test -v -json -coverprofile=coverage.out ./... 2>&1 | tee ../.ci-results/test-school.json
        TEST_EXIT=$?
        set -e

        # JSON-Zeilen extrahieren und mit jq zählen
        JSON_FILE="../.ci-results/test-school.json"
        if grep -q '^{' "$JSON_FILE" 2>/dev/null; then
          TOTAL=$(grep '^{' "$JSON_FILE" | jq -s '[.[] | select(.Action=="run" and .Test != null)] | length')
          PASSED=$(grep '^{' "$JSON_FILE" | jq -s '[.[] | select(.Action=="pass" and .Test != null)] | length')
          FAILED=$(grep '^{' "$JSON_FILE" | jq -s '[.[] | select(.Action=="fail" and .Test != null)] | length')
          SKIPPED=$(grep '^{' "$JSON_FILE" | jq -s '[.[] | select(.Action=="skip" and .Test != null)] | length')
        else
          echo "WARNUNG: Keine JSON-Zeilen in $JSON_FILE gefunden (Build-Fehler?)"
          TOTAL=0; PASSED=0; FAILED=0; SKIPPED=0
        fi

        COVERAGE=$(go tool cover -func=coverage.out 2>/dev/null | tail -1 | awk '{print $3}' | tr -d '%' || echo "0")
        [ -z "$COVERAGE" ] && COVERAGE=0

        echo "{\"service\":\"school-service\",\"framework\":\"go\",\"total\":$TOTAL,\"passed\":$PASSED,\"failed\":$FAILED,\"skipped\":$SKIPPED,\"coverage\":$COVERAGE}" > ../.ci-results/results-school.json
        cat ../.ci-results/results-school.json

        # Backlog-Strategie: Fehler werden gemeldet aber Pipeline laeuft weiter
        if [ "$FAILED" -gt "0" ]; then
          echo "WARNUNG: $FAILED Tests fehlgeschlagen - werden ins Backlog geschrieben"
        fi

  test-go-edu-search:
    image: *golang_image
    environment:
      CGO_ENABLED: "0"
    commands:
      - |
        set -euo pipefail
        apk add --no-cache jq bash
        mkdir -p .ci-results

        if [ ! -d "edu-search-service" ]; then
          echo '{"service":"edu-search-service","framework":"go","total":0,"passed":0,"failed":0,"skipped":0,"coverage":0}' > .ci-results/results-edu-search.json
          echo "WARNUNG: edu-search-service Verzeichnis nicht gefunden"
          exit 0
        fi

        cd edu-search-service
        set +e
        go test -v -json -coverprofile=coverage.out ./internal/... 2>&1 | tee ../.ci-results/test-edu-search.json
        TEST_EXIT=$?
        set -e

        # JSON-Zeilen extrahieren und mit jq zählen
        JSON_FILE="../.ci-results/test-edu-search.json"
        if grep -q '^{' "$JSON_FILE" 2>/dev/null; then
          TOTAL=$(grep '^{' "$JSON_FILE" | jq -s '[.[] | select(.Action=="run" and .Test != null)] | length')
          PASSED=$(grep '^{' "$JSON_FILE" | jq -s '[.[] | select(.Action=="pass" and .Test != null)] | length')
          FAILED=$(grep '^{' "$JSON_FILE" | jq -s '[.[] | select(.Action=="fail" and .Test != null)] | length')
          SKIPPED=$(grep '^{' "$JSON_FILE" | jq -s '[.[] | select(.Action=="skip" and .Test != null)] | length')
        else
          echo "WARNUNG: Keine JSON-Zeilen in $JSON_FILE gefunden (Build-Fehler?)"
          TOTAL=0; PASSED=0; FAILED=0; SKIPPED=0
        fi

        COVERAGE=$(go tool cover -func=coverage.out 2>/dev/null | tail -1 | awk '{print $3}' | tr -d '%' || echo "0")
        [ -z "$COVERAGE" ] && COVERAGE=0

        echo "{\"service\":\"edu-search-service\",\"framework\":\"go\",\"total\":$TOTAL,\"passed\":$PASSED,\"failed\":$FAILED,\"skipped\":$SKIPPED,\"coverage\":$COVERAGE}" > ../.ci-results/results-edu-search.json
        cat ../.ci-results/results-edu-search.json

        # Backlog-Strategie: Fehler werden gemeldet aber Pipeline laeuft weiter
        if [ "$FAILED" -gt "0" ]; then
          echo "WARNUNG: $FAILED Tests fehlgeschlagen - werden ins Backlog geschrieben"
        fi

  test-go-ai-compliance:
    image: *golang_image
    environment:
      CGO_ENABLED: "0"
    commands:
      - |
        set -euo pipefail
        apk add --no-cache jq bash
        mkdir -p .ci-results

        if [ ! -d "ai-compliance-sdk" ]; then
          echo '{"service":"ai-compliance-sdk","framework":"go","total":0,"passed":0,"failed":0,"skipped":0,"coverage":0}' > .ci-results/results-ai-compliance.json
          echo "WARNUNG: ai-compliance-sdk Verzeichnis nicht gefunden"
          exit 0
        fi

        cd ai-compliance-sdk
        set +e
        go test -v -json -coverprofile=coverage.out ./... 2>&1 | tee ../.ci-results/test-ai-compliance.json
        TEST_EXIT=$?
        set -e

        # JSON-Zeilen extrahieren und mit jq zählen
        JSON_FILE="../.ci-results/test-ai-compliance.json"
        if grep -q '^{' "$JSON_FILE" 2>/dev/null; then
          TOTAL=$(grep '^{' "$JSON_FILE" | jq -s '[.[] | select(.Action=="run" and .Test != null)] | length')
          PASSED=$(grep '^{' "$JSON_FILE" | jq -s '[.[] | select(.Action=="pass" and .Test != null)] | length')
          FAILED=$(grep '^{' "$JSON_FILE" | jq -s '[.[] | select(.Action=="fail" and .Test != null)] | length')
          SKIPPED=$(grep '^{' "$JSON_FILE" | jq -s '[.[] | select(.Action=="skip" and .Test != null)] | length')
        else
          echo "WARNUNG: Keine JSON-Zeilen in $JSON_FILE gefunden (Build-Fehler?)"
          TOTAL=0; PASSED=0; FAILED=0; SKIPPED=0
        fi

        COVERAGE=$(go tool cover -func=coverage.out 2>/dev/null | tail -1 | awk '{print $3}' | tr -d '%' || echo "0")
        [ -z "$COVERAGE" ] && COVERAGE=0

        echo "{\"service\":\"ai-compliance-sdk\",\"framework\":\"go\",\"total\":$TOTAL,\"passed\":$PASSED,\"failed\":$FAILED,\"skipped\":$SKIPPED,\"coverage\":$COVERAGE}" > ../.ci-results/results-ai-compliance.json
        cat ../.ci-results/results-ai-compliance.json

        # Backlog-Strategie: Fehler werden gemeldet aber Pipeline laeuft weiter
        if [ "$FAILED" -gt "0" ]; then
          echo "WARNUNG: $FAILED Tests fehlgeschlagen - werden ins Backlog geschrieben"
        fi

  test-python-backend:
    image: *python_ci_image
    environment:
      CI: "true"
      DATABASE_URL: "postgresql://test:test@localhost:5432/test_db"
      SKIP_DB_TESTS: "true"
      SKIP_WEASYPRINT_TESTS: "false"
      SKIP_INTEGRATION_TESTS: "true"
    commands:
      - |
        set -uo pipefail
        mkdir -p .ci-results

        if [ ! -d "backend" ]; then
          echo '{"service":"backend","framework":"pytest","total":0,"passed":0,"failed":0,"skipped":0,"coverage":0}' > .ci-results/results-backend.json
          echo "WARNUNG: backend Verzeichnis nicht gefunden"
          exit 0
        fi

        cd backend
        # Set PYTHONPATH to current directory (backend) so local packages like classroom_engine, alerts_agent are found
        # IMPORTANT: Use absolute path and export before pip install to ensure modules are available
        export PYTHONPATH="$(pwd):${PYTHONPATH:-}"

        # Test tools are pre-installed in breakpilot/python-ci image
        # Only install project-specific dependencies
        pip install --quiet --no-cache-dir -r requirements.txt

        # NOTE: PostgreSQL service removed - tests that require DB are skipped via SKIP_DB_TESTS=true
        # For full integration tests, use: docker compose -f docker-compose.test.yml up -d

        set +e
        # Use python -m pytest to ensure PYTHONPATH is properly applied before pytest starts
        python -m pytest tests/ -v --tb=short --cov=. --cov-report=term-missing --json-report --json-report-file=../.ci-results/test-backend.json
        TEST_EXIT=$?
        set -e

        if [ -f ../.ci-results/test-backend.json ]; then
          TOTAL=$(python3 -c "import json; d=json.load(open('../.ci-results/test-backend.json')); print(d.get('summary',{}).get('total',0))" 2>/dev/null || echo "0")
          PASSED=$(python3 -c "import json; d=json.load(open('../.ci-results/test-backend.json')); print(d.get('summary',{}).get('passed',0))" 2>/dev/null || echo "0")
          FAILED=$(python3 -c "import json; d=json.load(open('../.ci-results/test-backend.json')); print(d.get('summary',{}).get('failed',0))" 2>/dev/null || echo "0")
          SKIPPED=$(python3 -c "import json; d=json.load(open('../.ci-results/test-backend.json')); print(d.get('summary',{}).get('skipped',0))" 2>/dev/null || echo "0")
        else
          TOTAL=0; PASSED=0; FAILED=0; SKIPPED=0
        fi

        echo "{\"service\":\"backend\",\"framework\":\"pytest\",\"total\":$TOTAL,\"passed\":$PASSED,\"failed\":$FAILED,\"skipped\":$SKIPPED,\"coverage\":0}" > ../.ci-results/results-backend.json
        cat ../.ci-results/results-backend.json

        if [ "$TEST_EXIT" -ne "0" ]; then exit 1; fi

  test-python-voice:
    image: *python_image
    environment:
      CI: "true"
    commands:
      - |
        set -uo pipefail
        mkdir -p .ci-results

        if [ ! -d "voice-service" ]; then
          echo '{"service":"voice-service","framework":"pytest","total":0,"passed":0,"failed":0,"skipped":0,"coverage":0}' > .ci-results/results-voice.json
          echo "WARNUNG: voice-service Verzeichnis nicht gefunden"
          exit 0
        fi

        cd voice-service
        export PYTHONPATH="$(pwd):${PYTHONPATH:-}"
        pip install --quiet --no-cache-dir -r requirements.txt
        pip install --quiet --no-cache-dir pytest-json-report

        set +e
        python -m pytest tests/ -v --tb=short --json-report --json-report-file=../.ci-results/test-voice.json
        TEST_EXIT=$?
        set -e

        if [ -f ../.ci-results/test-voice.json ]; then
          TOTAL=$(python3 -c "import json; d=json.load(open('../.ci-results/test-voice.json')); print(d.get('summary',{}).get('total',0))" 2>/dev/null || echo "0")
          PASSED=$(python3 -c "import json; d=json.load(open('../.ci-results/test-voice.json')); print(d.get('summary',{}).get('passed',0))" 2>/dev/null || echo "0")
          FAILED=$(python3 -c "import json; d=json.load(open('../.ci-results/test-voice.json')); print(d.get('summary',{}).get('failed',0))" 2>/dev/null || echo "0")
          SKIPPED=$(python3 -c "import json; d=json.load(open('../.ci-results/test-voice.json')); print(d.get('summary',{}).get('skipped',0))" 2>/dev/null || echo "0")
        else
          TOTAL=0; PASSED=0; FAILED=0; SKIPPED=0
        fi

        echo "{\"service\":\"voice-service\",\"framework\":\"pytest\",\"total\":$TOTAL,\"passed\":$PASSED,\"failed\":$FAILED,\"skipped\":$SKIPPED,\"coverage\":0}" > ../.ci-results/results-voice.json
        cat ../.ci-results/results-voice.json

        if [ "$TEST_EXIT" -ne "0" ]; then exit 1; fi

  test-bqas-golden:
    image: *python_image
    commands:
      - |
        set -uo pipefail
        mkdir -p .ci-results

        if [ ! -d "voice-service/tests/bqas" ]; then
          echo '{"service":"bqas-golden","framework":"pytest","total":0,"passed":0,"failed":0,"skipped":0,"coverage":0}' > .ci-results/results-bqas-golden.json
          echo "WARNUNG: voice-service/tests/bqas Verzeichnis nicht gefunden"
          exit 0
        fi

        cd voice-service
        export PYTHONPATH="$(pwd):${PYTHONPATH:-}"
        pip install --quiet --no-cache-dir -r requirements.txt
        pip install --quiet --no-cache-dir pytest-json-report pytest-asyncio

        set +e
        python -m pytest tests/bqas/test_golden.py tests/bqas/test_regression.py tests/bqas/test_synthetic.py -v --tb=short --json-report --json-report-file=../.ci-results/test-bqas-golden.json
        TEST_EXIT=$?
        set -e

        if [ -f ../.ci-results/test-bqas-golden.json ]; then
          TOTAL=$(python3 -c "import json; d=json.load(open('../.ci-results/test-bqas-golden.json')); print(d.get('summary',{}).get('total',0))" 2>/dev/null || echo "0")
          PASSED=$(python3 -c "import json; d=json.load(open('../.ci-results/test-bqas-golden.json')); print(d.get('summary',{}).get('passed',0))" 2>/dev/null || echo "0")
          FAILED=$(python3 -c "import json; d=json.load(open('../.ci-results/test-bqas-golden.json')); print(d.get('summary',{}).get('failed',0))" 2>/dev/null || echo "0")
          SKIPPED=$(python3 -c "import json; d=json.load(open('../.ci-results/test-bqas-golden.json')); print(d.get('summary',{}).get('skipped',0))" 2>/dev/null || echo "0")
        else
          TOTAL=0; PASSED=0; FAILED=0; SKIPPED=0
        fi

        echo "{\"service\":\"bqas-golden\",\"framework\":\"pytest\",\"total\":$TOTAL,\"passed\":$PASSED,\"failed\":$FAILED,\"skipped\":$SKIPPED,\"coverage\":0}" > ../.ci-results/results-bqas-golden.json
        cat ../.ci-results/results-bqas-golden.json

        # BQAS tests may skip if Ollama not available - don't fail pipeline
        if [ "$FAILED" -gt "0" ]; then exit 1; fi

  test-bqas-rag:
    image: *python_image
    commands:
      - |
        set -uo pipefail
        mkdir -p .ci-results

        if [ ! -d "voice-service/tests/bqas" ]; then
          echo '{"service":"bqas-rag","framework":"pytest","total":0,"passed":0,"failed":0,"skipped":0,"coverage":0}' > .ci-results/results-bqas-rag.json
          echo "WARNUNG: voice-service/tests/bqas Verzeichnis nicht gefunden"
          exit 0
        fi

        cd voice-service
        export PYTHONPATH="$(pwd):${PYTHONPATH:-}"
        pip install --quiet --no-cache-dir -r requirements.txt
        pip install --quiet --no-cache-dir pytest-json-report pytest-asyncio

        set +e
        python -m pytest tests/bqas/test_rag.py tests/bqas/test_notifier.py -v --tb=short --json-report --json-report-file=../.ci-results/test-bqas-rag.json
        TEST_EXIT=$?
        set -e

        if [ -f ../.ci-results/test-bqas-rag.json ]; then
          TOTAL=$(python3 -c "import json; d=json.load(open('../.ci-results/test-bqas-rag.json')); print(d.get('summary',{}).get('total',0))" 2>/dev/null || echo "0")
          PASSED=$(python3 -c "import json; d=json.load(open('../.ci-results/test-bqas-rag.json')); print(d.get('summary',{}).get('passed',0))" 2>/dev/null || echo "0")
          FAILED=$(python3 -c "import json; d=json.load(open('../.ci-results/test-bqas-rag.json')); print(d.get('summary',{}).get('failed',0))" 2>/dev/null || echo "0")
          SKIPPED=$(python3 -c "import json; d=json.load(open('../.ci-results/test-bqas-rag.json')); print(d.get('summary',{}).get('skipped',0))" 2>/dev/null || echo "0")
        else
          TOTAL=0; PASSED=0; FAILED=0; SKIPPED=0
        fi

        echo "{\"service\":\"bqas-rag\",\"framework\":\"pytest\",\"total\":$TOTAL,\"passed\":$PASSED,\"failed\":$FAILED,\"skipped\":$SKIPPED,\"coverage\":0}" > ../.ci-results/results-bqas-rag.json
        cat ../.ci-results/results-bqas-rag.json

        # BQAS tests may skip if Ollama not available - don't fail pipeline
        if [ "$FAILED" -gt "0" ]; then exit 1; fi

  test-python-klausur:
    image: *python_image
    environment:
      CI: "true"
    commands:
      - |
        set -uo pipefail
        mkdir -p .ci-results

        if [ ! -d "klausur-service/backend" ]; then
          echo '{"service":"klausur-service","framework":"pytest","total":0,"passed":0,"failed":0,"skipped":0,"coverage":0}' > .ci-results/results-klausur.json
          echo "WARNUNG: klausur-service/backend Verzeichnis nicht gefunden"
          exit 0
        fi

        cd klausur-service/backend
        # Set PYTHONPATH to current directory so local modules like hyde, hybrid_search, etc. are found
        export PYTHONPATH="$(pwd):${PYTHONPATH:-}"

        pip install --quiet --no-cache-dir -r requirements.txt 2>/dev/null || pip install --quiet --no-cache-dir fastapi uvicorn pytest pytest-asyncio pytest-json-report
        pip install --quiet --no-cache-dir pytest-json-report

        set +e
        python -m pytest tests/ -v --tb=short --json-report --json-report-file=../../.ci-results/test-klausur.json
        TEST_EXIT=$?
        set -e

        if [ -f ../../.ci-results/test-klausur.json ]; then
          TOTAL=$(python3 -c "import json; d=json.load(open('../../.ci-results/test-klausur.json')); print(d.get('summary',{}).get('total',0))" 2>/dev/null || echo "0")
          PASSED=$(python3 -c "import json; d=json.load(open('../../.ci-results/test-klausur.json')); print(d.get('summary',{}).get('passed',0))" 2>/dev/null || echo "0")
          FAILED=$(python3 -c "import json; d=json.load(open('../../.ci-results/test-klausur.json')); print(d.get('summary',{}).get('failed',0))" 2>/dev/null || echo "0")
          SKIPPED=$(python3 -c "import json; d=json.load(open('../../.ci-results/test-klausur.json')); print(d.get('summary',{}).get('skipped',0))" 2>/dev/null || echo "0")
        else
          TOTAL=0; PASSED=0; FAILED=0; SKIPPED=0
        fi

        echo "{\"service\":\"klausur-service\",\"framework\":\"pytest\",\"total\":$TOTAL,\"passed\":$PASSED,\"failed\":$FAILED,\"skipped\":$SKIPPED,\"coverage\":0}" > ../../.ci-results/results-klausur.json
        cat ../../.ci-results/results-klausur.json

        if [ "$TEST_EXIT" -ne "0" ]; then exit 1; fi

  test-nodejs-h5p:
    image: *nodejs_image
    commands:
      - |
        set -uo pipefail
        mkdir -p .ci-results

        if [ ! -d "h5p-service" ]; then
          echo '{"service":"h5p-service","framework":"jest","total":0,"passed":0,"failed":0,"skipped":0,"coverage":0}' > .ci-results/results-h5p.json
          echo "WARNUNG: h5p-service Verzeichnis nicht gefunden"
          exit 0
        fi

        cd h5p-service
        npm ci --silent 2>/dev/null || npm install --silent

        set +e
        npm run test:ci -- --json --outputFile=../.ci-results/test-h5p.json 2>&1
        TEST_EXIT=$?
        set -e

        if [ -f ../.ci-results/test-h5p.json ]; then
          TOTAL=$(node -e "const d=require('../.ci-results/test-h5p.json'); console.log(d.numTotalTests || 0)" 2>/dev/null || echo "0")
          PASSED=$(node -e "const d=require('../.ci-results/test-h5p.json'); console.log(d.numPassedTests || 0)" 2>/dev/null || echo "0")
          FAILED=$(node -e "const d=require('../.ci-results/test-h5p.json'); console.log(d.numFailedTests || 0)" 2>/dev/null || echo "0")
          SKIPPED=$(node -e "const d=require('../.ci-results/test-h5p.json'); console.log(d.numPendingTests || 0)" 2>/dev/null || echo "0")
        else
          TOTAL=0; PASSED=0; FAILED=0; SKIPPED=0
        fi

        [ -z "$TOTAL" ] && TOTAL=0
        [ -z "$PASSED" ] && PASSED=0
        [ -z "$FAILED" ] && FAILED=0
        [ -z "$SKIPPED" ] && SKIPPED=0

        echo "{\"service\":\"h5p-service\",\"framework\":\"jest\",\"total\":$TOTAL,\"passed\":$PASSED,\"failed\":$FAILED,\"skipped\":$SKIPPED,\"coverage\":0}" > ../.ci-results/results-h5p.json
        cat ../.ci-results/results-h5p.json

        if [ "$TEST_EXIT" -ne "0" ]; then exit 1; fi

  # ========================================
  # STAGE 2.5: Integration Tests
  # ========================================
  # Integration Tests laufen in separater Pipeline:
  # .woodpecker/integration.yml
  # (benötigt Pipeline-Level Services für PostgreSQL und Valkey)

  # ========================================
  # STAGE 3: Test-Ergebnisse an Dashboard senden
  # ========================================

  report-test-results:
    image: curlimages/curl:8.10.1
    commands:
      - |
        set -uo pipefail
        echo "=== Sende Test-Ergebnisse an Dashboard ==="
        echo "Pipeline Status: ${CI_PIPELINE_STATUS:-unknown}"
        ls -la .ci-results/ || echo "Verzeichnis nicht gefunden"

        PIPELINE_STATUS="${CI_PIPELINE_STATUS:-unknown}"

        for f in .ci-results/results-*.json; do
          [ -f "$f" ] || continue
          echo "Sending: $f"
          curl -f -sS -X POST "http://backend:8000/api/tests/ci-result" \
            -H "Content-Type: application/json" \
            -d "{
              \"pipeline_id\": \"${CI_PIPELINE_NUMBER}\",
              \"commit\": \"${CI_COMMIT_SHA}\",
              \"branch\": \"${CI_COMMIT_BRANCH}\",
              \"status\": \"${PIPELINE_STATUS}\",
              \"test_results\": $(cat "$f")
            }" || echo "WARNUNG: Konnte $f nicht senden"
        done

        echo "=== Test-Ergebnisse gesendet ==="
    when:
      status: [success, failure]
    depends_on:
      - test-go-consent
      - test-go-billing
      - test-go-school
      - test-go-edu-search
      - test-go-ai-compliance
      - test-python-backend
      - test-python-voice
      - test-bqas-golden
      - test-bqas-rag
      - test-python-klausur
      - test-nodejs-h5p

  # ========================================
  # STAGE 4: Build & Security (nur Tags/manuell)
  # ========================================

  build-consent-service:
    image: *docker_image
    commands:
      - docker build -t breakpilot/consent-service:${CI_COMMIT_SHA:0:8} ./consent-service
      - docker tag breakpilot/consent-service:${CI_COMMIT_SHA:0:8} breakpilot/consent-service:latest
      - echo "Built breakpilot/consent-service:${CI_COMMIT_SHA:0:8}"
    when:
      - event: tag
      - event: manual

  build-backend:
    image: *docker_image
    commands:
      - docker build -t breakpilot/backend:${CI_COMMIT_SHA:0:8} ./backend
      - docker tag breakpilot/backend:${CI_COMMIT_SHA:0:8} breakpilot/backend:latest
      - echo "Built breakpilot/backend:${CI_COMMIT_SHA:0:8}"
    when:
      - event: tag
      - event: manual

  build-voice-service:
    image: *docker_image
    commands:
      - |
        if [ -d ./voice-service ]; then
          docker build -t breakpilot/voice-service:${CI_COMMIT_SHA:0:8} ./voice-service
          docker tag breakpilot/voice-service:${CI_COMMIT_SHA:0:8} breakpilot/voice-service:latest
          echo "Built breakpilot/voice-service:${CI_COMMIT_SHA:0:8}"
        else
          echo "voice-service Verzeichnis nicht gefunden - ueberspringe"
        fi
    when:
      - event: tag
      - event: manual

  generate-sbom:
    image: *golang_image
    commands:
      - |
        echo "Installing syft for ARM64..."
        wget -qO- https://raw.githubusercontent.com/anchore/syft/main/install.sh | sh -s -- -b /usr/local/bin
        syft dir:./consent-service -o cyclonedx-json > sbom-consent.json
        syft dir:./backend -o cyclonedx-json > sbom-backend.json
        if [ -d ./voice-service ]; then
          syft dir:./voice-service -o cyclonedx-json > sbom-voice.json
        fi
        echo "SBOMs generated successfully"
    when:
      - event: tag
      - event: manual

  vulnerability-scan:
    image: *golang_image
    commands:
      - |
        echo "Installing grype for ARM64..."
        wget -qO- https://raw.githubusercontent.com/anchore/grype/main/install.sh | sh -s -- -b /usr/local/bin
        grype sbom:sbom-consent.json -o table --fail-on critical || true
        grype sbom:sbom-backend.json -o table --fail-on critical || true
        if [ -f sbom-voice.json ]; then
          grype sbom:sbom-voice.json -o table --fail-on critical || true
        fi
    when:
      - event: tag
      - event: manual
    depends_on:
      - generate-sbom

  # ========================================
  # STAGE 5: Deploy (nur manuell)
  # ========================================

  deploy-production:
    image: *docker_image
    commands:
      - echo "Deploying to production..."
      - docker compose -f docker-compose.yml pull || true
      - docker compose -f docker-compose.yml up -d --remove-orphans || true
    when:
      event: manual
    depends_on:
      - build-consent-service
      - build-backend
