
name: Build Electron App

on:
  workflow_dispatch:
    inputs:
      arch:
        description: 'Architecture to build'
        required: true
        default: 'both'
        type: choice
        options:
          - arm64
          - x64
          - both

jobs:
  build-windows:
    runs-on: windows-latest
    steps:
      - name: Checkout code
        uses: actions/checkout@v3

      - name: Setup Node.js
        uses: actions/setup-node@v3
        with:
          node-version: '22'

      - name: Install dependencies
        run: npm ci

      - name: Build Windows app
        run: npm run build:win
        env:
          GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
        
      - name: Upload Windows build
        uses: actions/upload-artifact@v4
        with:
          name: windows-installer
          path: release/**/*.exe
          retention-days: 30

  build-macos:
    runs-on: macos-latest
    strategy:
      matrix:
        arch: ${{ github.event.inputs.arch == 'both' && fromJSON('["arm64", "x64"]') || fromJSON(format('["{0}"]', github.event.inputs.arch)) }}
    
    steps:
      # ─── Checkout ─────────────────────────────────────────────
      - name: Checkout code
        uses: actions/checkout@v4

      # ─── Setup Node.js ────────────────────────────────────────
      - name: Setup Node.js
        uses: actions/setup-node@v4
        with:
          node-version: 22
          cache: npm

      # ─── Setup Python (needed by some native deps) ────────────
      - name: Setup Python
        uses: actions/setup-python@v5
        with:
          python-version: '3.11'

      # ─── Install Dependencies ─────────────────────────────────
      - name: Install dependencies
        run: npm ci

      # ─── Import Code Signing Certificate ──────────────────────
      # This is the KEY step that makes CI signing work.
      # We create a temporary keychain, import the .p12 cert into it,
      # and set it as the default so codesign can find it.
      - name: Import code signing certificate
        env:
          MAC_CERTIFICATE_P12: ${{ secrets.MAC_CERTIFICATE_P12 }}
          MAC_CERTIFICATE_PASSWORD: ${{ secrets.MAC_CERTIFICATE_PASSWORD }}
        run: |
          # Create a temporary keychain
          KEYCHAIN_PATH=$RUNNER_TEMP/build.keychain-db
          KEYCHAIN_PASSWORD=$(openssl rand -base64 32)

          # Create and configure keychain
          security create-keychain -p "$KEYCHAIN_PASSWORD" "$KEYCHAIN_PATH"
          security set-keychain-settings -lut 21600 "$KEYCHAIN_PATH"
          security unlock-keychain -p "$KEYCHAIN_PASSWORD" "$KEYCHAIN_PATH"

          # Decode and import certificate
          echo "$MAC_CERTIFICATE_P12" | base64 --decode > $RUNNER_TEMP/certificate.p12
          security import $RUNNER_TEMP/certificate.p12 \
            -k "$KEYCHAIN_PATH" \
            -P "$MAC_CERTIFICATE_PASSWORD" \
            -T /usr/bin/codesign \
            -T /usr/bin/security

          # Allow codesign to access the keychain without UI prompt
          security set-key-partition-list -S apple-tool:,apple: -k "$KEYCHAIN_PASSWORD" "$KEYCHAIN_PATH"

          # Add to keychain search path (makes it the default)
          security list-keychains -d user -s "$KEYCHAIN_PATH" $(security list-keychains -d user | tr -d '"')

          # Verify the identity is available
          security find-identity -v -p codesigning "$KEYCHAIN_PATH"

          # Clean up the .p12 file
          rm -f $RUNNER_TEMP/certificate.p12

      # ─── Build Vite + Electron ────────────────────────────────
      - name: Build Vite + Electron
        run: npx tsc && npx vite build

      # ─── Package with electron-builder ────────────────────────
      # electron-builder handles deep codesigning the .app bundle
      # "notarize: false" in electron-builder.json5 prevents it from
      # trying its own notarization flow
      - name: Package .app bundle
        run: npx electron-builder --mac --${{ matrix.arch }} --dir
        env:
          CSC_NAME: "Samir Patil (N26FZ4GW28)"
          GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}

      # ─── Read version from package.json ───────────────────────
      - name: Get version
        id: version
        run: echo "version=$(node -p 'require(\"./package.json\").version')" >> $GITHUB_OUTPUT

      # ─── Locate the .app bundle ───────────────────────────────
      - name: Find .app bundle
        id: find_app
        run: |
          VERSION="${{ steps.version.outputs.version }}"
          echo "=== Release directory contents ==="
          ls -laR "release/${VERSION}/" || echo "release/${VERSION}/ not found"
          echo "=== Searching for .app bundle ==="
          APP_BUNDLE=$(find "release/${VERSION}" -maxdepth 4 -name "*.app" -type d | head -n1)
          if [ -z "$APP_BUNDLE" ]; then
            echo "::error::No .app bundle found in release/${VERSION}/"
            exit 1
          fi
          echo "app_bundle=$APP_BUNDLE" >> $GITHUB_OUTPUT
          echo "Found: $APP_BUNDLE"

      # ─── Verify .app signature ────────────────────────────────
      - name: Verify .app code signature
        run: codesign --verify --deep --strict "${{ steps.find_app.outputs.app_bundle }}"

      # ─── Create DMG ───────────────────────────────────────────
      - name: Create DMG
        id: dmg
        run: |
          VERSION="${{ steps.version.outputs.version }}"
          ARCH="${{ matrix.arch }}"
          DMG_NAME="Openscreen-Mac-${ARCH}-${VERSION}.dmg"
          RELEASE_DIR="release/${VERSION}"
          DMG_OUTPUT="${RELEASE_DIR}/${DMG_NAME}"
          STAGING="${RELEASE_DIR}/dmg-staging"

          mkdir -p "$STAGING"
          cp -R "${{ steps.find_app.outputs.app_bundle }}" "$STAGING/"
          ln -s /Applications "$STAGING/Applications"

          hdiutil create \
            -srcfolder "$STAGING" \
            -volname "Openscreen" \
            -fs HFS+ \
            -fsargs "-c c=64,a=16,e=16" \
            -format UDBZ \
            "$DMG_OUTPUT"

          rm -rf "$STAGING"

          echo "dmg_path=$DMG_OUTPUT" >> $GITHUB_OUTPUT
          echo "dmg_name=$DMG_NAME" >> $GITHUB_OUTPUT

      # ─── Sign DMG ─────────────────────────────────────────────
      - name: Sign DMG
        run: |
          codesign --force \
            --sign "Developer ID Application: Samir Patil (N26FZ4GW28)" \
            --timestamp \
            "${{ steps.dmg.outputs.dmg_path }}"

      # ─── Notarize DMG ────────────────────────────────────────
      # On CI we can't use keychain profiles for notarytool, so we
      # pass credentials directly via env vars / flags
      - name: Notarize DMG
        run: |
          xcrun notarytool submit "${{ steps.dmg.outputs.dmg_path }}" \
            --apple-id "${{ secrets.APPLE_ID }}" \
            --team-id "${{ secrets.APPLE_TEAM_ID }}" \
            --password "${{ secrets.APPLE_APP_SPECIFIC_PASSWORD }}" \
            --wait
        timeout-minutes: 15

      # ─── Staple ───────────────────────────────────────────────
      - name: Staple notarization ticket
        run: xcrun stapler staple "${{ steps.dmg.outputs.dmg_path }}"

      # ─── Validate ─────────────────────────────────────────────
      - name: Validate stapled DMG
        run: |
          xcrun stapler validate "${{ steps.dmg.outputs.dmg_path }}"
          spctl -a -vv -t install "${{ steps.dmg.outputs.dmg_path }}"

      # ─── Upload Artifact ──────────────────────────────────────
      - name: Upload notarized DMG
        uses: actions/upload-artifact@v4
        with:
          name: openscreen-mac-${{ matrix.arch }}
          path: ${{ steps.dmg.outputs.dmg_path }}
          retention-days: 30

      # ─── Cleanup Keychain ─────────────────────────────────────
      - name: Cleanup keychain
        if: always()
        run: security delete-keychain $RUNNER_TEMP/build.keychain-db || true

  build-linux:
    runs-on: ubuntu-latest
    steps:
      - name: Checkout code
        uses: actions/checkout@v3

      - name: Setup Node.js
        uses: actions/setup-node@v3
        with:
          node-version: '22'

      - name: Install dependencies
        run: npm ci

      # bsdtar (from libarchive-tools) is required by fpm to build pacman
      # packages. AppImage and deb don't need it; ubuntu-latest doesn't ship it.
      - name: Install pacman build dependencies
        run: sudo apt-get update && sudo apt-get install -y libarchive-tools

      - name: Build Linux app
        run: npm run build:linux
        env:
          GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}

      - name: Upload Linux build
        uses: actions/upload-artifact@v4
        with:
          name: linux-installer
          path: |
            release/**/*.AppImage
            release/**/*.zsync
            release/**/*.deb
            release/**/*.pacman
          retention-days: 30
