name: Build WDTT Release

on:
  push:
    branches:
      - "**"
  workflow_dispatch:

jobs:
  build-release:
    name: Build release APK
    runs-on: ubuntu-latest

    permissions:
      contents: read

    env:
      ANDROID_MIN_API: "29"
      ANDROID_COMPILE_SDK: "35"
      ANDROID_BUILD_TOOLS: "35.0.0"
      ANDROID_NDK_VERSION: "27.2.12479018"
      SERVER_BINARY_NAME: "server"

    steps:
      - name: Checkout repository
        uses: actions/checkout@v4

      - name: Set up Java 17
        uses: actions/setup-java@v4
        with:
          distribution: temurin
          java-version: "17"

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

      - name: Install Android SDK packages
        shell: bash
        run: |
          set -euo pipefail

          sdkmanager \
            "platforms;android-${ANDROID_COMPILE_SDK}" \
            "build-tools;${ANDROID_BUILD_TOOLS}" \
            "ndk;${ANDROID_NDK_VERSION}"

          echo "ANDROID_NDK_HOME=${ANDROID_SDK_ROOT}/ndk/${ANDROID_NDK_VERSION}" >> "$GITHUB_ENV"

      - name: Set up Go
        uses: actions/setup-go@v5
        with:
          go-version: "1.26.x"
          cache: true
          cache-dependency-path: |
            go.mod
            go_client/go.mod

      - name: Generate Go sums
        shell: bash
        run: |
          set -euo pipefail

          echo "== Root Go module =="
          go mod tidy

          echo "== Go client module =="
          cd go_client
          go mod tidy

      - name: Build Linux server binaries
        shell: bash
        run: |
          set -euo pipefail

          mkdir -p build/server

          echo "== Build server linux/amd64 =="
          CGO_ENABLED=0 GOOS=linux GOARCH=amd64 \
            go build \
              -trimpath \
              -ldflags="-s -w -checklinkname=0" \
              -o build/server/wdtt-server-linux-amd64 \
              ./server.go

          echo "== Build server linux/arm64 =="
          CGO_ENABLED=0 GOOS=linux GOARCH=arm64 \
            go build \
              -trimpath \
              -ldflags="-s -w -checklinkname=0" \
              -o build/server/wdtt-server-linux-arm64 \
              ./server.go

          chmod +x build/server/wdtt-server-linux-amd64
          chmod +x build/server/wdtt-server-linux-arm64

      - name: Put server binary into Android assets
        shell: bash
        run: |
          set -euo pipefail

          mkdir -p app/src/main/assets

          # Android deploy code expects this exact asset name.
          cp build/server/wdtt-server-linux-amd64 app/src/main/assets/${SERVER_BINARY_NAME}
          chmod +x app/src/main/assets/${SERVER_BINARY_NAME}

          echo "Server asset:"
          ls -lh app/src/main/assets/${SERVER_BINARY_NAME}

      - name: Build Android Go client libraries
        shell: bash
        run: |
          set -euo pipefail

          NDK_ROOT="${ANDROID_NDK_HOME}"
          TOOLCHAIN="$NDK_ROOT/toolchains/llvm/prebuilt/linux-x86_64/bin"

          if [ ! -d "$TOOLCHAIN" ]; then
            echo "Android NDK toolchain not found: $TOOLCHAIN"
            exit 1
          fi

          echo "Using NDK: $NDK_ROOT"
          echo "Using toolchain: $TOOLCHAIN"

          mkdir -p app/src/main/jniLibs/arm64-v8a
          mkdir -p app/src/main/jniLibs/armeabi-v7a
          mkdir -p app/src/main/jniLibs/x86_64
          mkdir -p build/go-client

          cd go_client

          echo "== Build libclient.so for arm64-v8a =="
          CGO_ENABLED=1 \
          GOOS=android \
          GOARCH=arm64 \
          CC="$TOOLCHAIN/aarch64-linux-android${ANDROID_MIN_API}-clang" \
            go build \
              -buildmode=c-shared \
              -trimpath \
              -ldflags="-s -w -checklinkname=0" \
              -o ../app/src/main/jniLibs/arm64-v8a/libclient.so \
              .

          cp ../app/src/main/jniLibs/arm64-v8a/libclient.so \
             ../build/go-client/libclient-arm64-v8a.so

          echo "== Build libclient.so for armeabi-v7a =="
          CGO_ENABLED=1 \
          GOOS=android \
          GOARCH=arm \
          GOARM=7 \
          CC="$TOOLCHAIN/armv7a-linux-androideabi${ANDROID_MIN_API}-clang" \
            go build \
              -buildmode=c-shared \
              -trimpath \
              -ldflags="-s -w -checklinkname=0" \
              -o ../app/src/main/jniLibs/armeabi-v7a/libclient.so \
              .

          cp ../app/src/main/jniLibs/armeabi-v7a/libclient.so \
             ../build/go-client/libclient-armeabi-v7a.so

          echo "== Build libclient.so for x86_64 =="
          CGO_ENABLED=1 \
          GOOS=android \
          GOARCH=amd64 \
          CC="$TOOLCHAIN/x86_64-linux-android${ANDROID_MIN_API}-clang" \
            go build \
              -buildmode=c-shared \
              -trimpath \
              -ldflags="-s -w -checklinkname=0" \
              -o ../app/src/main/jniLibs/x86_64/libclient.so \
              .

          cp ../app/src/main/jniLibs/x86_64/libclient.so \
             ../build/go-client/libclient-x86_64.so

          cd ..

          echo "Built JNI libraries:"
          find app/src/main/jniLibs -type f -name "libclient.so" -exec ls -lh {} \;

      - name: Make Gradle wrapper executable
        shell: bash
        run: chmod +x ./gradlew

      - name: Generate temporary release keystore
        shell: bash
        run: |
          set -euo pipefail

          KEYSTORE_PASSWORD="wdtt_temp_release_password"
          KEY_PASSWORD="$KEYSTORE_PASSWORD"
          KEY_ALIAS="wdtt-release"

          rm -f release.keystore local.properties signing.env

          keytool -genkeypair             -v             -keystore release.keystore             -storetype PKCS12             -storepass "$KEYSTORE_PASSWORD"             -keypass "$KEY_PASSWORD"             -alias "$KEY_ALIAS"             -keyalg RSA             -keysize 4096             -validity 10000             -dname "CN=WDTT,O=WDTT,C=LV"

          {
            echo "KEYSTORE_PASSWORD=$KEYSTORE_PASSWORD"
            echo "KEY_PASSWORD=$KEY_PASSWORD"
            echo "KEY_ALIAS=$KEY_ALIAS"
          } > signing.env

          echo "Generated temporary release keystore"
          ls -lh release.keystore

      - name: Build Android release APK
        shell: bash
        run: |
          set -euo pipefail

          # No local.properties is created here, so Gradle produces unsigned release APKs.
          # The workflow signs them manually in the next step using apksigner.
          ./gradlew clean :app:assembleRelease --stacktrace

      - name: Sign release APKs manually
        shell: bash
        run: |
          set -euo pipefail

          source signing.env

          BUILD_TOOLS="$(find "$ANDROID_HOME/build-tools" -mindepth 1 -maxdepth 1 -type d | sort -V | tail -n 1)"
          ZIPALIGN="$BUILD_TOOLS/zipalign"
          APKSIGNER="$BUILD_TOOLS/apksigner"

          echo "Using zipalign: $ZIPALIGN"
          echo "Using apksigner: $APKSIGNER"

          mkdir -p build/signed-apk
          shopt -s nullglob
          unsigned_apks=(app/build/outputs/apk/release/*-unsigned.apk)

          if [ ${#unsigned_apks[@]} -eq 0 ]; then
            echo "No unsigned release APKs found"
            echo "Available APK outputs:"
            find app/build/outputs/apk -type f -name "*.apk" -print || true
            exit 1
          fi

          for apk in "${unsigned_apks[@]}"; do
            name="$(basename "$apk" -unsigned.apk)"
            aligned="build/signed-apk/${name}-aligned.apk"
            signed="build/signed-apk/${name}-signed.apk"

            echo "== Align $apk =="
            "$ZIPALIGN" -p -f 4 "$apk" "$aligned"

            echo "== Sign $aligned =="
            "$APKSIGNER" sign               --ks release.keystore               --ks-key-alias "$KEY_ALIAS"               --ks-pass "pass:$KEYSTORE_PASSWORD"               --key-pass "pass:$KEY_PASSWORD"               --v1-signing-enabled true               --v2-signing-enabled true               --v3-signing-enabled true               --v4-signing-enabled false               --out "$signed"               "$aligned"

            echo "== Verify $signed =="
            "$APKSIGNER" verify               --verbose               --print-certs               "$signed"
          done

          echo "Signed APKs:"
          ls -lh build/signed-apk/*-signed.apk

      - name: Collect build outputs
        shell: bash
        run: |
          set -euo pipefail

          mkdir -p build/artifacts/apk
          mkdir -p build/artifacts/server
          mkdir -p build/artifacts/go-client

          echo "== Signed APK outputs =="
          find build/signed-apk -type f -name "*-signed.apk" -print -exec ls -lh {} \;

          cp build/signed-apk/*-signed.apk build/artifacts/apk/
          cp build/server/* build/artifacts/server/
          cp build/go-client/* build/artifacts/go-client/

          echo "== Final artifacts =="
          find build/artifacts -type f -exec ls -lh {} \;

      - name: Upload release APK artifact
        uses: actions/upload-artifact@v4
        with:
          name: WDTT-release-apk
          path: build/artifacts/apk/*.apk
          if-no-files-found: error
          retention-days: 14

      - name: Upload server binaries artifact
        uses: actions/upload-artifact@v4
        with:
          name: WDTT-server-binaries
          path: build/artifacts/server/*
          if-no-files-found: error
          retention-days: 14

      - name: Upload Go client libraries artifact
        uses: actions/upload-artifact@v4
        with:
          name: WDTT-go-client-libraries
          path: build/artifacts/go-client/*
          if-no-files-found: error
          retention-days: 14
