name: Build Geocoder Index

concurrency:
  group: geocoder-build-${{ github.event_name == 'pull_request' && github.head_ref || github.ref }}
  cancel-in-progress: ${{ github.event_name == 'pull_request' }}

on:
  schedule:
    # Daily at 06:00 UTC
    - cron: '0 6 * * *'
  pull_request:
    types: [opened, synchronize, reopened, labeled]
    paths:
      - 'geocoder/**'
      - '.github/workflows/geocoder-build.yml'
  workflow_dispatch:
    inputs:
      pbf_url:
        description: 'Override PBF URL (leave empty to use replication diffs)'
        required: false
        type: string
      force_fresh_download:
        description: 'Force fresh planet PBF download (skip replication diffs)'
        required: false
        type: boolean
        default: false
      skip_patch:
        description: 'Skip patch generation'
        required: false
        type: boolean
        default: false
      runner:
        description: 'Runner label'
        required: false
        type: string
        default: 'self-hosted'

env:
  S3_BUCKET: geoshenanigans-reverse-geocoding
  S3_ENDPOINT: https://fly.storage.tigris.dev
  S3_PREFIX: geocoder
  REGIONS: "planet africa asia europe north-america south-america oceania central-america antarctica"

permissions:
  contents: read

jobs:
  # --- PR validation: build tools + small test build ---
  validate:
    if: github.event_name == 'pull_request'
    runs-on: ubuntu-latest
    timeout-minutes: 30
    steps:
      - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6
        with:
          persist-credentials: false

      - name: Install dependencies
        run: |
          sudo apt-get update -qq
          sudo apt-get install -y -qq cmake g++ libz-dev libzstd-dev \
            libbz2-dev libexpat1-dev libs2-dev libosmium2-dev

      - name: Build tools
        run: |
          cd geocoder/builder && mkdir -p build && cd build
          cmake .. -DCMAKE_BUILD_TYPE=Release
          make -j$(nproc) build-index geocoder-diff geocoder-patch

      - name: Download Monaco PBF
        run: |
          curl -sL -o /tmp/monaco.osm.pbf \
            "https://download.geofabrik.de/europe/monaco-latest.osm.pbf"

      - name: Test determinism + diff + patch
        run: |
          cd geocoder/builder/build
          RUNS=5

          # Build N times from same PBF
          for i in $(seq 1 $RUNS); do
            echo "=== Build $i/$RUNS ==="
            ./build-index "/tmp/build-$i/" /tmp/monaco.osm.pbf --simplify-epsilon --epsilon-scale 1 2>&1 | tail -1
          done

          # Cross-compare all builds against build 1
          echo ""
          echo "=== Determinism check ($RUNS builds) ==="
          FAIL=0
          for i in $(seq 2 $RUNS); do
            for f in /tmp/build-1/*.bin; do
              b=$(basename "$f")
              if ! cmp -s "/tmp/build-1/$b" "/tmp/build-$i/$b"; then
                echo "::error::Build $i differs from build 1: $b"
                FAIL=1
              fi
            done
          done
          [ $FAIL -eq 0 ] && echo "Determinism: PASS ($RUNS identical builds)" || exit 1

          # Test diff + patch round-trip (build 1 → build 1, should be identity)
          echo ""
          echo "=== Diff + Patch round-trip ==="
          ./geocoder-diff /tmp/build-1/ /tmp/build-1/ -o /tmp/test.gcpatch 2>&1 | tail -1
          ./geocoder-patch /tmp/build-1/ /tmp/test.gcpatch -o /tmp/patched/ 2>&1 | tail -1

          for f in /tmp/build-1/*.bin; do
            b=$(basename "$f")
            if ! cmp -s "/tmp/patched/$b" "/tmp/build-1/$b"; then
              echo "::error::Patch round-trip MISMATCH: $b"
              FAIL=1
            fi
          done
          [ $FAIL -eq 0 ] && echo "Patch round-trip: PASS" || exit 1

  # --- PR planet test: full build + validation without S3 (triggered by label) ---
  planet-test:
    if: github.event_name == 'pull_request' && contains(github.event.pull_request.labels.*.name, 'planet-test')
    runs-on: pokedex-giant
    timeout-minutes: 360

    steps:
      - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6
        with:
          persist-credentials: false

      - name: Install dependencies
        run: |
          sudo apt-get update -qq
          sudo apt-get install -y -qq cmake g++ libz-dev libzstd-dev \
            libbz2-dev libexpat1-dev libs2-dev libosmium2-dev aria2 jq unzip python3-pip
          curl -sL "https://awscli.amazonaws.com/awscli-exe-linux-x86_64.zip" -o /tmp/awscliv2.zip
          unzip -q /tmp/awscliv2.zip -d /tmp && sudo /tmp/aws/install
          pip install --break-system-packages osmium 2>/dev/null \
            || pip install --user osmium 2>/dev/null \
            || python3 -m pip install --user --break-system-packages osmium
          echo "$HOME/.local/bin" >> "$GITHUB_PATH"

      - name: Configure S3 credentials
        run: |
          echo "AWS_ACCESS_KEY_ID=$S3_ACCESS_KEY_ID" >> "$GITHUB_ENV"
          echo "AWS_SECRET_ACCESS_KEY=$S3_SECRET_ACCESS_KEY" >> "$GITHUB_ENV"
          echo "AWS_DEFAULT_REGION=auto" >> "$GITHUB_ENV"
          echo "AWS_ENDPOINT_URL=$S3_ENDPOINT" >> "$GITHUB_ENV"
        env:
          S3_ACCESS_KEY_ID: ${{ secrets.TIGRIS_WRITE_KEY_ID }}
          S3_SECRET_ACCESS_KEY: ${{ secrets.TIGRIS_WRITE_ACCESS_KEY }}

      - name: Build tools
        run: |
          cd geocoder/builder && mkdir -p build && cd build
          cmake .. -DCMAKE_BUILD_TYPE=Release
          make -j$(nproc) build-index geocoder-diff geocoder-patch
          echo "$PWD" >> "$GITHUB_PATH"

      - name: Download planet PBF
        id: pbf
        env:
          RUNNER_TEMP: ${{ runner.temp }}
        run: |
          WORKDIR="$RUNNER_TEMP/geocoder-test"
          mkdir -p "$WORKDIR"
          echo "workdir=$WORKDIR" >> "$GITHUB_OUTPUT"

          PBF_URL=$(curl -sI "https://planet.openstreetmap.org/pbf/planet-latest.osm.pbf" \
            | grep -i '^location:' | awk '{print $2}' | tr -d '\r')
          echo "Downloading $PBF_URL..."
          aria2c -x 8 -s 8 --max-tries=3 -d "$WORKDIR" -o planet.osm.pbf "$PBF_URL"
          ls -lh "$WORKDIR/planet.osm.pbf"

      - name: Build "old" index from downloaded PBF
        id: old_build
        env:
          WORKDIR: ${{ steps.pbf.outputs.workdir }}
        run: |
          OLD_DATE=$(date -u -d "yesterday" +%Y-%m-%d)
          echo "date=$OLD_DATE" >> "$GITHUB_OUTPUT"
          echo "Building 'old' index ($OLD_DATE) from base PBF..."
          time build-index "$WORKDIR/old-output/" "$WORKDIR/planet.osm.pbf" \
            --simplify-epsilon --epsilon-scale 1 \
            --continents --multi-output --multi-quality 2>&1 | tail -10
          find "$WORKDIR/old-output" -name "*.bin" | wc -l
          echo "bin files produced"

      - name: Upload old build to S3
        env:
          WORKDIR: ${{ steps.pbf.outputs.workdir }}
          OLD_DATE: ${{ steps.old_build.outputs.date }}
        run: |
          echo "Uploading old build as $OLD_DATE..."
          aws s3 sync "$WORKDIR/old-output/" \
            "s3://$S3_BUCKET/$S3_PREFIX/builds/$OLD_DATE/" \
            --no-progress --only-show-errors

      - name: Apply replication diffs to PBF
        env:
          WORKDIR: ${{ steps.pbf.outputs.workdir }}
        run: |
          echo "Applying replication diffs to bring PBF up to date..."
          pyosmium-up-to-date -v \
            --server https://planet.openstreetmap.org/replication/day \
            -s 2000 "$WORKDIR/planet.osm.pbf" 2>&1

      - name: Build "new" index from updated PBF
        id: new_build
        env:
          WORKDIR: ${{ steps.pbf.outputs.workdir }}
        run: |
          NEW_DATE=$(date -u +%Y-%m-%d)
          echo "date=$NEW_DATE" >> "$GITHUB_OUTPUT"
          echo "Building 'new' index ($NEW_DATE) from updated PBF..."
          time build-index "$WORKDIR/output/" "$WORKDIR/planet.osm.pbf" \
            --simplify-epsilon --epsilon-scale 1 \
            --continents --multi-output --multi-quality 2>&1 | tail -10
          rm -f "$WORKDIR/planet.osm.pbf"
          find "$WORKDIR/output" -name "*.bin" | wc -l
          echo "bin files produced"

      - name: Generate and verify patches for all variants
        env:
          WORKDIR: ${{ steps.pbf.outputs.workdir }}
          OLD_DATE: ${{ steps.old_build.outputs.date }}
          NEW_DATE: ${{ steps.new_build.outputs.date }}
        run: |
          echo "## Planet Test Results ($OLD_DATE → $NEW_DATE)" >> "$GITHUB_STEP_SUMMARY"
          echo "" >> "$GITHUB_STEP_SUMMARY"
          echo "| Variant | Files | Patch Size | Verified |" >> "$GITHUB_STEP_SUMMARY"
          echo "|---------|-------|-----------|----------|" >> "$GITHUB_STEP_SUMMARY"

          PASS=0; FAIL=0; SKIP=0
          VARIANTS=$(cd "$WORKDIR/output" && find . -name "*.bin" -exec dirname {} \; | sort -u | sed 's|^\./||')

          for variant in $VARIANTS; do
            NEW_DIR="$WORKDIR/output/$variant"
            OLD_DIR="$WORKDIR/old-output/$variant"
            N_NEW=$(ls "$NEW_DIR"/*.bin 2>/dev/null | wc -l)
            N_OLD=$(ls "$OLD_DIR"/*.bin 2>/dev/null | wc -l)
            [ "$N_NEW" -lt 2 ] && continue
            if [ "$N_OLD" -ne "$N_NEW" ]; then
              SKIP=$((SKIP + 1))
              continue
            fi

            PATCH_FILE="$WORKDIR/test.gcpatch"
            geocoder-diff "$OLD_DIR" "$NEW_DIR" -o "$PATCH_FILE" 2>/dev/null
            PATCH_SIZE=$(stat -c%s "$PATCH_FILE" 2>/dev/null || echo 0)
            PATCH_KB=$((PATCH_SIZE / 1024))

            VERIFY_DIR="$WORKDIR/verify"
            rm -rf "$VERIFY_DIR"; mkdir -p "$VERIFY_DIR"
            geocoder-patch "$OLD_DIR" "$PATCH_FILE" -o "$VERIFY_DIR/" 2>/dev/null

            MATCH=0
            for f in "$NEW_DIR"/*.bin; do
              b=$(basename "$f")
              h1=$(md5sum "$VERIFY_DIR/$b" 2>/dev/null | awk '{print $1}')
              h2=$(md5sum "$NEW_DIR/$b" | awk '{print $1}')
              [ "$h1" = "$h2" ] && MATCH=$((MATCH + 1))
            done

            if [ $MATCH -eq $N_NEW ]; then
              echo "  $variant: PASS ($MATCH/$N_NEW, ${PATCH_KB} KiB)"
              echo "| $variant | $N_NEW | ${PATCH_KB} KiB | PASS |" >> "$GITHUB_STEP_SUMMARY"
              PASS=$((PASS + 1))
            else
              echo "::error::$variant: FAIL ($MATCH/$N_NEW match)"
              echo "| $variant | $N_NEW | ${PATCH_KB} KiB | **FAIL** |" >> "$GITHUB_STEP_SUMMARY"
              FAIL=$((FAIL + 1))
            fi
            rm -f "$PATCH_FILE"
            rm -rf "$VERIFY_DIR"
          done

          rm -rf "$WORKDIR/old-output"

          echo "" >> "$GITHUB_STEP_SUMMARY"
          echo "**Total: $PASS pass, $FAIL fail, $SKIP skip**" >> "$GITHUB_STEP_SUMMARY"

          echo "Results: $PASS pass, $FAIL fail, $SKIP skip"
          [ $FAIL -gt 0 ] && exit 1 || true

      - name: Upload new build to S3
        env:
          WORKDIR: ${{ steps.pbf.outputs.workdir }}
          NEW_DATE: ${{ steps.new_build.outputs.date }}
        run: |
          echo "Uploading new build as $NEW_DATE..."
          aws s3 sync "$WORKDIR/output/" \
            "s3://$S3_BUCKET/$S3_PREFIX/builds/$NEW_DATE/" \
            --no-progress --only-show-errors
          echo "$NEW_DATE" | aws s3 cp - \
            "s3://$S3_BUCKET/$S3_PREFIX/builds/latest.txt" \
            --content-type text/plain
          echo "Upload complete"

  # --- Production build: full planet + S3 upload ---
  build:
    if: github.event_name != 'pull_request'
    runs-on: ${{ inputs.runner || 'pokedex-giant' }}
    timeout-minutes: 240
    permissions:
      contents: read

    steps:
      - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6
        with:
          persist-credentials: false

      - name: Install dependencies
        run: |
          sudo apt-get update -qq
          sudo apt-get install -y -qq cmake g++ libz-dev libzstd-dev \
            libbz2-dev libexpat1-dev libs2-dev libosmium2-dev aria2 jq python3-pip unzip
          curl -sL "https://awscli.amazonaws.com/awscli-exe-linux-x86_64.zip" -o /tmp/awscliv2.zip
          unzip -q /tmp/awscliv2.zip -d /tmp && sudo /tmp/aws/install
          pip install --break-system-packages osmium 2>/dev/null \
            || pip install --user osmium 2>/dev/null \
            || python3 -m pip install --user --break-system-packages osmium
          echo "$HOME/.local/bin" >> "$GITHUB_PATH"

      - name: Configure S3 credentials
        run: |
          echo "AWS_ACCESS_KEY_ID=$S3_ACCESS_KEY_ID" >> "$GITHUB_ENV"
          echo "AWS_SECRET_ACCESS_KEY=$S3_SECRET_ACCESS_KEY" >> "$GITHUB_ENV"
          echo "AWS_DEFAULT_REGION=auto" >> "$GITHUB_ENV"
          echo "AWS_ENDPOINT_URL=$S3_ENDPOINT" >> "$GITHUB_ENV"
        env:
          S3_ACCESS_KEY_ID: ${{ secrets.TIGRIS_WRITE_KEY_ID }}
          S3_SECRET_ACCESS_KEY: ${{ secrets.TIGRIS_WRITE_ACCESS_KEY }}

      - name: Build tools
        run: |
          cd geocoder/builder && mkdir -p build && cd build
          cmake .. -DCMAKE_BUILD_TYPE=Release
          make -j$(nproc) build-index geocoder-diff geocoder-patch
          echo "$PWD" >> "$GITHUB_PATH"

      - name: Determine build date
        id: meta
        run: |
          BUILD_DATE=$(date -u +%Y-%m-%d)
          echo "date=$BUILD_DATE" >> "$GITHUB_OUTPUT"

          EXISTS=$(aws s3 ls "s3://$S3_BUCKET/$S3_PREFIX/builds/$BUILD_DATE/planet/" 2>/dev/null | wc -l)
          if [ "$EXISTS" -gt 0 ]; then
            echo "skip=true" >> "$GITHUB_OUTPUT"
            echo "Build for $BUILD_DATE already exists"
          else
            echo "skip=false" >> "$GITHUB_OUTPUT"
          fi

      - name: Obtain PBF
        if: steps.meta.outputs.skip != 'true'
        id: pbf
        env:
          INPUT_PBF_URL: ${{ inputs.pbf_url }}
          INPUT_FORCE_FRESH: ${{ inputs.force_fresh_download }}
          RUNNER_TEMP: ${{ runner.temp }}
        run: |
          WORKDIR="$RUNNER_TEMP/geocoder-build"
          mkdir -p "$WORKDIR"
          echo "workdir=$WORKDIR" >> "$GITHUB_OUTPUT"

          if [ -n "$INPUT_PBF_URL" ]; then
            echo "Downloading from override URL..."
            aria2c -x 8 -s 8 --max-tries=3 -d "$WORKDIR" -o planet.osm.pbf "$INPUT_PBF_URL"
            echo "method=download" >> "$GITHUB_OUTPUT"

          elif [ "$INPUT_FORCE_FRESH" = "true" ]; then
            echo "Downloading fresh planet PBF..."
            PBF_URL=$(curl -sI "https://planet.openstreetmap.org/pbf/planet-latest.osm.pbf" \
              | grep -i '^location:' | awk '{print $2}' | tr -d '\r')
            aria2c -x 8 -s 8 --max-tries=3 -d "$WORKDIR" -o planet.osm.pbf "$PBF_URL"
            echo "method=download" >> "$GITHUB_OUTPUT"

          else
            STORED_PBF="s3://$S3_BUCKET/$S3_PREFIX/pbf/planet-current.osm.pbf"
            if aws s3 ls "$STORED_PBF" 2>/dev/null | grep -q 'planet-current'; then
              echo "Downloading stored PBF and applying replication diffs..."
              aws s3 cp "$STORED_PBF" "$WORKDIR/planet.osm.pbf" --no-progress --only-show-errors
              pyosmium-up-to-date -v \
                --server https://planet.openstreetmap.org/replication/day \
                -s 2000 "$WORKDIR/planet.osm.pbf" 2>&1
              echo "method=diff" >> "$GITHUB_OUTPUT"
            else
              echo "No stored PBF — downloading fresh planet..."
              PBF_URL=$(curl -sI "https://planet.openstreetmap.org/pbf/planet-latest.osm.pbf" \
                | grep -i '^location:' | awk '{print $2}' | tr -d '\r')
              aria2c -x 8 -s 8 --max-tries=3 -d "$WORKDIR" -o planet.osm.pbf "$PBF_URL"
              echo "method=download" >> "$GITHUB_OUTPUT"
            fi
          fi

          ls -lh "$WORKDIR/planet.osm.pbf"

      - name: Build index with all variants
        if: steps.meta.outputs.skip != 'true'
        env:
          WORKDIR: ${{ steps.pbf.outputs.workdir }}
        run: |
          echo "Building geocoder index (continents + modes + quality variants)..."
          time build-index "$WORKDIR/output/" "$WORKDIR/planet.osm.pbf" \
            --simplify-epsilon --epsilon-scale 1 \
            --continents --multi-output --multi-quality 2>&1 | tail -10
          echo ""
          find "$WORKDIR/output" -name "*.bin" | wc -l
          echo "bin files across all variants"

      - name: Upload PBF to S3
        if: steps.meta.outputs.skip != 'true'
        env:
          WORKDIR: ${{ steps.pbf.outputs.workdir }}
        run: |
          aws s3 cp "$WORKDIR/planet.osm.pbf" \
            "s3://$S3_BUCKET/$S3_PREFIX/pbf/planet-current.osm.pbf" \
            --no-progress --only-show-errors
          rm -f "$WORKDIR/planet.osm.pbf"

      - name: Upload builds to S3
        if: steps.meta.outputs.skip != 'true'
        env:
          WORKDIR: ${{ steps.pbf.outputs.workdir }}
          BUILD_DATE: ${{ steps.meta.outputs.date }}
        run: |
          S3_BUILDS="s3://$S3_BUCKET/$S3_PREFIX/builds/$BUILD_DATE"

          aws s3 sync "$WORKDIR/output/" "$S3_BUILDS/" \
            --no-progress --only-show-errors

          echo "$BUILD_DATE" | aws s3 cp - \
            "s3://$S3_BUCKET/$S3_PREFIX/builds/latest.txt" \
            --content-type text/plain

      - name: Find previous build
        if: steps.meta.outputs.skip != 'true' && inputs.skip_patch != true
        id: prev
        env:
          CURRENT: ${{ steps.meta.outputs.date }}
        run: |
          PREV=$(aws s3 ls "s3://$S3_BUCKET/$S3_PREFIX/builds/" \
            | grep 'PRE' | awk '{print $2}' | tr -d '/' \
            | grep -E '^[0-9]{4}-[0-9]{2}-[0-9]{2}$' \
            | sort | grep -B1 "^$CURRENT$" | head -1)

          if [ -n "$PREV" ] && [ "$PREV" != "$CURRENT" ]; then
            echo "date=$PREV" >> "$GITHUB_OUTPUT"
            echo "found=true" >> "$GITHUB_OUTPUT"
            echo "Previous build: $PREV"
          else
            echo "found=false" >> "$GITHUB_OUTPUT"
            echo "No previous build found — will verify via second build"
          fi

      - name: Bootstrap validation (no previous build)
        if: steps.prev.outputs.found != 'true' && steps.meta.outputs.skip != 'true' && inputs.skip_patch != true
        env:
          WORKDIR: ${{ steps.pbf.outputs.workdir }}
        run: |
          echo "No previous build — building again to validate determinism + patch pipeline"
          echo "Downloading today's PBF again..."

          # Re-download the PBF we already uploaded
          aws s3 cp "s3://$S3_BUCKET/$S3_PREFIX/pbf/planet-current.osm.pbf" \
            "$WORKDIR/planet-verify.osm.pbf" --no-progress --only-show-errors

          time build-index "$WORKDIR/output2/" "$WORKDIR/planet-verify.osm.pbf" \
            --simplify-epsilon --epsilon-scale 1 \
            --continents --multi-output --multi-quality 2>&1 | tail -5
          rm -f "$WORKDIR/planet-verify.osm.pbf"

          echo ""
          echo "=== Comparing builds ==="
          FAIL=0
          while IFS= read -r f; do
            rel="${f#$WORKDIR/output/}"
            if ! cmp -s "$f" "$WORKDIR/output2/$rel"; then
              echo "::error::Bootstrap MISMATCH: $rel"
              FAIL=1
            fi
          done < <(find "$WORKDIR/output" -name "*.bin")
          rm -rf "$WORKDIR/output2"

          if [ $FAIL -ne 0 ]; then
            echo "::error::Bootstrap determinism check FAILED"
            exit 1
          fi
          echo "Bootstrap determinism: PASS (two identical builds)"

          # Also verify identity patch round-trip on planet variant
          echo ""
          echo "=== Verifying patch pipeline (identity) ==="
          DIR="$WORKDIR/output/planet"
          if [ -d "$DIR" ]; then
            geocoder-diff "$DIR" "$DIR" -o "$WORKDIR/test.gcpatch" 2>/dev/null
            mkdir -p "$WORKDIR/verify"
            geocoder-patch "$DIR" "$WORKDIR/test.gcpatch" -o "$WORKDIR/verify/" 2>/dev/null
            for f in "$DIR"/*.bin; do
              b=$(basename "$f")
              if ! cmp -s "$WORKDIR/verify/$b" "$DIR/$b"; then
                echo "::error::Identity patch MISMATCH: $b"
                FAIL=1
              fi
            done
            rm -rf "$WORKDIR/verify" "$WORKDIR/test.gcpatch"
            [ $FAIL -eq 0 ] && echo "Identity patch: PASS" || exit 1
          fi

      - name: Generate and verify patches for all variants
        if: steps.prev.outputs.found == 'true'
        env:
          WORKDIR: ${{ steps.pbf.outputs.workdir }}
          PREV: ${{ steps.prev.outputs.date }}
          CURRENT: ${{ steps.meta.outputs.date }}
        run: |
          S3_PREV_BASE="s3://$S3_BUCKET/$S3_PREFIX/builds/$PREV"

          echo "## Patch Generation ($PREV → $CURRENT)" >> "$GITHUB_STEP_SUMMARY"
          echo "" >> "$GITHUB_STEP_SUMMARY"
          echo "| Variant | Files | Patch Size | Verified |" >> "$GITHUB_STEP_SUMMARY"
          echo "|---------|-------|-----------|----------|" >> "$GITHUB_STEP_SUMMARY"

          PASS=0; FAIL=0; SKIP=0

          VARIANTS=$(cd "$WORKDIR/output" && find . -name "*.bin" -exec dirname {} \; | sort -u | sed 's|^\./||')

          for variant in $VARIANTS; do
            NEW_DIR="$WORKDIR/output/$variant"
            N_NEW=$(ls "$NEW_DIR"/*.bin 2>/dev/null | wc -l)
            [ "$N_NEW" -lt 2 ] && continue

            PREV_DIR="$WORKDIR/prev-variant"
            rm -rf "$PREV_DIR"; mkdir -p "$PREV_DIR"
            aws s3 sync "$S3_PREV_BASE/$variant/" "$PREV_DIR/" \
              --no-progress --only-show-errors 2>/dev/null

            N_PREV=$(ls "$PREV_DIR"/*.bin 2>/dev/null | wc -l)
            if [ "$N_PREV" -ne "$N_NEW" ]; then
              SKIP=$((SKIP + 1))
              continue
            fi

            PATCH_FILE="$WORKDIR/current-patch.gcpatch"
            geocoder-diff "$PREV_DIR" "$NEW_DIR" -o "$PATCH_FILE" 2>/dev/null
            PATCH_SIZE=$(stat -c%s "$PATCH_FILE" 2>/dev/null || echo 0)
            PATCH_KB=$((PATCH_SIZE / 1024))

            VERIFY_DIR="$WORKDIR/verify-variant"
            rm -rf "$VERIFY_DIR"; mkdir -p "$VERIFY_DIR"
            geocoder-patch "$PREV_DIR" "$PATCH_FILE" -o "$VERIFY_DIR" 2>/dev/null

            MATCH=0
            for f in "$NEW_DIR"/*.bin; do
              b=$(basename "$f")
              h1=$(md5sum "$VERIFY_DIR/$b" 2>/dev/null | awk '{print $1}')
              h2=$(md5sum "$NEW_DIR/$b" | awk '{print $1}')
              [ "$h1" = "$h2" ] && MATCH=$((MATCH + 1))
            done

            if [ $MATCH -eq $N_NEW ]; then
              echo "  $variant: PASS ($MATCH/$N_NEW, ${PATCH_KB} KiB)"
              echo "| $variant | $N_NEW | ${PATCH_KB} KiB | PASS |" >> "$GITHUB_STEP_SUMMARY"
              PASS=$((PASS + 1))

              aws s3 cp "$PATCH_FILE" \
                "s3://$S3_BUCKET/$S3_PREFIX/patches/$variant/${PREV}-to-${CURRENT}.gcpatch" \
                --no-progress --only-show-errors
            else
              echo "::error::$variant: FAIL ($MATCH/$N_NEW match)"
              echo "| $variant | $N_NEW | ${PATCH_KB} KiB | **FAIL** |" >> "$GITHUB_STEP_SUMMARY"
              FAIL=$((FAIL + 1))
            fi

            rm -f "$PATCH_FILE"
            rm -rf "$VERIFY_DIR" "$PREV_DIR"
          done

          echo ""
          echo "Results: $PASS pass, $FAIL fail, $SKIP skip"
          echo "" >> "$GITHUB_STEP_SUMMARY"
          echo "**Total: $PASS pass, $FAIL fail, $SKIP skip**" >> "$GITHUB_STEP_SUMMARY"

          [ $FAIL -gt 0 ] && exit 1 || true

      - name: Clean up old builds (keep last 2)
        if: steps.meta.outputs.skip != 'true'
        run: |
          BUILDS=$(aws s3 ls "s3://$S3_BUCKET/$S3_PREFIX/builds/" \
            | grep 'PRE' | awk '{print $2}' | tr -d '/' \
            | grep -E '^[0-9]{4}-[0-9]{2}-[0-9]{2}$' \
            | sort -r)

          COUNT=0
          while IFS= read -r build; do
            COUNT=$((COUNT + 1))
            if [ $COUNT -gt 2 ]; then
              echo "Deleting old build: $build"
              aws s3 rm "s3://$S3_BUCKET/$S3_PREFIX/builds/$build/" --recursive \
                --no-progress --only-show-errors
            fi
          done <<< "$BUILDS"

      - name: Update index.json
        if: steps.meta.outputs.skip != 'true'
        env:
          BUILD_DATE: ${{ steps.meta.outputs.date }}
        run: |

          BUILDS_JSON=$(aws s3 ls "s3://$S3_BUCKET/$S3_PREFIX/builds/" \
            | grep 'PRE' | awk '{print $2}' | tr -d '/' \
            | grep -E '^[0-9]{4}-[0-9]{2}-[0-9]{2}$' \
            | sort -r \
            | while read -r b; do
                REGIONS_LIST=$(aws s3 ls "s3://$S3_BUCKET/$S3_PREFIX/builds/$b/" \
                  | grep 'PRE' | awk '{print $2}' | tr -d '/' \
                  | jq -R . | jq -s .)
                echo "{\"date\":\"$b\",\"regions\":$REGIONS_LIST}"
              done | jq -s .)

          PATCHES_JSON=$(for region in $REGIONS; do
            REGION_PATCHES=$(aws s3 ls "s3://$S3_BUCKET/$S3_PREFIX/patches/$region/" 2>/dev/null \
              | awk '{print $4}' | grep '\.gcpatch$' | sort -r \
              | while read -r p; do
                  SIZE=$(aws s3 ls "s3://$S3_BUCKET/$S3_PREFIX/patches/$region/$p" | awk '{print $3}')
                  FROM=$(echo "$p" | sed 's/\(.*\)-to-.*/\1/')
                  TO=$(echo "$p" | sed 's/.*-to-\(.*\)\.gcpatch/\1/')
                  echo "{\"from\":\"$FROM\",\"to\":\"$TO\",\"file\":\"patches/$region/$p\",\"bytes\":${SIZE:-0}}"
                done | jq -s .)
            [ "$REGION_PATCHES" = "null" ] && REGION_PATCHES="[]"
            echo "{\"region\":\"$region\",\"patches\":$REGION_PATCHES}"
          done | jq -s .)

          jq -n \
            --arg updated "$(date -u +%Y-%m-%dT%H:%M:%SZ)" \
            --arg latest "$BUILD_DATE" \
            --argjson builds "$BUILDS_JSON" \
            --argjson patches "$PATCHES_JSON" \
            '{
              updated: $updated,
              latest_build: $latest,
              builds: $builds,
              patches: $patches
            }' > /tmp/index.json

          aws s3 cp /tmp/index.json \
            "s3://$S3_BUCKET/$S3_PREFIX/index.json" \
            --content-type application/json \
            --no-progress --only-show-errors

      - name: Summary
        if: always()
        env:
          BUILD_DATE: ${{ steps.meta.outputs.date }}
          PBF_METHOD: ${{ steps.pbf.outputs.method || 'skipped' }}
          WAS_SKIPPED: ${{ steps.meta.outputs.skip }}
        run: |
          echo "" >> "$GITHUB_STEP_SUMMARY"
          echo "## Build Info" >> "$GITHUB_STEP_SUMMARY"
          echo "" >> "$GITHUB_STEP_SUMMARY"
          echo "| | |" >> "$GITHUB_STEP_SUMMARY"
          echo "|---|---|" >> "$GITHUB_STEP_SUMMARY"
          echo "| **Date** | $BUILD_DATE |" >> "$GITHUB_STEP_SUMMARY"
          echo "| **PBF method** | $PBF_METHOD |" >> "$GITHUB_STEP_SUMMARY"
          if [ "$WAS_SKIPPED" = "true" ]; then
            echo "| **Status** | Skipped (already exists) |" >> "$GITHUB_STEP_SUMMARY"
          else
            echo "| **Status** | Built and uploaded |" >> "$GITHUB_STEP_SUMMARY"
          fi
