name: Build and Release to F-Droid

on:
  push:
    tags:
      - '*'
  workflow_dispatch:

jobs:
  ci:
    runs-on: docker
    env:
      ANDROID_HOME: /opt/android-sdk
      ANDROID_SDK_ROOT: /opt/android-sdk
    steps:
      - name: Checkout
        uses: actions/checkout@v4

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

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

      - name: Install Android SDK packages
        run: |
          sdkmanager --licenses >/dev/null <<'EOF'
          y
          y
          y
          y
          y
          y
          y
          y
          y
          y
          EOF
          sdkmanager "platform-tools" "platforms;android-36" "build-tools;36.0.0"

      - name: Install jq
        run: |
          set -e
          SUDO=""
          if command -v sudo >/dev/null 2>&1; then
            SUDO="sudo"
          fi
          if command -v apt-get >/dev/null 2>&1; then
            $SUDO apt-get update
            $SUDO apt-get install -y jq
          elif command -v apk >/dev/null 2>&1; then
            $SUDO apk add --no-cache jq
          elif command -v dnf >/dev/null 2>&1; then
            $SUDO dnf install -y jq
          elif command -v yum >/dev/null 2>&1; then
            $SUDO yum install -y jq
          else
            echo "Could not find a supported package manager to install jq"
            exit 1
          fi

      - name: Setup Flutter
        uses: subosito/flutter-action@v2
        with:
          channel: 'stable'

      - name: Trust Flutter SDK git directory
        run: |
          set -e
          FLUTTER_BIN_DIR="$(dirname "$(command -v flutter)")"
          FLUTTER_SDK_DIR="$(cd "$FLUTTER_BIN_DIR/.." && pwd -P)"
          git config --global --add safe.directory "$FLUTTER_SDK_DIR"
          if [ -n "${FLUTTER_ROOT:-}" ]; then
            git config --global --add safe.directory "$FLUTTER_ROOT"
          fi
          git config --global --add safe.directory /opt/hostedtoolcache/flutter/stable-3.41.4-x64 || true

      - name: Verify Android + Flutter toolchain
        run: flutter doctor -v

      - name: Install dependencies
        run: flutter pub get

      - name: Static analysis
        run: flutter analyze --no-pub

      - name: Run tests
        run: flutter test

      - name: Check outdated dependencies
        run: dart pub outdated
        continue-on-error: true

      - name: Trivy filesystem scan
        run: |
          set -e
          SUDO=""
          if command -v sudo >/dev/null 2>&1; then
            SUDO="sudo"
          fi
          if command -v apt-get >/dev/null 2>&1; then
            $SUDO apt-get update
            $SUDO apt-get install -y wget apt-transport-https gnupg lsb-release
            wget -qO - https://aquasecurity.github.io/trivy-repo/deb/public.key | gpg --dearmor | $SUDO tee /usr/share/keyrings/trivy.gpg > /dev/null
            echo "deb [signed-by=/usr/share/keyrings/trivy.gpg] https://aquasecurity.github.io/trivy-repo/deb generic main" | $SUDO tee /etc/apt/sources.list.d/trivy.list
            $SUDO apt-get update
            $SUDO apt-get install -y trivy
          elif command -v apk >/dev/null 2>&1; then
            $SUDO apk add --no-cache trivy || (wget -qO trivy.tar.gz https://github.com/aquasecurity/trivy/releases/latest/download/trivy_0.62.1_Linux-64bit.tar.gz && tar xzf trivy.tar.gz trivy && $SUDO mv trivy /usr/local/bin/)
          fi
          trivy filesystem --severity HIGH,CRITICAL --exit-code 0 .
        continue-on-error: true

      - name: Build debug APK
        run: flutter build apk --debug

  build-and-deploy:
    needs: ci
    runs-on: docker
    env:
      ANDROID_HOME: /opt/android-sdk
      ANDROID_SDK_ROOT: /opt/android-sdk
    steps:
      - name: Checkout
        uses: actions/checkout@v4

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

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

      - name: Install Android SDK packages
        run: |
          sdkmanager --licenses >/dev/null <<'EOF'
          y
          y
          y
          y
          y
          y
          y
          y
          y
          y
          EOF
          sdkmanager "platform-tools" "platforms;android-36" "build-tools;36.0.0"

      - name: Install jq
        run: |
          set -e
          SUDO=""
          if command -v sudo >/dev/null 2>&1; then
            SUDO="sudo"
          fi

          if command -v apt-get >/dev/null 2>&1; then
            $SUDO apt-get update
            $SUDO apt-get install -y jq
          elif command -v apk >/dev/null 2>&1; then
            $SUDO apk add --no-cache jq
          elif command -v dnf >/dev/null 2>&1; then
            $SUDO dnf install -y jq
          elif command -v yum >/dev/null 2>&1; then
            $SUDO yum install -y jq
          else
            echo "Could not find a supported package manager to install jq"
            exit 1
          fi

      - name: Setup Flutter
        uses: subosito/flutter-action@v2
        with:
          channel: 'stable'

      - name: Trust Flutter SDK git directory
        run: |
          set -e
          FLUTTER_BIN_DIR="$(dirname "$(command -v flutter)")"
          FLUTTER_SDK_DIR="$(cd "$FLUTTER_BIN_DIR/.." && pwd -P)"
          git config --global --add safe.directory "$FLUTTER_SDK_DIR"
          if [ -n "${FLUTTER_ROOT:-}" ]; then
            git config --global --add safe.directory "$FLUTTER_ROOT"
          fi
          # Runner-specific fallback observed in failing logs
          git config --global --add safe.directory /opt/hostedtoolcache/flutter/stable-3.41.4-x64 || true

      - name: Verify Android + Flutter toolchain
        run: flutter doctor -v

      - name: Install dependencies
        run: flutter pub get

      - name: Set version from git tag
        run: |
          set -e                                                                                                                                            
          RAW_TAG="${GITHUB_REF_NAME:-${GITHUB_REF##*/}}"                                                                                                   
          
          # Strip leading 'v' if present (v1.2.3 -> 1.2.3)                                                                                                  
          VERSION="${RAW_TAG#v}"                                                                                                                            
          
          # Extract a numeric build number for versionCode.                                                                                                 
          # Converts semver x.y.z into a single integer: x*10000 + y*100 + z                                                                                
          # e.g. 1.1.1 -> 10101, 2.3.15 -> 20315                                                                                                            
          MAJOR=$(echo "$VERSION" | cut -d. -f1)                                                                                                            
          MINOR=$(echo "$VERSION" | cut -d. -f2)                                                                                                            
          PATCH=$(echo "$VERSION" | cut -d. -f3)                                                                                                            
          MAJOR=${MAJOR:-0}; MINOR=${MINOR:-0}; PATCH=${PATCH:-0}                                                                                           
          VERSION_CODE=$(( MAJOR * 10000 + MINOR * 100 + PATCH ))                                                                                           
          
          echo "Version: $VERSION, VersionCode: $VERSION_CODE"                                                                                              
          
          # Update pubspec.yaml: replace the version line                                                                                                   
          sed -i "s/^version: .*/version: ${VERSION}+${VERSION_CODE}/" pubspec.yaml
          
          grep '^version:' pubspec.yaml

      # ADD THIS NEW STEP
      - name: Setup Android Keystore
        env:
          KEYSTORE_BASE64: ${{ secrets.KEYSTORE_BASE64 }}
          KEY_PASSWORD: ${{ secrets.KEY_PASSWORD }}
          KEY_ALIAS: ${{ secrets.KEY_ALIAS }}
        run: |
          # Decode the base64 string back into the binary .jks file
          echo "$KEYSTORE_BASE64" | base64 --decode > android/app/upload-keystore.jks
          
          # Create the key.properties file that build.gradle expects
          echo "storePassword=$KEY_PASSWORD" > android/key.properties
          echo "keyPassword=$KEY_PASSWORD" >> android/key.properties
          echo "keyAlias=$KEY_ALIAS" >> android/key.properties
          echo "storeFile=upload-keystore.jks" >> android/key.properties

      - name: Build APK
        run: flutter build apk --release

      - name: Setup F-Droid Server Tools
        run: |
          SUDO=""
          if command -v sudo >/dev/null 2>&1; then
            SUDO="sudo"
          fi
          $SUDO apt-get update
          # sshpass from apt, fdroidserver via pip to get a newer androguard that
          # can parse modern Flutter/AGP APKs (apt ships fdroidserver 2.2.1 which crashes)
          $SUDO apt-get install -y sshpass python3-pip
          pip3 install --break-system-packages --upgrade fdroidserver

      - name: Initialize or fetch F-Droid Repository
        env:
          HOST: ${{ secrets.HETZNER_HOST }}
          USER: ${{ secrets.HETZNER_USER }}
          PASS: ${{ secrets.HETZNER_PASS }}
        run: |
          mkdir -p fdroid

          # Ensure remote path exists (sftp mkdir, ignoring errors if already present).
          sshpass -p "$PASS" sftp -o StrictHostKeyChecking=no "$USER@$HOST" <<'SFTP'
          -mkdir dev
          -mkdir dev/fdroid
          -mkdir dev/fdroid/repo
          SFTP

          # Try to download the entire fdroid/ directory from Hetzner to keep
          # older APKs, the repo keystore, and config.yml across runs.
          # If it fails (first time), initialize a new local repo.
          sshpass -p "$PASS" scp -o StrictHostKeyChecking=no -r "$USER@$HOST:dev/fdroid/." fdroid/ || (cd fdroid && fdroid init)

      - name: Ensure F-Droid repo signing key and icon
        run: |
          cd fdroid

          # Ensure repo icon exists (use app launcher icon)
          mkdir -p repo/icons
          if [ ! -f repo/icons/icon.png ]; then
            cp ../android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png repo/icons/icon.png
          fi

          # If keystore doesn't exist, create the signing key.
          # This only runs on the very first deployment; subsequent runs
          # download the keystore from Hetzner via the scp step above.
          if [ ! -f keystore.p12 ]; then
            fdroid update --create-key
          fi

      - name: Copy new APK to repo
        run: |
          set -e
          mkdir -p fdroid/repo

          # Prefer tag name for release builds; fallback to ref name for manual runs.
          REF_NAME="${GITHUB_REF_NAME:-${GITHUB_REF##*/}}"
          SAFE_REF_NAME="$(echo "$REF_NAME" | tr '/ ' '__' | tr -cd '[:alnum:]_.-')"
          if [ -z "$SAFE_REF_NAME" ]; then
            SAFE_REF_NAME="${GITHUB_SHA:-manual}"
          fi

          cp build/app/outputs/flutter-apk/app-release.apk "fdroid/repo/my_flutter_app_${SAFE_REF_NAME}.apk"

      - name: Copy metadata to F-Droid repo
        run: |
          cp -r fdroid-metadata/* fdroid/metadata/

      - name: Generate F-Droid Index
        run: |
          cd fdroid
          fdroid update -c

      - name: Upload Repo to Hetzner
        env:
          HOST: ${{ secrets.HETZNER_HOST }}
          USER: ${{ secrets.HETZNER_USER }}
          PASS: ${{ secrets.HETZNER_PASS }}
        run: |
          set -euo pipefail
          SSH_OPTS="-o StrictHostKeyChecking=no -o ConnectTimeout=20"

          # Create remote directory tree via SFTP batch (no exec channel needed).
          # Leading '-' on each mkdir means "ignore error if already exists".
          sshpass -p "$PASS" sftp $SSH_OPTS "$USER@$HOST" <<'SFTP'
          -mkdir dev
          -mkdir dev/fdroid
          -mkdir dev/fdroid/repo
          SFTP

          # Upload the entire fdroid/ directory (repo + keystore + config)
          # so the signing key persists across runs.
          sshpass -p "$PASS" scp $SSH_OPTS -r fdroid/. "$USER@$HOST:dev/fdroid/"
