name: SonarQube Analysis

on:
  push:
  pull_request:
    types: [opened, synchronize, reopened]

concurrency:
  group: ${{ github.workflow }}-${{ github.ref }}
  cancel-in-progress: true

jobs:
  sonarqube:
    name: Build, Test & Analyse
    runs-on: ubuntu-latest
    timeout-minutes: 15

    env:
      SONAR_PROJECT_KEY: security-scan-test

    steps:
      - name: Checkout repository
        uses: actions/checkout@v4
        with:
          fetch-depth: 0

      - name: Set up JDK 17
        uses: actions/setup-java@v4
        with:
          java-version: '17'
          distribution: 'temurin'

      - name: Make Maven wrapper executable
        run: chmod +x mvnw

      - name: Cache Maven packages
        uses: actions/cache@v4
        with:
          path: ~/.m2/repository
          key: maven-${{ runner.os }}-${{ hashFiles('**/pom.xml') }}
          restore-keys: maven-${{ runner.os }}-

      - name: Cache SonarQube analysis data
        uses: actions/cache@v4
        with:
          path: ~/.sonar/cache
          key: sonar-${{ runner.os }}
          restore-keys: sonar-${{ runner.os }}

      # SONAR_TOKEN replaced by SONAR_ADMIN_TOKEN — the admin token is used
      # only for provisioning; the scan uses an ephemeral PROJECT_ANALYSIS_TOKEN
      # generated in the bootstrap step below.
      - name: Validate required secrets
        env:
          SONAR_ADMIN_TOKEN: 
          SONAR_HOST_URL: 
        run: |
          [[ -n "$SONAR_ADMIN_TOKEN" ]] || { echo "::error::SONAR_ADMIN_TOKEN is not set"; exit 1; }
          [[ -n "$SONAR_HOST_URL" ]]    || { echo "::error::SONAR_HOST_URL is not set"; exit 1; }
          [[ -n "$SONAR_PROJECT_KEY" ]] || { echo "::error::SONAR_PROJECT_KEY is not set"; exit 1; }

      - name: Bootstrap SonarQube project and generate scan token
        id: sonar-bootstrap
        env:
          SONAR_ADMIN_TOKEN: 
          SONAR_HOST_URL: 
        run: |
          # ---- 1. Create the project if it doesn't already exist ----
          PROJECT_COUNT=$(curl -sf \
            -u "${SONAR_ADMIN_TOKEN}:" \
            "${SONAR_HOST_URL}/api/projects/search?projects=${SONAR_PROJECT_KEY}" \
            | jq '.paging.total')

          if [[ "$PROJECT_COUNT" == "0" ]]; then
            echo "Project '${SONAR_PROJECT_KEY}' not found — creating it..."
            curl -sf -X POST \
              -u "${SONAR_ADMIN_TOKEN}:" \
              "${SONAR_HOST_URL}/api/projects/create" \
              --data-urlencode "name=${SONAR_PROJECT_KEY}" \
              --data-urlencode "project=${SONAR_PROJECT_KEY}" \
              --data-urlencode "mainBranch=main" \
              --data-urlencode "visibility=private"
            echo "✅ Project created."
          else
            echo "✅ Project '${SONAR_PROJECT_KEY}' already exists — skipping creation."
          fi

          # ---- 2. Revoke any leftover token from a previous failed run ----
          TOKEN_NAME="gitea-scan-${SONAR_PROJECT_KEY}"
          curl -sf -X POST \
            -u "${SONAR_ADMIN_TOKEN}:" \
            "${SONAR_HOST_URL}/api/user_tokens/revoke" \
            --data-urlencode "name=${TOKEN_NAME}" \
            > /dev/null 2>&1 || true

          # ---- 3. Generate a fresh PROJECT_ANALYSIS_TOKEN for this run ----
          SCAN_TOKEN=$(curl -sf -X POST \
            -u "${SONAR_ADMIN_TOKEN}:" \
            "${SONAR_HOST_URL}/api/user_tokens/generate" \
            --data-urlencode "name=${TOKEN_NAME}" \
            --data-urlencode "type=PROJECT_ANALYSIS_TOKEN" \
            --data-urlencode "projectKey=${SONAR_PROJECT_KEY}" \
            | jq -r '.token')

          [[ -n "$SCAN_TOKEN" ]] || { echo "::error::Failed to generate scan token"; exit 1; }

          echo "✅ Scan token generated for project '${SONAR_PROJECT_KEY}'"
          echo "::add-mask::${SCAN_TOKEN}"
          echo "SCAN_TOKEN=${SCAN_TOKEN}" >> "$GITHUB_ENV"

      - name: Build and test
        run: |
          ./mvnw -B verify \
            -Dtest='!PostgresIntegrationTests,!MySqlIntegrationTests'

      - name: SonarQube analysis
        env:
          SCAN_TOKEN: 
          SONAR_HOST_URL: 
        run: |
          ./mvnw -B org.sonarsource.scanner.maven:sonar-maven-plugin:4.0.0.4121:sonar \
            -Dsonar.projectKey="${SONAR_PROJECT_KEY}" \
            -Dsonar.host.url="${SONAR_HOST_URL}" \
            -Dsonar.token="${SCAN_TOKEN}" \
            -Dsonar.java.source=17 \
            -Dsonar.coverage.jacoco.xmlReportPaths=target/site/jacoco/jacoco.xml

      - name: Quality Gate check
        env:
          SCAN_TOKEN: 
          SONAR_HOST_URL: 
        run: |
          echo "Waiting for SonarQube to process the analysis..."
          for i in $(seq 1 24); do
            RESPONSE=$(curl -sf -u "${SCAN_TOKEN}:" \
              "${SONAR_HOST_URL}/api/qualitygates/project_status?projectKey=${SONAR_PROJECT_KEY}" || true)
            STATUS=$(echo "$RESPONSE" | jq -r '.projectStatus.status' 2>/dev/null || echo "NONE")
            if [[ "$STATUS" =~ ^(OK|ERROR|WARN)$ ]]; then break; fi
            echo "  Status: ${STATUS:-pending} — retrying in 5s..."
            sleep 5
          done
          echo "Quality Gate status: $STATUS"
          [[ "$STATUS" != "ERROR" ]] || { echo "::error::Quality Gate FAILED"; exit 1; }

      - name: Revoke scan token
        if: always()
        env:
          SONAR_ADMIN_TOKEN: 
          SONAR_HOST_URL: 
        run: |
          curl -sf -X POST \
            -u "${SONAR_ADMIN_TOKEN}:" \
            "${SONAR_HOST_URL}/api/user_tokens/revoke" \
            --data-urlencode "name=gitea-scan-${SONAR_PROJECT_KEY}" \
            && echo "✅ Scan token revoked" \
            || echo "⚠️  Token revocation failed (may have already been removed)"
