name: Release

on:
  workflow_dispatch:
  push:
    tags: ['v*']

env:
  CARGO_TERM_COLOR: always
  MACOSX_DEPLOYMENT_TARGET: "12.0"

concurrency:
  group: ${{ github.workflow }}-${{ github.ref }}
  cancel-in-progress: true

jobs:
  build:
    if: github.server_url == 'https://github.com'
    strategy:
      fail-fast: false
      matrix:
        include:
          - os: ubuntu-latest
            target: x86_64-unknown-linux-gnu
            artifact: cagire-linux-x86_64
          - os: macos-15-intel
            target: x86_64-apple-darwin
            artifact: cagire-macos-x86_64
          - os: macos-14
            target: aarch64-apple-darwin
            artifact: cagire-macos-aarch64
          - os: windows-latest
            target: x86_64-pc-windows-msvc
            artifact: cagire-windows-x86_64

    runs-on: ${{ matrix.os }}
    timeout-minutes: 30

    steps:
      - uses: actions/checkout@v4
        with:
          submodules: recursive

      - name: Install Rust toolchain
        uses: dtolnay/rust-toolchain@stable
        with:
          targets: ${{ matrix.target }}

      - name: Cache Rust dependencies
        uses: Swatinem/rust-cache@v2
        with:
          key: ${{ matrix.target }}

      - name: Install cargo-binstall
        uses: cargo-bins/cargo-binstall@main

      - name: Install dependencies (Linux)
        if: runner.os == 'Linux'
        run: |
          sudo apt-get update
          sudo apt-get install -y build-essential cmake pkg-config libasound2-dev libclang-dev libjack-dev \
            libxcb-render0-dev libxcb-shape0-dev libxcb-xfixes0-dev libxkbcommon-dev libssl-dev libgl1-mesa-dev
          cargo binstall -y cargo-bundle

      - name: Install dependencies (macOS)
        if: runner.os == 'macOS'
        run: |
          brew list cmake &>/dev/null || brew install cmake
          cargo binstall -y cargo-bundle

      - name: Install dependencies (Windows)
        if: runner.os == 'Windows'
        run: |
          choco install cmake --installargs 'ADD_CMAKE_TO_PATH=System'
          echo "C:\Program Files\CMake\bin" >> $env:GITHUB_PATH

      - name: Build
        run: cargo build --release --target ${{ matrix.target }}

      - name: Build desktop
        run: cargo build --release --features desktop --bin cagire-desktop --target ${{ matrix.target }}

      - name: Bundle desktop app
        if: runner.os != 'Windows'
        run: cargo bundle --release --features desktop --bin cagire-desktop --target ${{ matrix.target }}

      - name: Build AppImages (Linux)
        if: runner.os == 'Linux'
        run: |
          mkdir -p target/releases
          scripts/make-appimage.sh target/${{ matrix.target }}/release/cagire x86_64 target/releases
          scripts/make-appimage.sh target/${{ matrix.target }}/release/cagire-desktop x86_64 target/releases

      - name: Upload AppImage artifacts (Linux)
        if: runner.os == 'Linux'
        uses: actions/upload-artifact@v4
        with:
          name: ${{ matrix.artifact }}-appimage
          path: target/releases/*.AppImage

      - name: Bundle CLAP plugin
        run: cargo xtask bundle cagire-plugins --release --target ${{ matrix.target }}

      - name: Zip macOS app bundle
        if: runner.os == 'macOS'
        run: |
          cd target/${{ matrix.target }}/release/bundle/osx
          zip -r Cagire.app.zip Cagire.app

      - name: Upload artifact (Unix)
        if: runner.os != 'Windows'
        uses: actions/upload-artifact@v4
        with:
          name: ${{ matrix.artifact }}
          path: target/${{ matrix.target }}/release/cagire

      - name: Upload artifact (Windows)
        if: runner.os == 'Windows'
        uses: actions/upload-artifact@v4
        with:
          name: ${{ matrix.artifact }}
          path: target/${{ matrix.target }}/release/cagire.exe

      - name: Upload desktop artifact (Linux deb)
        if: runner.os == 'Linux'
        uses: actions/upload-artifact@v4
        with:
          name: ${{ matrix.artifact }}-desktop
          path: target/${{ matrix.target }}/release/bundle/deb/*.deb

      - name: Upload desktop artifact (macOS app bundle)
        if: runner.os == 'macOS'
        uses: actions/upload-artifact@v4
        with:
          name: ${{ matrix.artifact }}-desktop
          path: target/${{ matrix.target }}/release/bundle/osx/Cagire.app.zip

      - name: Upload desktop artifact (Windows exe)
        if: runner.os == 'Windows'
        uses: actions/upload-artifact@v4
        with:
          name: ${{ matrix.artifact }}-desktop
          path: target/${{ matrix.target }}/release/cagire-desktop.exe

      - name: Install cargo-wix (Windows)
        if: runner.os == 'Windows'
        run: cargo install cargo-wix

      - name: Build MSI installer (Windows)
        if: runner.os == 'Windows'
        run: cargo wix --no-build --nocapture -C -p -C x64

      - name: Upload MSI installer (Windows)
        if: runner.os == 'Windows'
        uses: actions/upload-artifact@v4
        with:
          name: ${{ matrix.artifact }}-msi
          path: target/wix/*.msi

      - name: Upload CLAP artifact
        uses: actions/upload-artifact@v4
        with:
          name: ${{ matrix.artifact }}-clap
          path: target/bundled/cagire-plugins.clap

      - name: Upload VST3 artifact
        uses: actions/upload-artifact@v4
        with:
          name: ${{ matrix.artifact }}-vst3
          path: target/bundled/cagire-plugins.vst3

  build-cross:
    if: github.server_url == 'https://github.com'
    runs-on: ubuntu-latest
    timeout-minutes: 45

    strategy:
      fail-fast: false
      matrix:
        include:
          - target: aarch64-unknown-linux-gnu
            artifact: cagire-linux-aarch64

    steps:
      - uses: actions/checkout@v4
        with:
          submodules: recursive

      - name: Install Rust toolchain
        uses: dtolnay/rust-toolchain@stable
        with:
          targets: ${{ matrix.target }}

      - name: Cache Rust dependencies
        uses: Swatinem/rust-cache@v2
        with:
          key: ${{ matrix.target }}

      - name: Install cross
        run: cargo install cross --git https://github.com/cross-rs/cross

      - name: Build
        run: cross build --release --target ${{ matrix.target }}

      - name: Build desktop
        run: cross build --release --features desktop --bin cagire-desktop --target ${{ matrix.target }}

      - name: Upload artifact
        uses: actions/upload-artifact@v4
        with:
          name: ${{ matrix.artifact }}
          path: target/${{ matrix.target }}/release/cagire

      - name: Upload desktop artifact
        uses: actions/upload-artifact@v4
        with:
          name: ${{ matrix.artifact }}-desktop
          path: target/${{ matrix.target }}/release/cagire-desktop

  universal-macos:
    if: github.server_url == 'https://github.com'
    needs: build
    runs-on: macos-14
    timeout-minutes: 10

    steps:
      - name: Download macOS artifacts
        uses: actions/download-artifact@v4
        with:
          pattern: cagire-macos-*
          path: artifacts

      - name: Create universal CLI binary
        run: |
          lipo -create \
            artifacts/cagire-macos-x86_64/cagire \
            artifacts/cagire-macos-aarch64/cagire \
            -output cagire
          chmod +x cagire
          lipo -info cagire

      - name: Create universal app bundle
        run: |
          cd artifacts/cagire-macos-aarch64-desktop
          unzip Cagire.app.zip
          cd ../cagire-macos-x86_64-desktop
          unzip Cagire.app.zip
          cd ../..
          cp -R artifacts/cagire-macos-aarch64-desktop/Cagire.app Cagire.app
          lipo -create \
            artifacts/cagire-macos-x86_64-desktop/Cagire.app/Contents/MacOS/cagire-desktop \
            artifacts/cagire-macos-aarch64-desktop/Cagire.app/Contents/MacOS/cagire-desktop \
            -output Cagire.app/Contents/MacOS/cagire-desktop
          lipo -info Cagire.app/Contents/MacOS/cagire-desktop
          zip -r Cagire.app.zip Cagire.app

      - name: Create universal CLAP plugin
        run: |
          mkdir -p cagire-plugins.clap/Contents/MacOS
          cp artifacts/cagire-macos-aarch64-clap/cagire-plugins.clap/Contents/Info.plist \
            cagire-plugins.clap/Contents/ 2>/dev/null || true
          cp artifacts/cagire-macos-aarch64-clap/cagire-plugins.clap/Contents/PkgInfo \
            cagire-plugins.clap/Contents/ 2>/dev/null || true
          lipo -create \
            artifacts/cagire-macos-x86_64-clap/cagire-plugins.clap/Contents/MacOS/cagire-plugins \
            artifacts/cagire-macos-aarch64-clap/cagire-plugins.clap/Contents/MacOS/cagire-plugins \
            -output cagire-plugins.clap/Contents/MacOS/cagire-plugins
          lipo -info cagire-plugins.clap/Contents/MacOS/cagire-plugins

      - name: Create universal VST3 plugin
        run: |
          mkdir -p cagire-plugins.vst3/Contents/MacOS
          cp -R artifacts/cagire-macos-aarch64-vst3/cagire-plugins.vst3/Contents/Info.plist \
            cagire-plugins.vst3/Contents/ 2>/dev/null || true
          cp artifacts/cagire-macos-aarch64-vst3/cagire-plugins.vst3/Contents/PkgInfo \
            cagire-plugins.vst3/Contents/ 2>/dev/null || true
          cp -R artifacts/cagire-macos-aarch64-vst3/cagire-plugins.vst3/Contents/Resources \
            cagire-plugins.vst3/Contents/ 2>/dev/null || true
          lipo -create \
            artifacts/cagire-macos-x86_64-vst3/cagire-plugins.vst3/Contents/MacOS/cagire-plugins \
            artifacts/cagire-macos-aarch64-vst3/cagire-plugins.vst3/Contents/MacOS/cagire-plugins \
            -output cagire-plugins.vst3/Contents/MacOS/cagire-plugins
          lipo -info cagire-plugins.vst3/Contents/MacOS/cagire-plugins

      - uses: actions/checkout@v4
        with:
          sparse-checkout: |
            assets/DMG-README.txt
            scripts/make-dmg.sh
          clean: false

      - name: Create DMG
        run: |
          chmod +x scripts/make-dmg.sh
          scripts/make-dmg.sh Cagire.app .

      - name: Build .pkg installer
        run: |
          VERSION="${GITHUB_REF_NAME#v}"
          mkdir -p pkg-root/Applications pkg-root/usr/local/bin
          cp -R Cagire.app pkg-root/Applications/
          cp cagire pkg-root/usr/local/bin/
          pkgbuild --analyze --root pkg-root component.plist
          plutil -replace BundleIsRelocatable -bool NO component.plist
          pkgbuild --root pkg-root --identifier com.sova.cagire \
            --version "$VERSION" --install-location / \
            --component-plist component.plist \
            "Cagire-${VERSION}-universal.pkg"

      - name: Upload universal CLI
        uses: actions/upload-artifact@v4
        with:
          name: cagire-macos-universal
          path: cagire

      - name: Upload universal app bundle
        uses: actions/upload-artifact@v4
        with:
          name: cagire-macos-universal-desktop
          path: Cagire.app.zip

      - name: Upload universal CLAP plugin
        uses: actions/upload-artifact@v4
        with:
          name: cagire-macos-universal-clap
          path: cagire-plugins.clap

      - name: Upload universal VST3 plugin
        uses: actions/upload-artifact@v4
        with:
          name: cagire-macos-universal-vst3
          path: cagire-plugins.vst3

      - name: Upload DMG
        uses: actions/upload-artifact@v4
        with:
          name: cagire-macos-universal-dmg
          path: Cagire-*.dmg

      - name: Upload .pkg installer
        uses: actions/upload-artifact@v4
        with:
          name: cagire-macos-universal-pkg
          path: Cagire-*-universal.pkg

  release:
    needs: [build, build-cross, universal-macos]
    if: startsWith(github.ref, 'refs/tags/v') && github.server_url == 'https://github.com'
    runs-on: ubuntu-latest
    timeout-minutes: 10
    permissions:
      contents: write

    steps:
      - name: Download all artifacts
        uses: actions/download-artifact@v4
        with:
          path: artifacts

      - name: Prepare release files
        run: |
          mkdir -p release
          for dir in artifacts/*/; do
            name=$(basename "$dir")
            if [[ "$name" == "cagire-macos-universal-dmg" ]]; then
              cp "$dir"/*.dmg release/
            elif [[ "$name" == "cagire-macos-universal-pkg" ]]; then
              cp "$dir"/*.pkg release/
            elif [[ "$name" == "cagire-macos-universal-desktop" ]]; then
              cp "$dir/Cagire.app.zip" "release/cagire-macos-universal-desktop.app.zip"
            elif [[ "$name" == "cagire-macos-universal" ]]; then
              cp "$dir/cagire" "release/cagire-macos-universal"
            elif [[ "$name" == "cagire-macos-universal-clap" ]]; then
              cd "$dir" && zip -r "../../release/cagire-macos-universal-clap.zip" cagire-plugins.clap && cd ../..
            elif [[ "$name" == "cagire-macos-universal-vst3" ]]; then
              cd "$dir" && zip -r "../../release/cagire-macos-universal-vst3.zip" cagire-plugins.vst3 && cd ../..
            elif [[ "$name" == *-clap ]]; then
              base="${name%-clap}"
              cd "$dir" && zip -r "../../release/${base}-clap.zip" cagire-plugins.clap && cd ../..
            elif [[ "$name" == *-vst3 ]]; then
              base="${name%-vst3}"
              cd "$dir" && zip -r "../../release/${base}-vst3.zip" cagire-plugins.vst3 && cd ../..
            elif [[ "$name" == *-msi ]]; then
              cp "$dir"/*.msi release/
            elif [[ "$name" == *-appimage ]]; then
              cp "$dir"/*.AppImage release/
            elif [[ "$name" == *-desktop ]]; then
              base="${name%-desktop}"
              if ls "$dir"/*.deb 1>/dev/null 2>&1; then
                cp "$dir"/*.deb "release/${base}-desktop.deb"
              elif [ -f "$dir/Cagire.app.zip" ]; then
                cp "$dir/Cagire.app.zip" "release/${base}-desktop.app.zip"
              elif [ -f "$dir/cagire-desktop.exe" ]; then
                cp "$dir/cagire-desktop.exe" "release/${base}-desktop.exe"
              fi
            else
              if [ -f "$dir/cagire.exe" ]; then
                cp "$dir/cagire.exe" "release/${name}.exe"
              elif [ -f "$dir/cagire" ]; then
                cp "$dir/cagire" "release/${name}"
              fi
            fi
          done

      - name: Create Release
        uses: softprops/action-gh-release@v2
        with:
          files: release/*
          generate_release_notes: true
