# Android native E2E tests
name: E2E Tests - Android

on:
  push:
    branches: [ "main" ]
    paths:
      - 'apps/mobile-app/**'
      - 'core/**'
      - '.github/workflows/e2e-tests-android.yml'
  pull_request:
    branches: [ "main" ]
    paths:
      - 'apps/mobile-app/**'
      - 'core/**'
      - '.github/workflows/e2e-tests-android.yml'
  workflow_dispatch:

concurrency:
  group: ${{ github.workflow }}-${{ github.ref }}
  cancel-in-progress: true

jobs:
  android-e2e-tests:
    if: false  # Temporarily disabled - will re-test in separate PR
    timeout-minutes: 60
    runs-on: ubuntu-latest
    defaults:
      run:
        working-directory: apps/mobile-app

    steps:
      - name: Free disk space
        uses: jlumbroso/free-disk-space@v1.3.1
        with:
          tool-cache: false
          android: false  # Keep Android SDK
          dotnet: false   # Keep .NET (we need it)
          haskell: true
          large-packages: true
          docker-images: true
          swap-storage: true

      - name: Checkout repository
        uses: actions/checkout@v6

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

      - 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: Setup .NET
        uses: actions/setup-dotnet@v5
        with:
          dotnet-version: 9.0.x

      - name: Setup Rust toolchain
        uses: dtolnay/rust-toolchain@stable
        with:
          targets: aarch64-linux-android,armv7-linux-androideabi,x86_64-linux-android,i686-linux-android

      - name: Cache Rust dependencies
        uses: Swatinem/rust-cache@v2
        with:
          workspaces: core/rust

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

      - name: Accept Android licenses
        run: yes | sdkmanager --licenses || true

      - name: Install Android NDK
        run: sdkmanager --install "ndk;26.1.10909125"

      - name: Build core libraries for Android
        run: |
          cd ../../core
          chmod +x build-and-distribute.sh
          ./build-and-distribute.sh --android

      - name: Verify core library distribution
        run: |
          TARGET_DIRS=(
            "utils/dist/core/identity-generator"
            "utils/dist/core/models"
            "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 "Core library distribution verified"

      - name: Install mobile app dependencies
        run: npm ci

      - name: Build API server
        working-directory: apps/server
        run: dotnet build AliasVault.Api

      - name: Start PostgreSQL
        run: |
          sudo systemctl start postgresql
          sudo -u postgres createuser -s aliasvault || true
          sudo -u postgres psql -c "ALTER USER aliasvault WITH PASSWORD 'password';" || true
          sudo -u postgres createdb -O aliasvault aliasdb_e2e_android || true

      - name: Start API server
        working-directory: apps/server/AliasVault.Api
        run: |
          dotnet run --no-build > /tmp/api-server.log 2>&1 &
          # Wait for API to be ready
          echo "Waiting for API to start..."
          for i in {1..30}; do
            if curl -s http://localhost:5100/v1/ > /dev/null 2>&1; then
              echo "API is ready!"
              break
            fi
            echo "Attempt $i: API not ready yet..."
            sleep 2
          done
        env:
          ConnectionStrings__AliasServerDbContext: "Host=localhost;Port=5432;Database=aliasdb_e2e_android;Username=aliasvault;Password=password"
          JWT_KEY: "12345678901234567890123456789012"
          DATA_PROTECTION_CERT_PASS: "Development"
          PUBLIC_REGISTRATION_ENABLED: "true"
          ADMIN_PASSWORD_HASH: "AQAAAAIAAYagAAAAEKWfKfa2gh9Z72vjAlnNP1xlME7FsunRznzyrfqFte40FToufRwa3kX8wwDwnEXZag=="
          ADMIN_PASSWORD_GENERATED: "2024-01-01T00:00:00Z"
          # Bind to all interfaces (IPv4 and IPv6)
          ASPNETCORE_URLS: "http://0.0.0.0:5100"

      - name: Enable KVM
        run: |
          echo 'KERNEL=="kvm", GROUP="kvm", MODE="0666", OPTIONS+="static_node=kvm"' | sudo tee /etc/udev/rules.d/99-kvm4all.rules
          sudo udevadm control --reload-rules
          sudo udevadm trigger --name-match=kvm

      - name: Cache AVD
        uses: actions/cache@v5
        id: avd-cache
        with:
          path: |
            ~/.android/avd/*
            ~/.android/adb*
          key: avd-api-34-x86_64-${{ runner.os }}

      - name: Create AVD and generate snapshot for caching
        if: steps.avd-cache.outputs.cache-hit != 'true'
        uses: reactivecircus/android-emulator-runner@v2
        with:
          api-level: 34
          arch: x86_64
          target: google_apis
          force-avd-creation: false
          emulator-options: -no-window -gpu swiftshader_indirect -noaudio -no-boot-anim -camera-back none
          disable-animations: true
          script: echo "Generated AVD snapshot for caching."

      - name: Start Metro bundler
        run: |
          # Start Metro bundler in background (non-interactive mode for CI)
          npx expo start --offline > /tmp/metro.log 2>&1 &
          METRO_PID=$!
          echo $METRO_PID > /tmp/metro.pid

          # Wait for Metro to be ready
          echo "Waiting for Metro bundler to start..."
          for i in {1..30}; do
            if curl -s http://localhost:8081/status 2>/dev/null | grep -q "packager-status:running"; then
              echo "Metro bundler is ready!"
              break
            fi
            echo "Attempt $i: Metro not ready yet..."
            # Show recent log for debugging
            tail -3 /tmp/metro.log 2>/dev/null || true
            sleep 2
          done

      - name: Build and Run Android E2E Tests
        uses: reactivecircus/android-emulator-runner@v2
        with:
          api-level: 34
          arch: x86_64
          target: google_apis
          force-avd-creation: false
          emulator-options: -no-snapshot-save -no-window -gpu swiftshader_indirect -noaudio -no-boot-anim -camera-back none
          disable-animations: true
          working-directory: apps/mobile-app/android
          script: |
            # Wait for emulator to be fully booted
            adb wait-for-device
            adb shell input keyevent 82  # Unlock screen

            # Set up port forwarding so emulator can reach host's API server and Metro bundler
            adb reverse tcp:5100 tcp:5100  # API server
            adb reverse tcp:8081 tcp:8081  # Metro bundler

            # Build and install the debug APK
            ./gradlew :app:assembleDebug
            adb install -r app/build/outputs/apk/debug/app-debug.apk

            # Run the instrumented tests
            ./gradlew :app:connectedDebugAndroidTest -Pandroid.testInstrumentationRunnerArguments.API_URL=http://10.0.2.2:5100 --stacktrace
        env:
          API_URL: "http://10.0.2.2:5100"
          ANDROID_NDK_HOME: ${{ env.ANDROID_SDK_ROOT }}/ndk/26.1.10909125

      - name: Upload test results
        if: always()
        uses: actions/upload-artifact@v7
        with:
          name: android-e2e-test-results
          path: apps/mobile-app/android/app/build/reports/androidTests/
          retention-days: 14

      - name: Upload test outputs
        if: always()
        uses: actions/upload-artifact@v7
        with:
          name: android-e2e-test-outputs
          path: apps/mobile-app/android/app/build/outputs/androidTest-results/
          retention-days: 14

      - name: Upload logs on failure
        if: failure()
        uses: actions/upload-artifact@v7
        with:
          name: android-e2e-test-logs
          path: |
            /tmp/api-server.log
            /tmp/metro.log
          retention-days: 14
          if-no-files-found: ignore
