name: Build App

on:
  workflow_dispatch:
    inputs:
      job_id:
        description: Build job ID
        required: true
        type: string
      app_name:
        description: Application display name (Chinese)
        required: true
        type: string
      app_name_en:
        description: Application English name for packaging
        required: true
        type: string
      app_identifier:
        description: Application bundle identifier
        required: true
        type: string

permissions:
  contents: write

env:
  JOB_ID: ${{ inputs.job_id }}
  APP_NAME: ${{ inputs.app_name }}
  APP_NAME_EN: ${{ inputs.app_name_en }}
  APP_IDENTIFIER: ${{ inputs.app_identifier }}
  APP_VERSION: ${{ inputs.app_version }}
  NDK_VERSION: "27.2.12479018"
  # Faster release builds in CI; local release profile keeps full LTO.
  CI: true
  CARGO_PROFILE_RELEASE_LTO: false
  CARGO_PROFILE_RELEASE_CODEGEN_UNITS: 16

jobs:
  build-windows:
    runs-on: windows-latest
    steps:
      - uses: actions/checkout@v4

      - uses: actions/setup-node@v4
        with:
          node-version: lts/*
          cache: npm

      - name: Install dependencies
        run: npm ci --workspace=template --include-workspace-root

      - name: Prepare template
        run: node .github/scripts/prepare-template.mjs

      - uses: dtolnay/rust-toolchain@stable

      - uses: swatinem/rust-cache@v2
        with:
          workspaces: template/src-tauri -> target
          shared-key: tauri-release

      - name: Build Windows app
        working-directory: template
        run: npm run tauri build -- --bundles nsis

      - name: Collect Windows artifacts
        shell: pwsh
        run: |
          New-Item -ItemType Directory -Force -Path artifacts/windows | Out-Null
          $bundleRoot = "template/src-tauri/target/release/bundle"
          if (Test-Path $bundleRoot) {
            Get-ChildItem -Path $bundleRoot -Recurse -Include *setup.exe,*.exe,*.msi -ErrorAction SilentlyContinue |
              Copy-Item -Destination artifacts/windows -Force
          }
          Get-ChildItem -Path "template/src-tauri/target/release" -Filter "*.exe" -ErrorAction SilentlyContinue |
            Where-Object { $_.Name -notmatch "wix|candle|light" } |
            Copy-Item -Destination artifacts/windows -Force
          Get-ChildItem artifacts/windows

      - uses: actions/upload-artifact@v4
        with:
          name: windows-build
          path: artifacts/windows/*
          if-no-files-found: error

  build-android:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4

      - uses: actions/setup-node@v4
        with:
          node-version: lts/*
          cache: npm

      - name: Install dependencies
        run: npm ci --workspace=template --include-workspace-root

      - name: Prepare template
        run: node .github/scripts/prepare-template.mjs

      - uses: actions/setup-java@v4
        with:
          distribution: temurin
          java-version: 17

      - uses: android-actions/setup-android@v3

      - name: Cache Android NDK
        uses: actions/cache@v4
        id: android-ndk-cache
        with:
          path: ${{ env.ANDROID_HOME }}/ndk/${{ env.NDK_VERSION }}
          key: android-ndk-${{ env.NDK_VERSION }}-${{ runner.os }}

      - name: Cache Gradle
        uses: actions/cache@v4
        with:
          path: |
            ~/.gradle/caches
            ~/.gradle/wrapper
          key: gradle-${{ runner.os }}-${{ hashFiles('template/src-tauri/Cargo.lock', 'template/package.json') }}
          restore-keys: |
            gradle-${{ runner.os }}-

      - name: Install Android SDK components
        run: |
          sdkmanager "platforms;android-34" "build-tools;34.0.0"
          if [ "${{ steps.android-ndk-cache.outputs.cache-hit }}" != "true" ]; then
            sdkmanager "ndk;${{ env.NDK_VERSION }}"
          fi

      - uses: dtolnay/rust-toolchain@stable
        with:
          targets: aarch64-linux-android

      - uses: swatinem/rust-cache@v2
        with:
          workspaces: template/src-tauri -> target
          shared-key: tauri-release

      - name: Initialize Android project
        working-directory: template
        run: npm run tauri android init
        env:
          NDK_HOME: ${{ env.ANDROID_HOME }}/ndk/${{ env.NDK_VERSION }}

      - name: Regenerate app icons for Android
        run: node .github/scripts/generate-app-icons.mjs
        env:
          JOB_ID: ${{ inputs.job_id }}

      - name: Build Android APK
        working-directory: template
        run: npm run tauri android build -- --apk --target aarch64 --ci
        env:
          NDK_HOME: ${{ env.ANDROID_HOME }}/ndk/${{ env.NDK_VERSION }}

      - name: Sign Android APK
        run: bash .github/scripts/sign-android-apk.sh
        env:
          ANDROID_KEYSTORE_BASE64: ${{ secrets.ANDROID_KEYSTORE_BASE64 }}
          ANDROID_KEYSTORE_PASSWORD: ${{ secrets.ANDROID_KEYSTORE_PASSWORD }}
          ANDROID_KEY_PASSWORD: ${{ secrets.ANDROID_KEY_PASSWORD }}
          ANDROID_KEY_ALIAS: ${{ secrets.ANDROID_KEY_ALIAS }}

      - uses: actions/upload-artifact@v4
        with:
          name: android-build
          path: artifacts/android/*
          if-no-files-found: error

  finalize:
    needs: [build-windows, build-android]
    runs-on: ubuntu-latest
    if: always() && needs.build-windows.result == 'success' && needs.build-android.result == 'success'
    steps:
      - uses: actions/checkout@v4

      - uses: actions/download-artifact@v4
        with:
          name: windows-build
          path: release-assets/windows

      - uses: actions/download-artifact@v4
        with:
          name: android-build
          path: release-assets/android

      - name: Rename release assets
        run: |
          mkdir -p release-assets/final
          shopt -s nullglob
          for file in release-assets/windows/*; do
            base="$(basename "$file")"
            cp "$file" "release-assets/final/web2app-${{ inputs.job_id }}-windows-${base}"
          done
          for file in release-assets/android/*; do
            base="$(basename "$file")"
            cp "$file" "release-assets/final/web2app-${{ inputs.job_id }}-android-${base}"
          done
          ls -la release-assets/final

      - name: Create GitHub Release
        uses: softprops/action-gh-release@v2
        with:
          tag_name: build-${{ inputs.job_id }}
          name: Web2App ${{ inputs.app_name }} (${{ inputs.job_id }})
          body: |
            Automated build for **${{ inputs.app_name }}** (English: `${{ inputs.app_name_en }}`, version: `${{ inputs.app_version }}`, ID: `${{ inputs.app_identifier }}`).

            - Windows desktop installer/portable binary
            - Android APK (arm64-v8a, signed for sideload install)
          draft: false
          prerelease: true
          files: release-assets/final/*
        env:
          GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}

      - name: Remove uploaded site zip
        run: |
          path="builds/${{ inputs.job_id }}/site.zip"
          sha=$(gh api repos/${{ github.repository }}/contents/$path --jq .sha 2>/dev/null || true)
          if [ -n "$sha" ]; then
            gh api repos/${{ github.repository }}/contents/$path \
              -X DELETE \
              -f message="chore: cleanup build ${{ inputs.job_id }}" \
              -f sha="$sha"
          fi
        env:
          GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
