name: Create android Play Store APK
on:
  push:
    branches: [master, release/*, test/git-actions]
    tags:
      - v*
  workflow_dispatch:
    inputs: {}

permissions:
  contents: write

# Per-ref so rapid non-tag master pushes supersede each other (newest dev build
# wins). Groups are keyed by ref, so a master push can never cancel a `v*` tag
# release build (different ref = different group).
concurrency:
  group: build-android-${{ github.ref }}
  cancel-in-progress: true

jobs:
  build-android:
    runs-on: ubuntu-latest
    env:
      UNSPLASH_KEY: ${{ secrets.UNSPLASH_KEY }}
      UNSPLASH_CLIENT_ID: ${{ secrets.UNSPLASH_CLIENT_ID }}
    steps:
      - name: Checkout sources
        uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v6
        with:
          # Full commit/tag graph (blobless, so cheap) is needed to derive the
          # per-push dev versionCode from the last stable tag.
          fetch-depth: 0
          filter: blob:none
      - uses: actions/setup-node@48b55a011bda9f5d6aeb4c2d9c7362e8dae4041e # v6
        with:
          node-version: 22
      - name: Setup Java
        uses: actions/setup-java@1bcf9fb12cf4aa7d266a90ae39939e61372fe520 # v5
        with:
          distribution: 'temurin'
          java-version: 21
      - name: Setup Gradle
        uses: gradle/actions/setup-gradle@3f131e8634966bd73d06cc69884922b02e6faf92 # v6.2.0
      #      - name: Build with Gradle
      #        run: ./gradlew build
      - name: Setup android-sdk
        uses: android-actions/setup-android@40fd30fb8d7440372e1316f5d1809ec01dcd3699 # v4.0.1
        with:
          accept-android-sdk-licenses: true
          log-accepted-android-sdk-licenses: true #make accepting the android sdk license verbose
          packages: 'platform-tools platforms;android-36 build-tools;35.0.0'

      - name: Get npm cache directory
        id: npm-cache-dir
        run: |
          echo "dir=$(npm config get cache)" >> $GITHUB_OUTPUT
      - uses: actions/cache@55cc8345863c7cc4c66a329aec7e433d2d1c52a9 # v5
        id: npm-cache # use this to check for `cache-hit` ==> if: steps.npm-cache.outputs.cache-hit != 'true'
        with:
          path: ${{ steps.npm-cache-dir.outputs.dir }}
          key: ${{ runner.os }}-node22-${{ hashFiles('**/package-lock.json') }}
          restore-keys: |
            ${{ runner.os }}-node22-
      - name: Install npm Packages
        #  if: steps.npm-cache.outputs.cache-hit != 'true'
        run: npm i

      - name: Decode Keystore
        env:
          RELEASE_KEYSTORE_PASSWORD: ${{ secrets.DROID_KEYSTORE_PASSWORD }}
          RELEASE_KEYSTORE_ALIAS: ${{ secrets.DROID_KEYSTORE_ALIAS }}
          RELEASE_KEY_PASSWORD: ${{ secrets.DROID_KEY_PASSWORD }}
        run: |
          echo "${{ secrets.DROID_KEYSTORE_BASE_64 }}" | base64 --decode > keystore.jks

      # --- Per-push dev build (non-tag master pushes only) --------------------
      # On plain master pushes the release-signed APK is otherwise artifact-only;
      # here we stamp it with a dev versionCode and (after Build) ship it to the
      # Play `internal` track so a fresh build auto-updates on the phone. All
      # steps are gated to refs/heads/master (non-tag), so the tag/release path
      # is untouched. Nothing is committed — the versionCode is only sed'd into
      # the working copy of build.gradle at build time.
      - name: Compute dev versionCode
        id: devvc
        # Dev distribution must never redden the release-critical build; on any
        # failure the downstream gates read '' and simply skip.
        continue-on-error: true
        if: github.ref == 'refs/heads/master'
        run: node tools/android-dev-version-code.js
      - name: Apply dev versionCode
        id: applyvc
        # continue-on-error: a dev-versioning hiccup must never break the
        # release-critical build; on failure `applied` stays unset and the Play
        # upload below is skipped (the artifact build still succeeds).
        continue-on-error: true
        if: github.ref == 'refs/heads/master' && steps.devvc.outputs.skip == 'false'
        env:
          CODE: ${{ steps.devvc.outputs.code }}
        run: |
          set -euo pipefail
          sed -i -E "s/versionCode [0-9_]+/versionCode ${CODE}/" android/app/build.gradle
          grep -qE "versionCode ${CODE}( |$)" android/app/build.gradle \
            || { echo "::error::versionCode override did not apply"; exit 1; }
          grep -nE 'versionCode [0-9_]+' android/app/build.gradle
          echo "applied=true" >> "$GITHUB_OUTPUT"

      - name: Build
        run: npm run dist:android:prod
        env:
          RELEASE_KEYSTORE_PASSWORD: ${{ secrets.DROID_KEYSTORE_PASSWORD }}
          RELEASE_KEYSTORE_ALIAS: ${{ secrets.DROID_KEYSTORE_ALIAS }}
          RELEASE_KEY_PASSWORD: ${{ secrets.DROID_KEY_PASSWORD }}

      - name: DEBUG
        run: |
          ls -la android/app/build/outputs
          ls -la android/app/build/outputs/apk
          ls -la android/app/build/outputs/apk/play
          ls -la android/app/build/outputs/apk/play/release

      # APK is now signed automatically by Gradle using signingConfig

      - name: 'Upload APK files'
        uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1
        with:
          name: sup-android-release
          path: android/app/build/outputs/apk/**/*.apk

      # Ship the dev-versioned APK to the Play `internal` track (non-tag master
      # pushes only, and only when the versionCode was actually applied). This is
      # the same track the tag build stages real releases on below; dev builds
      # (code base+1..999) and releases (base+9000) stay distinct by versionCode,
      # so they interleave on the track without colliding. Chosen over a closed
      # track because internal testing skips review, so builds land in minutes.
      - name: Upload dev build to Play (internal track)
        # continue-on-error: re-runs (same commit -> same versionCode, which Play
        # rejects as already used), the post-release window (a just-tagged release
        # has a higher code on this track until the tag propagates to the dev
        # step — closed by `git push --follow-tags`), and transient Play API
        # errors must not fail the release-critical workflow.
        continue-on-error: true
        if: github.ref == 'refs/heads/master' && steps.applyvc.outputs.applied == 'true'
        uses: r0adkll/upload-google-play@e738b9dd8f2476ea806d921b64aacd24f34515a5 # v1.1.5
        with:
          serviceAccountJsonPlainText: ${{ secrets.GOOGLE_PLAY_SERVICE_ACCOUNT_JSON }}
          packageName: com.superproductivity.superproductivity
          releaseFiles: android/app/build/outputs/apk/play/release/*.apk
          releaseName: 'dev ${{ steps.devvc.outputs.code }} (${{ steps.devvc.outputs.sha }})'
          tracks: internal
          status: completed

      - name: Wait for main release to be created
        if: startsWith(github.ref, 'refs/tags/v')
        run: |
          echo "Waiting for main release to be created..."
          for i in {1..40}; do
            if gh release view ${{ github.ref_name }} --repo ${{ github.repository }} >/dev/null 2>&1; then
              echo "Release found!"
              break
            fi
            echo "Waiting for release... (attempt $i/40)"
            sleep 30
          done

          # Fail if release still doesn't exist
          if ! gh release view ${{ github.ref_name }} --repo ${{ github.repository }} >/dev/null 2>&1; then
            echo "ERROR: Release ${{ github.ref_name }} was not created after 20 minutes"
            exit 1
          fi
        env:
          GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}

      - name: Upload APK to existing GitHub Release
        if: startsWith(github.ref, 'refs/tags/v')
        run: |
          for apk in android/app/build/outputs/apk/play/release/*.apk; do
            if [ -f "$apk" ]; then
              echo "Uploading $apk to release ${{ github.ref_name }}"
              gh release upload ${{ github.ref_name }} "$apk" --repo ${{ github.repository }}
            fi
          done
        env:
          GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}

      - name: Prepare Google Play release notes
        if: startsWith(github.ref, 'refs/tags/v') && !contains(github.ref, '-')
        run: npm run release-notes:prepare-play-store

      - name: Upload to Google Play Console
        if: startsWith(github.ref, 'refs/tags/v') && !contains(github.ref, '-')
        uses: r0adkll/upload-google-play@e738b9dd8f2476ea806d921b64aacd24f34515a5 # v1.1.5
        with:
          serviceAccountJsonPlainText: ${{ secrets.GOOGLE_PLAY_SERVICE_ACCOUNT_JSON }}
          packageName: com.superproductivity.superproductivity
          releaseFiles: android/app/build/outputs/apk/play/release/*.apk
          tracks: internal
          status: completed
          inAppUpdatePriority: 2
          whatsNewDirectory: build/generated-release-notes/play-store
