name: Backport CommonCore

on:
  pull_request:
    types:
      - closed
    branches:
      - main

permissions:
  contents: write
  pull-requests: write

env:
  BACKPORT_PATH: CommonCore
  BACKPORT_BRANCH_PREFIX: backport/commoncore
  DISABLE_BACKPORT_LABEL: no-backport

jobs:
  backport:
    name: Create CommonCore backport PRs
    runs-on: ubuntu-latest
    steps:
      - name: Checkout sources
        uses: actions/checkout@v6
        with:
          fetch-depth: 0

      - name: Check backport eligibility
        id: eligibility
        shell: bash
        env:
          GITHUB_TOKEN: ${{ secrets.CI_BOT_TOKEN }}
        run: |
          set -euo pipefail

          api_url="${GITHUB_API_URL:-${GITHUB_SERVER_URL}/api/v1}"

          echo "Backport debug: event=${GITHUB_EVENT_NAME:-unknown}"
          echo "Backport debug: server=${GITHUB_SERVER_URL}"
          echo "Backport debug: api=${api_url}"
          echo "Backport debug: repository=${GITHUB_REPOSITORY}"
          echo "Backport debug: action=$(jq -r '.action // ""' "$GITHUB_EVENT_PATH")"

          merged="$(jq -r '.pull_request.merged // (.pull_request.merged_at != null)' "$GITHUB_EVENT_PATH")"
          base_branch="$(jq -r '.pull_request.base.ref' "$GITHUB_EVENT_PATH")"
          has_disable_label="$(jq -r --arg disable_backport_label "$DISABLE_BACKPORT_LABEL" 'any(.pull_request.labels[]?; .name == $disable_backport_label)' "$GITHUB_EVENT_PATH")"
          echo "Backport debug: pr=$(jq -r '.pull_request.number // ""' "$GITHUB_EVENT_PATH") base=${base_branch} merged=${merged}"
          echo "Backport debug: disable label present=${has_disable_label}"

          {
            echo "should_backport=$([[ "$merged" == "true" && "$base_branch" == "main" && "$has_disable_label" != "true" ]] && echo true || echo false)"
            echo "pr_number=$(jq -r '.pull_request.number' "$GITHUB_EVENT_PATH")"
            echo "pr_title<<EOF"
            jq -r '.pull_request.title' "$GITHUB_EVENT_PATH"
            echo "EOF"
          } >> "$GITHUB_OUTPUT"

          labels="$(curl -fsS \
            -H "Accept: application/json" \
            -H "Authorization: token ${GITHUB_TOKEN}" \
            "${api_url}/repos/${GITHUB_REPOSITORY}/labels")"

          if ! jq -e --arg disable_backport_label "$DISABLE_BACKPORT_LABEL" 'any(.[]; .name == $disable_backport_label)' <<< "$labels" >/dev/null; then
            curl -fsS -X POST \
              -H "Accept: application/json" \
              -H "Authorization: token ${GITHUB_TOKEN}" \
              -H "Content-Type: application/json" \
              -d "$(jq -n --arg name "$DISABLE_BACKPORT_LABEL" --arg color "ededed" --arg description "Disable automatic CommonCore backporting for this pull request." '{name: $name, color: $color, description: $description}')" \
              "${api_url}/repos/${GITHUB_REPOSITORY}/labels"
          fi

      - name: Create backport pull requests
        if: steps.eligibility.outputs.should_backport == 'true'
        shell: bash
        env:
          GITHUB_TOKEN: ${{ secrets.CI_BOT_TOKEN }}
          PR_NUMBER: ${{ steps.eligibility.outputs.pr_number }}
          PR_TITLE: ${{ steps.eligibility.outputs.pr_title }}
        run: |
          set -euo pipefail

          api_url="${GITHUB_API_URL:-${GITHUB_SERVER_URL}/api/v1}"
          repo_api_path="/repos/${GITHUB_REPOSITORY}"

          api_request() {
            local method="$1"
            local path="$2"
            local output="$3"
            local data_file="${4:-}"
            local status
            local args=(-sS -X "$method" -H "Accept: application/json" -H "Authorization: token ${GITHUB_TOKEN}" -w "%{http_code}" -o "$output")

            if [[ -n "$data_file" ]]; then
              args+=(-H "Content-Type: application/json" --data-binary "@${data_file}")
            fi

            echo "Backport debug: ${method} ${path}"
            if ! status="$(curl "${args[@]}" "${api_url}${path}")"; then
              echo "Backport debug: ${method} ${path} failed before HTTP status was captured."
              if [[ -s "$output" ]]; then
                echo "Backport debug: response body:"
                cat "$output"
              fi
              return 1
            fi

            echo "Backport debug: ${method} ${path} -> HTTP ${status}"
            if [[ ! "$status" =~ ^2 ]]; then
              echo "Backport debug: response body:"
              cat "$output"
              return 1
            fi
          }

          echo "Backport debug: event=${GITHUB_EVENT_NAME:-unknown}"
          echo "Backport debug: server=${GITHUB_SERVER_URL}"
          echo "Backport debug: api=${api_url}"
          echo "Backport debug: repository=${GITHUB_REPOSITORY}"
          echo "Backport debug: pr=${PR_NUMBER}"
          echo "Backport debug: actor=${GITHUB_ACTOR:-unknown}"

          git config user.name "SteamWar Backport Bot"
          git config user.email "actions@steamwar.de"

          if [[ "${GITHUB_SERVER_URL}" == https://* ]]; then
            auth_host="${GITHUB_SERVER_URL#https://}"
            git remote set-url origin "https://oauth2:${GITHUB_TOKEN}@${auth_host}/${GITHUB_REPOSITORY}.git"
          fi

          git fetch --prune origin '+refs/heads/version/*:refs/remotes/origin/version/*'

          api_request GET "${repo_api_path}" repo-debug.json
          jq -r '"Backport debug: repo permissions admin=\(.permissions.admin // "unknown") push=\(.permissions.push // "unknown") pull=\(.permissions.pull // "unknown")"' repo-debug.json || true

          echo "Backport debug: GET ${repo_api_path}/pulls/${PR_NUMBER}.diff"
          curl -fsSL -w "Backport debug: GET ${repo_api_path}/pulls/${PR_NUMBER}.diff -> HTTP %{http_code}\n" \
            -H "Accept: text/plain" \
            -H "Authorization: token ${GITHUB_TOKEN}" \
            "${api_url}${repo_api_path}/pulls/${PR_NUMBER}.diff" \
            -o pull-request.diff

          if ! grep -Eq "^diff --git a/${BACKPORT_PATH}/" pull-request.diff; then
            echo "Pull request #${PR_NUMBER} has no ${BACKPORT_PATH} changes to backport."
            exit 0
          fi

          mapfile -t target_branches < <(git for-each-ref --format='%(refname:strip=3)' refs/remotes/origin/version)
          if [[ "${#target_branches[@]}" -eq 0 ]]; then
            echo "No version/* branches found."
            exit 0
          fi

          for target_branch in "${target_branches[@]}"; do
            safe_target="${target_branch//\//-}"
            backport_branch="${BACKPORT_BRANCH_PREFIX}/pr-${PR_NUMBER}-to-${safe_target}"

            git checkout -B "${backport_branch}" "origin/${target_branch}"
            git reset --hard "origin/${target_branch}"

            if ! git apply --3way --index --include="${BACKPORT_PATH}/**" pull-request.diff; then
              echo "Failed to apply CommonCore backport for ${target_branch}."
              exit 1
            fi

            if git diff --cached --quiet; then
              echo "CommonCore changes from #${PR_NUMBER} are already present in ${target_branch}."
              continue
            fi

            git commit -m "Backport CommonCore changes from #${PR_NUMBER}" -m "${PR_TITLE}"
            git push --force-with-lease origin "${backport_branch}"

            api_request GET "${repo_api_path}/pulls?state=open" open-pulls.json
            open_pr_number="$(jq -r --arg base "$target_branch" --arg head "$backport_branch" '[.[] | select(.base.ref == $base and .head.ref == $head) | (.number // .index)][0] // empty' open-pulls.json)"

            if [[ -n "$open_pr_number" ]]; then
              echo "Backport PR #${open_pr_number} already exists for ${target_branch}."
              continue
            fi

            pr_body="$(printf 'Automatic CommonCore backport of #%s.\n\nOriginal PR title: %s\n\nOnly files below `CommonCore/` are included.' "$PR_NUMBER" "$PR_TITLE")"

            jq -n \
              --arg base "$target_branch" \
              --arg head "$backport_branch" \
              --arg title "Backport CommonCore changes from #${PR_NUMBER} to ${target_branch}" \
              --arg body "$pr_body" \
              '{base: $base, head: $head, title: $title, body: $body}' > create-pull.json

            echo "Backport debug: create PR base=${target_branch} head=${backport_branch}"
            api_request POST "${repo_api_path}/pulls" create-pull-response.json create-pull.json
          done
