name: CI - Build & Test
run-name: 🔍 CI ${{ gitea.ref_name }} by @${{ gitea.actor }}

# ── Concurrency: cancel in-progress CI when new push arrives ──
concurrency:
  group: ci-${{ gitea.ref }}
  cancel-in-progress: true

on:
  push:
    branches:
      - main
      - 'codex/**'
  pull_request:
    branches: [main]
  workflow_dispatch:

jobs:
  # ─── Backend ───────────────────────────────────
  backend:
    name: Backend (.NET)
    runs-on: linux
    steps:
      - name: Checkout
        uses: actions/checkout@v4

      - name: Setup .NET SDK
        uses: actions/setup-dotnet@v4
        with:
          dotnet-version: '10.0.x'

      - name: Restore
        run: dotnet restore backend-tests/Nexus.Api.Tests.csproj

      - name: Build without contract-time key persistence
        run: |
          key_dir="$HOME/.aspnet/DataProtection-Keys"
          count_keys() {
            if [ -d "$key_dir" ]; then
              find "$key_dir" -type f -name 'key-*.xml' | wc -l
            else
              printf '0\n'
            fi
          }
          before="$(count_keys)"
          dotnet build backend-tests/Nexus.Api.Tests.csproj --no-restore --configuration Release
          after="$(count_keys)"
          test "$before" -eq "$after"

      - name: Verify EF migration model
        run: |
          dotnet tool restore
          dotnet tool run dotnet-ef migrations has-pending-model-changes \
            --project backend/Nexus.Api.csproj \
            --startup-project backend/Nexus.Api.csproj \
            --configuration Release \
            --no-build

      - name: Block high or critical backend vulnerabilities
        run: |
          dotnet list backend/Nexus.Api.csproj package --vulnerable --include-transitive --format json > /tmp/nexus-dotnet-vulnerabilities.json
          if grep -Eiq '"severity"[[:space:]]*:[[:space:]]*"(high|critical)"' /tmp/nexus-dotnet-vulnerabilities.json; then
            cat /tmp/nexus-dotnet-vulnerabilities.json
            exit 1
          fi

      - name: Verify OpenAPI contract
        run: |
          test -f backend/openapi/Nexus.Api.json
          test -z "$(git status --porcelain --untracked-files=all -- backend/openapi/Nexus.Api.json)"

      - name: Test
        run: dotnet test backend-tests/Nexus.Api.Tests.csproj --no-build --configuration Release --verbosity normal

  backend-integration:
    name: Backend integration (PostgreSQL/Toxiproxy)
    runs-on: linux
    timeout-minutes: 20
    env:
      NEXUS_RUN_DOCKER_INTEGRATION_TESTS: "true"
      NEXUS_RUN_TOXIPROXY_INTEGRATION_TESTS: "true"
    steps:
      - name: Checkout
        uses: actions/checkout@v4

      - name: Setup .NET SDK
        uses: actions/setup-dotnet@v4
        with:
          dotnet-version: '10.0.x'

      - name: Verify Docker endpoint
        run: docker info

      - name: Restore and build without contract-time key persistence
        run: |
          dotnet restore backend-tests/Nexus.Api.Tests.csproj
          key_dir="$HOME/.aspnet/DataProtection-Keys"
          count_keys() {
            if [ -d "$key_dir" ]; then
              find "$key_dir" -type f -name 'key-*.xml' | wc -l
            else
              printf '0\n'
            fi
          }
          before="$(count_keys)"
          dotnet build backend-tests/Nexus.Api.Tests.csproj --no-restore --configuration Release
          after="$(count_keys)"
          test "$before" -eq "$after"

      - name: Run all container-backed contracts
        run: >-
          dotnet test backend-tests/Nexus.Api.Tests.csproj
          --no-build
          --configuration Release
          --filter "Category=DockerIntegration|Category=ToxiproxyIntegration"
          --verbosity normal

  # ─── Frontend ──────────────────────────────────
  frontend:
    name: Frontend (Vue/TS)
    runs-on: linux
    steps:
      - name: Checkout
        uses: actions/checkout@v4

      - name: Setup Node.js
        uses: actions/setup-node@v4
        with:
          node-version: '24'

      - name: Setup pnpm
        run: |
          corepack enable
          corepack prepare pnpm@10.12.1 --activate

      - name: Install dependencies
        run: pnpm install --frozen-lockfile
        working-directory: frontend

      - name: Verify release version
        run: test "$(node -p "require('./package.json').version")" = "$(tr -d '[:space:]' < ../VERSION)"
        working-directory: frontend

      - name: Block high or critical production vulnerabilities
        run: pnpm audit --prod --audit-level high
        working-directory: frontend

      - name: Type check
        run: pnpm typecheck
        working-directory: frontend

      - name: Verify generated API types
        run: |
          pnpm openapi:generate
          test -z "$(git status --porcelain --untracked-files=all -- src/api/generated/schema.d.ts)"
        working-directory: frontend

      - name: Test
        run: pnpm test
        working-directory: frontend

      - name: Build
        run: pnpm build
        working-directory: frontend

      - name: Install Playwright Chromium
        run: pnpm exec playwright install --with-deps chromium
        working-directory: frontend

      - name: Browser end-to-end tests
        run: pnpm test:e2e
        working-directory: frontend

  # ─── Security ──────────────────────────────────
  security:
    name: Security Check
    runs-on: linux
    if: gitea.ref == 'refs/heads/main' || startsWith(gitea.ref, 'refs/heads/codex/')
    steps:
      - name: Checkout
        uses: actions/checkout@v4
        with:
          fetch-depth: 0

      - name: Gitleaks v8.30.1
        env:
          GITLEAKS_SHA256: 551f6fc83ea457d62a0d98237cbad105af8d557003051f41f3e7ca7b3f2470eb
        run: |
          curl -fsSL https://github.com/gitleaks/gitleaks/releases/download/v8.30.1/gitleaks_8.30.1_linux_x64.tar.gz -o /tmp/gitleaks.tar.gz
          echo "$GITLEAKS_SHA256  /tmp/gitleaks.tar.gz" | sha256sum -c -
          tar -xzf /tmp/gitleaks.tar.gz -C /tmp gitleaks
          /tmp/gitleaks git --redact --no-banner --exit-code 1 .

  deploy:
    name: Deploy Nexus
    runs-on: linux
    needs: [backend, backend-integration, frontend, security]
    concurrency:
      group: deploy-production
      cancel-in-progress: false
    if: |
      gitea.event_name == 'push' &&
      gitea.ref == 'refs/heads/main'
    env:
      DEPLOY_PATH: /home/projekte_bao/nexus
      ENV_POSTGRES_PASSWORD: ${{ secrets.ENV_POSTGRES_PASSWORD }}
      ENV_JWT_KEY: ${{ secrets.ENV_JWT_KEY }}
      ENV_BOOTSTRAP_OWNER_PASSWORD: ${{ secrets.ENV_BOOTSTRAP_OWNER_PASSWORD }}
      ENV_OPENCLAW_TOKEN: ${{ secrets.ENV_OPENCLAW_TOKEN }}
    steps:
      - name: Checkout
        uses: actions/checkout@v4

      - name: Deploy after green CI
        run: sh .gitea/scripts/deploy-nexus.sh
