pipeline {
  agent {
    kubernetes {
      label 'pegasus-tests'
      defaultContainer 'go-tester'
      yaml """
apiVersion: v1
kind: Pod
spec:
  nodeSelector:
    kubernetes.io/arch: arm64
    node-role.kubernetes.io/worker: "true"
  containers:
    - name: go-tester
      image: golang:1.22-bookworm
      command: ["cat"]
      tty: true
      volumeMounts:
        - name: workspace-volume
          mountPath: /home/jenkins/agent
    - name: node-tester
      image: node:20-bookworm
      command: ["cat"]
      tty: true
      volumeMounts:
        - name: workspace-volume
          mountPath: /home/jenkins/agent
    - name: publisher
      image: python:3.12-slim
      command: ["cat"]
      tty: true
      volumeMounts:
        - name: workspace-volume
          mountPath: /home/jenkins/agent
  volumes:
    - name: workspace-volume
      emptyDir: {}
"""
    }
  }

  environment {
    SUITE_NAME = 'pegasus'
    PUSHGATEWAY_URL = 'http://platform-quality-gateway.monitoring.svc.cluster.local:9091'
  }

  options {
    disableConcurrentBuilds()
  }

  triggers {
    pollSCM('H/5 * * * *')
  }

  stages {
    stage('Checkout') {
      steps {
        checkout scm
      }
    }

    stage('Backend unit tests') {
      steps {
        container('go-tester') {
          sh '''
            set -euo pipefail
            mkdir -p build
            cd backend
            go install github.com/jstemmer/go-junit-report/v2@latest
            set +e
            go test -coverprofile=../build/coverage-backend.out ./... > ../build/backend-test.out 2>&1
            test_rc=$?
            set -e
            cat ../build/backend-test.out
            "$(go env GOPATH)/bin/go-junit-report" < ../build/backend-test.out > ../build/junit-backend.xml
            coverage="0"
            if [ -f ../build/coverage-backend.out ]; then
              coverage="$(go tool cover -func=../build/coverage-backend.out | awk '/^total:/ {gsub("%","",$3); print $3}')"
            fi
            printf '%s\n' "${coverage}" > ../build/coverage-backend-percent.txt
            printf '%s\n' "${test_rc}" > ../build/backend-test.rc
          '''
        }
      }
    }

    stage('Frontend unit tests') {
      steps {
        container('node-tester') {
          sh '''
            set -euo pipefail
            mkdir -p build
            cd frontend
            npm ci
            set +e
            npm run test:ci > ../build/frontend-test.out 2>&1
            test_rc=$?
            set -e
            cat ../build/frontend-test.out
            if [ -f ../build/frontend-coverage/coverage-summary.json ]; then
              node -e 'const fs=require("fs");const p=JSON.parse(fs.readFileSync("../build/frontend-coverage/coverage-summary.json","utf8"));const pct=((p.total||{}).lines||{}).pct||0;process.stdout.write(String(pct));' > ../build/coverage-frontend-percent.txt
            else
              echo "0" > ../build/coverage-frontend-percent.txt
            fi
            printf '%s\n' "${test_rc}" > ../build/frontend-test.rc
          '''
        }
      }
    }

    stage('Combine coverage summary') {
      steps {
        container('publisher') {
          sh '''
            set -euo pipefail
            python - <<'PY'
import json
from pathlib import Path

build = Path('build')
def read_float(path: Path) -> float:
    if not path.exists():
        return 0.0
    try:
        return float(path.read_text(encoding='utf-8').strip())
    except ValueError:
        return 0.0

backend = read_float(build / 'coverage-backend-percent.txt')
frontend = read_float(build / 'coverage-frontend-percent.txt')
combined = (backend + frontend) / 2 if (backend or frontend) else 0.0

(build / 'coverage.json').write_text(
    json.dumps(
        {
            'summary': {
                'backend_percent': backend,
                'frontend_percent': frontend,
                'percent_covered': combined,
            }
        },
        indent=2,
    ) + '\n',
    encoding='utf-8',
)
print(f'Combined Pegasus coverage: {combined:.2f}%')
PY
          '''
        }
      }
    }

    stage('Publish test metrics') {
      steps {
        container('publisher') {
          sh '''
            set -euo pipefail
            python scripts/publish_test_metrics.py
          '''
        }
      }
    }

    stage('Quality gate') {
      steps {
        container('publisher') {
          sh '''
            set -euo pipefail
            backend_rc="$(cat build/backend-test.rc 2>/dev/null || echo 1)"
            frontend_rc="$(cat build/frontend-test.rc 2>/dev/null || echo 1)"
            if [ "${backend_rc}" -ne 0 ] || [ "${frontend_rc}" -ne 0 ]; then
              echo "Pegasus test suite failed (backend=${backend_rc}, frontend=${frontend_rc})"
              exit 1
            fi
          '''
        }
      }
    }
  }

  post {
    always {
      script {
        if (fileExists('build/junit-backend.xml') || fileExists('build/junit-frontend.xml')) {
          try {
            junit allowEmptyResults: true, testResults: 'build/junit-backend.xml,build/junit-frontend.xml'
          } catch (Throwable err) {
            echo "junit step unavailable: ${err.class.simpleName}"
          }
        }
      }
      archiveArtifacts artifacts: 'build/**', allowEmptyArchive: true, fingerprint: true
    }
  }
}
