name: "Build Android App"
description: "Builds Android APK/AAB, optionally signs and uploads to GitHub Release"
inputs:
  run_tests:
    description: "Whether to run Android unit tests"
    required: false
    default: "false"
  signed:
    description: "Whether to sign the Android build"
    required: false
    default: "false"
  release_tag:
    description: "If set, upload the resulting APK to the existing GitHub Release at this tag (draft or published). Requires signed=true. Fails if no such release exists."
    required: false
    default: ""

runs:
  using: "composite"
  steps:
    - name: Setup Node.js
      uses: actions/setup-node@v6
      with:
        node-version: '24'
        cache: 'npm'
        cache-dependency-path: apps/mobile-app/package-lock.json

    - name: Build core libraries
      shell: bash
      run: |
        cd ./core
        chmod +x build-and-distribute.sh
        ./build-and-distribute.sh

    - name: Verify core library distribution
      shell: bash
      run: |
        # Verify TypeScript core libraries
        TARGET_DIRS=(
          "apps/mobile-app/utils/dist/core/identity-generator"
          "apps/mobile-app/utils/dist/core/models"
          "apps/mobile-app/utils/dist/core/vault"
        )
        for dir in "${TARGET_DIRS[@]}"; do
          if [ ! -d "$dir" ]; then
            echo "❌ Error: Directory $dir does not exist"
            exit 1
          fi
        done
        echo "✅ TypeScript core libraries verified"

        # Verify Android native libraries (Rust core)
        JNILIBS_DIR="apps/mobile-app/android/app/src/main/jniLibs"
        REQUIRED_ABIS=("arm64-v8a" "armeabi-v7a" "x86_64")

        for abi in "${REQUIRED_ABIS[@]}"; do
          lib_path="$JNILIBS_DIR/$abi/libaliasvault_core.so"
          if [ ! -f "$lib_path" ]; then
            echo "❌ Missing required native library: $lib_path"
            echo "Run: cd core/rust && ./build.sh --android"
            exit 1
          fi
        done

        echo "✅ Android native libraries verified:"
        for abi in "${REQUIRED_ABIS[@]}"; do
          ls -lh "$JNILIBS_DIR/$abi/libaliasvault_core.so" | awk '{print "  " $NF ": " $5}'
        done

        # Verify Kotlin bindings (UniFFI-generated)
        KOTLIN_BINDINGS_DIR="apps/mobile-app/android/app/src/main/java/net/aliasvault/app/rustcore/uniffi/aliasvault_core"
        if [ ! -d "$KOTLIN_BINDINGS_DIR" ]; then
          echo "❌ Missing Kotlin bindings directory: $KOTLIN_BINDINGS_DIR"
          echo "Run: cd core/rust && ./build.sh --android"
          exit 1
        fi

        if [ ! -f "$KOTLIN_BINDINGS_DIR/aliasvault_core.kt" ]; then
          echo "❌ Missing Kotlin bindings file: $KOTLIN_BINDINGS_DIR/aliasvault_core.kt"
          echo "Run: cd core/rust && ./build.sh --android"
          exit 1
        fi

        echo "✅ Kotlin bindings verified:"
        ls -lh "$KOTLIN_BINDINGS_DIR"/*.kt | awk '{print "  " $NF ": " $5}'

    - name: Install dependencies
      run: npm ci
      shell: bash
      working-directory: apps/mobile-app

    - name: Extract version
      run: |
        VERSION=$(node -p "require('./app.json').expo.version")
        echo "VERSION=$VERSION" >> $GITHUB_ENV
      shell: bash
      working-directory: apps/mobile-app

    - name: Setup Java
      uses: actions/setup-java@v5
      with:
        distribution: 'temurin'
        java-version: '17'

    - name: Setup Android SDK
      uses: android-actions/setup-android@v4

    - name: Build JS bundle (Expo)
      run: |
        mkdir -p build
        npx expo export \
          --dev \
          --output-dir ./build \
          --platform android
      shell: bash
      working-directory: apps/mobile-app

    - name: Run Android Unit Tests
      if: ${{ inputs.run_tests == 'true' }}
      run: |
        cd android
        ./gradlew :app:testDebugUnitTest --tests "net.aliasvault.app.*"
      shell: bash
      working-directory: apps/mobile-app

    - name: Upload Android Test Reports
      if: ${{ inputs.run_tests == 'true' }}
      uses: actions/upload-artifact@v7
      with:
        name: android-test-reports
        path: apps/mobile-app/android/app/build/reports/tests/testDebugUnitTest/
        retention-days: 7

    - name: Decode keystore
      if: ${{ inputs.signed == 'true' }}
      run: echo "${{ env.ANDROID_KEYSTORE_BASE64 }}" | base64 --decode > android/app/keystore.jks
      shell: bash
      working-directory: apps/mobile-app

    - name: Configure signing
      if: ${{ inputs.signed == 'true' }}
      run: |
        # Ensure file ends with newline before appending (guards against
        # a missing trailing newline breaking the first appended property).
        [ -s android/gradle.properties ] && [ "$(tail -c 1 android/gradle.properties)" != "" ] && echo "" >> android/gradle.properties
        cat >> android/gradle.properties <<EOF
        ALIASVAULT_UPLOAD_STORE_FILE=keystore.jks
        ALIASVAULT_UPLOAD_KEY_ALIAS=${{ env.ANDROID_KEY_ALIAS }}
        ALIASVAULT_UPLOAD_STORE_PASSWORD=${{ env.ANDROID_KEYSTORE_PASSWORD }}
        ALIASVAULT_UPLOAD_KEY_PASSWORD=${{ env.ANDROID_KEY_PASSWORD }}
        EOF
      shell: bash
      working-directory: apps/mobile-app

    - name: Build APK & AAB (Release only if signed)
      if: ${{ inputs.signed == 'true' }}
      run: |
        cd android
        ./gradlew bundleRelease
        ./gradlew assembleRelease
      shell: bash
      working-directory: apps/mobile-app

    - name: Rename APK and AAB files
      if: ${{ inputs.signed == 'true' }}
      run: |
        mv android/app/build/outputs/apk/release/app-release.apk android/app/build/outputs/apk/release/aliasvault-${VERSION}-android.apk
        mv android/app/build/outputs/bundle/release/app-release.aab android/app/build/outputs/bundle/release/aliasvault-${VERSION}-android.aab
      shell: bash
      working-directory: apps/mobile-app

    - name: Upload AAB as artifact
      if: ${{ inputs.signed == 'true' }}
      uses: actions/upload-artifact@v7
      with:
        name: aliasvault-${{ env.VERSION }}-android.aab
        path: apps/mobile-app/android/app/build/outputs/bundle/release/aliasvault-${{ env.VERSION }}-android.aab
        retention-days: 14

    - name: Upload APK as artifact
      if: ${{ inputs.signed == 'true' }}
      uses: actions/upload-artifact@v7
      with:
        name: aliasvault-${{ env.VERSION }}-android.apk
        path: apps/mobile-app/android/app/build/outputs/apk/release/aliasvault-${{ env.VERSION }}-android.apk
        retention-days: 14

    - name: Upload APK to release
      if: ${{ inputs.release_tag != '' && inputs.signed == 'true' }}
      shell: bash
      env:
        GH_TOKEN: ${{ env.GITHUB_TOKEN }}
        RELEASE_TAG: ${{ inputs.release_tag }}
      run: |
        if ! gh release view "$RELEASE_TAG" --repo "$GITHUB_REPOSITORY" > /dev/null 2>&1; then
          echo "❌ No release exists at tag '$RELEASE_TAG'."
          echo "Create a draft release first, e.g.:"
          echo "  gh release create $RELEASE_TAG --draft --title $RELEASE_TAG --notes ''"
          exit 1
        fi

        APK="apps/mobile-app/android/app/build/outputs/apk/release/aliasvault-${VERSION}-android.apk"
        echo "Uploading $APK to release $RELEASE_TAG..."
        gh release upload "$RELEASE_TAG" "$APK" --clobber --repo "$GITHUB_REPOSITORY"


