name: contribution
on:
  pull_request:
    paths:
      - 'mappings/contributions/**'

concurrency:
  group: contribution-${{ github.event.pull_request.number }}
  cancel-in-progress: true

jobs:
  contribution:
    runs-on: s2-runner
    env:
      STEAM_APPS: /home/cs2/.steam/SteamApps
      RELEASE_BASE: ${{ github.server_url }}/${{ github.repository }}/releases/download
      API: ${{ github.server_url }}/api/v1/repos/${{ github.repository }}
    steps:
      - uses: actions/checkout@v6.0.2
        with:
          fetch-depth: 0

      - name: Resolve the affected game and its paths
        run: |
          changed=$(git diff --name-only "origin/${{ github.base_ref }}...HEAD" -- 'mappings/contributions/**')
          game=""
          if echo "$changed" | grep -q 'contributions/csgo/'; then game=cs2; fi
          if echo "$changed" | grep -q 'contributions/dota/'; then
            if [ -n "$game" ]; then echo "PR touches both games — split it into one PR per game"; exit 1; fi
            game=dota2
          fi
          if [ -z "$game" ]; then echo "no contributions/<game>/ files changed"; exit 1; fi
          case "$game" in cs2) key=csgo; appid=730 ;; dota2) key=dota; appid=570 ;; esac

          # The manifest carries the installed buildid + the install folder name (spaces and all).
          manifest="$STEAM_APPS/appmanifest_$appid.acf"
          [ -f "$manifest" ] || { echo "no manifest at $manifest — check STEAM_APPS"; exit 1; }
          installdir=$(grep -oP '"installdir"\s+"\K[^"]+' "$manifest")
          buildid=$(grep -oP '"buildid"\s+"\K[0-9]+' "$manifest")
          game_dir="$STEAM_APPS/common/$installdir/game"
          [ -d "$game_dir" ] || { echo "expected a game tree at '$game_dir' — check STEAM_APPS"; exit 1; }
          {
            echo "GAME=$game"
            echo "KEY=$key"
            echo "APPID=$appid"
            echo "GAME_DIR=$game_dir"
            echo "BUILDID=$buildid"
          } >> "$GITHUB_ENV"

      - name: Next patch number for this build
        run: |
          # The game-update run published <game>-<buildid>-0; each contribution on that build bumps the patch.
          tags=$(curl -fsSL -H "Authorization: token ${{ secrets.GITHUB_TOKEN }}" "$API/releases?limit=100" | jq -r '.[].tag_name')
          max=0
          while read -r t; do
            case "$t" in
              "$GAME-$BUILDID-"*) p=${t##*-}; if [ "$p" -gt "$max" ] 2>/dev/null; then max=$p; fi ;;
            esac
          done <<< "$tags"
          echo "PATCH=$((max + 1))" >> "$GITHUB_ENV"

      - name: Fetch current model + seed
        # Stored gzipped on the release (see derive.yml); the deriver reads plain JSON.
        run: |
          mkdir -p in dist work
          curl -fsSL -o in/model.gz "$RELEASE_BASE/$GAME-latest/model-$GAME.json.gz"
          gunzip -c in/model.gz > "in/model-$GAME.json"
          curl -fsSL -o in/seed.gz "$RELEASE_BASE/$GAME-latest/seed-$GAME.json.gz"
          gunzip -c in/seed.gz > "seed-$GAME.json"

      - name: Fold the PR's contributions into the seed's snapshot
        run: |
          python3 - "$KEY" "seed-$GAME.json" "seed-$GAME.patched.json" <<'PY'
          import json, sys, glob, os
          key, seed_in, seed_out = sys.argv[1:4]
          seed = json.load(open(seed_in))
          contribs = dict(seed.get("contributions") or {})
          for f in glob.glob(f"mappings/contributions/{key}/*.json"):
              contribs[os.path.basename(f)] = json.load(open(f))
          seed["contributions"] = contribs
          json.dump(seed, open(seed_out, "w"))
          PY

      - name: Build the deriver
        run: cargo build --release

      - name: Produce — validate the contribution live (no model fold; the build is unchanged)
        run: |
          ln -sfn "$GAME_DIR" "work/$BUILDID-$PATCH"
          ./target/release/source2rosetta --game "$GAME" produce \
            --seed         "seed-$GAME.patched.json" \
            --corpus-model "in/model-$GAME.json" \
            --target       "work/$BUILDID-$PATCH" \
            --game-dir     "$GAME_DIR" \
            --version      "$GAME-$BUILDID-$PATCH" \
            --out-dir      dist
          cp "seed-$GAME.patched.json" "dist/seed-$GAME.json"

      - name: Drop the re-folded model, compress the seed
        run: |
          rm -f "dist/model-$GAME.json"
          gzip -6 "dist/seed-$GAME.json"

      - name: Publish the immutable patch snapshot
        uses: https://code.forgejo.org/actions/forgejo-release@v2
        with:
          direction: upload
          url: ${{ github.server_url }}
          repo: ${{ github.repository }}
          tag: ${{ env.GAME }}-${{ env.BUILDID }}-${{ env.PATCH }}
          release-dir: dist
          token: ${{ secrets.GITHUB_TOKEN }}
          override: true
          release-notes: "${{ env.GAME }} gamedata — build ${{ env.BUILDID }}, patch ${{ env.PATCH }} (contribution PR #${{ github.event.pull_request.number }})."

      - name: Move <game>-latest to this patch
        uses: https://code.forgejo.org/actions/forgejo-release@v2
        with:
          direction: upload
          url: ${{ github.server_url }}
          repo: ${{ github.repository }}
          tag: ${{ env.GAME }}-latest
          release-dir: dist
          token: ${{ secrets.GITHUB_TOKEN }}
          override: true
          release-notes: "Rolling ${{ env.GAME }} gamedata — currently build ${{ env.BUILDID }} patch ${{ env.PATCH }}. Stable URL; assets overwritten on each update."
