# Cross-platform release build. Produces installer artifacts for
# Linux (.AppImage + .deb), Windows (.msi + .exe), macOS (.dmg + .app).
#
# Triggers:
# - Manual: any branch via "Run workflow" in the GitHub Actions UI.
#   Use this to build a Windows binary on demand to dual-boot test.
# - Tag push (v*): builds + drafts a GitHub Release with all artifacts
#   attached. Tag a release with `git tag v0.2.0 && git push --tags`.
#
# Artifacts:
# - workflow_dispatch builds: uploaded as Action artifacts
#   (visible in the run page, downloadable for 30 days).
# - tag builds: attached to a draft GitHub Release named after the tag.
#   Promote the draft to a release when ready.
#
# Signing:
# - macOS: signing + notarisation activate automatically when the
#   APPLE_* secrets are set in the repo. Builds unsigned if absent.
#   See docs/release/code-signing-setup.md for the cert walkthrough.
# - Windows: signing activates automatically when WINDOWS_CERTIFICATE
#   + WINDOWS_CERTIFICATE_PASSWORD are set. Builds unsigned if absent.
#   See docs/release/code-signing-setup.md for the cert walkthrough.
name: build

on:
  push:
    tags: ['v*']
  workflow_dispatch:
    inputs:
      tag_name:
        description: 'Optional tag name to attach the build to (leave blank for plain artifacts)'
        required: false

concurrency:
  group: build-${{ github.ref }}
  cancel-in-progress: false  # let release builds finish even on tag re-pushes

jobs:
  build:
    name: build (${{ matrix.os }})
    permissions:
      contents: write  # needed to create draft releases on tag pushes
    strategy:
      fail-fast: false
      matrix:
        include:
          - os: ubuntu-22.04
            artifact_glob: |
              src-tauri/target/release/bundle/appimage/*.AppImage
              src-tauri/target/release/bundle/appimage/*.AppImage.sha256
              src-tauri/target/release/bundle/deb/*.deb
          - os: windows-latest
            artifact_glob: |
              src-tauri/target/release/bundle/msi/*.msi
              src-tauri/target/release/bundle/nsis/*.exe
          - os: macos-latest
            artifact_glob: |
              src-tauri/target/release/bundle/dmg/*.dmg
              src-tauri/target/release/bundle/macos/*.app
    runs-on: ${{ matrix.os }}
    timeout-minutes: 60

    steps:
      - uses: actions/checkout@v4

      # System packages — same as check.yml but locked to release-build needs.
      # See check.yml for the per-package rationale (bindgen → libclang,
      # llama-cpp-sys-2 vulkan feature → libvulkan / VULKAN_SDK).
      - name: Install Linux deps
        if: matrix.os == 'ubuntu-22.04'
        run: |
          sudo apt-get update
          sudo apt-get install -y --no-install-recommends \
            libwebkit2gtk-4.1-dev \
            libappindicator3-dev \
            librsvg2-dev \
            libasound2-dev \
            libudev-dev \
            patchelf \
            cmake \
            build-essential \
            libclang-dev \
            clang \
            libvulkan-dev \
            glslang-tools \
            spirv-tools
          LIBCLANG_CANDIDATE=$(ls -d /usr/lib/llvm-*/lib 2>/dev/null | sort -V | tail -n1)
          if [ -z "$LIBCLANG_CANDIDATE" ]; then
            LIBCLANG_CANDIDATE=/usr/lib/x86_64-linux-gnu
          fi
          echo "LIBCLANG_PATH=$LIBCLANG_CANDIDATE" >> "$GITHUB_ENV"

      - name: Install macOS deps
        if: matrix.os == 'macos-latest'
        run: |
          brew list cmake >/dev/null 2>&1 || brew install cmake
          brew list llvm >/dev/null 2>&1 || brew install llvm
          brew install vulkan-headers vulkan-loader molten-vk shaderc
          echo "LIBCLANG_PATH=$(brew --prefix llvm)/lib" >> "$GITHUB_ENV"
          BREW_PREFIX=$(brew --prefix)
          echo "VULKAN_SDK=$BREW_PREFIX" >> "$GITHUB_ENV"
          echo "CMAKE_PREFIX_PATH=$BREW_PREFIX" >> "$GITHUB_ENV"

      - name: Install Windows deps
        if: matrix.os == 'windows-latest'
        shell: pwsh
        run: |
          cmake --version
          choco install -y llvm --no-progress
          choco install -y vulkan-sdk --no-progress
          $sdkRoot = Get-ChildItem -Directory "C:\VulkanSDK" | Sort-Object Name -Descending | Select-Object -First 1
          if (-not $sdkRoot) {
            Write-Error "VulkanSDK directory not found under C:\VulkanSDK after choco install"
            exit 1
          }
          echo "VULKAN_SDK=$($sdkRoot.FullName)" >> $env:GITHUB_ENV
          echo "LIBCLANG_PATH=C:\Program Files\LLVM\bin" >> $env:GITHUB_ENV

      - name: Install Node
        uses: actions/setup-node@v4
        with:
          node-version: 20
          cache: npm

      - name: Install Rust
        uses: dtolnay/rust-toolchain@stable

      # Workspace is at the repo root; target dir is ./target (not
      # src-tauri/target). See note in check.yml for details.
      - name: Cache Rust
        uses: Swatinem/rust-cache@v2
        with:
          workspaces: .
          shared-key: magnotia-build-${{ matrix.os }}

      - name: Install JS deps
        run: npm ci

      # tauri-action handles `tauri build` plus, on tag pushes, attaches
      # artifacts to a GitHub draft release. Empty tagName disables the
      # release-creation behaviour for manual workflow_dispatch runs.
      - name: Build (release)
        uses: tauri-apps/tauri-action@v0
        env:
          GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
          # macOS code-signing + notarisation. Builds unsigned if these secrets aren't set.
          # Set via: gh secret set APPLE_SIGNING_IDENTITY --body "..." (etc.)
          # See docs/release/code-signing-setup.md for the cert procurement walkthrough.
          APPLE_SIGNING_IDENTITY: ${{ secrets.APPLE_SIGNING_IDENTITY }}
          APPLE_CERTIFICATE: ${{ secrets.APPLE_CERTIFICATE }}
          APPLE_CERTIFICATE_PASSWORD: ${{ secrets.APPLE_CERTIFICATE_PASSWORD }}
          APPLE_ID: ${{ secrets.APPLE_ID }}
          APPLE_PASSWORD: ${{ secrets.APPLE_PASSWORD }}
          APPLE_TEAM_ID: ${{ secrets.APPLE_TEAM_ID }}
          # Windows code-signing. Builds unsigned if these secrets aren't set.
          # Set via: gh secret set WINDOWS_CERTIFICATE --body "..." (etc.)
          # See docs/release/code-signing-setup.md for the cert procurement walkthrough.
          WINDOWS_CERTIFICATE: ${{ secrets.WINDOWS_CERTIFICATE }}
          WINDOWS_CERTIFICATE_PASSWORD: ${{ secrets.WINDOWS_CERTIFICATE_PASSWORD }}
        with:
          # If pushed as a tag, use the tag name; otherwise leave empty
          # so tauri-action builds artifacts but does not touch releases.
          tagName: ${{ github.ref_type == 'tag' && github.ref_name || (inputs.tag_name || '') }}
          releaseName: ${{ github.ref_type == 'tag' && github.ref_name || (inputs.tag_name || '') }}
          releaseDraft: true
          prerelease: false
          # Build all bundle types the OS supports.
          args: ''

      - name: Compute AppImage SHA-256
        if: runner.os == 'Linux'
        shell: bash
        run: |
          set -euo pipefail
          cd src-tauri/target/release/bundle/appimage
          for img in *.AppImage; do
            sha256sum "$img" > "$img.sha256"
            echo "Generated: $img.sha256"
            cat "$img.sha256"
          done

      # Always upload as an Actions artifact too — accessible from the
      # workflow run page even if the release-creation step was skipped.
      - name: Upload artifacts
        if: always()
        uses: actions/upload-artifact@v4
        with:
          name: magnotia-${{ matrix.os }}-${{ github.sha }}
          path: ${{ matrix.artifact_glob }}
          retention-days: 30
          if-no-files-found: warn

      - name: Report artifact sizes
        if: always()
        shell: bash
        run: |
          if [ -d src-tauri/target/release/bundle ]; then
            find src-tauri/target/release/bundle -type f \
              \( -name '*.AppImage' -o -name '*.deb' -o -name '*.msi' -o -name '*.exe' -o -name '*.dmg' -o -name '*.app' \) \
              -exec du -h {} + | sort -h
          fi
