name: Release

on:
  push:
    tags:
      - "v*"
  workflow_dispatch:

permissions:
  contents: write

jobs:
  build:
    strategy:
      matrix:
        include:
          - target: x86_64-unknown-linux-gnu
            os: ubuntu-latest
            artifact-name: linux-x64
          - target: aarch64-unknown-linux-gnu
            os: ubuntu-latest
            artifact-name: linux-arm64
            use-cross: true
          - target: x86_64-apple-darwin
            os: macos-latest
            artifact-name: darwin-x64
          - target: aarch64-apple-darwin
            os: macos-latest
            artifact-name: darwin-arm64
          - target: x86_64-unknown-linux-musl
            os: ubuntu-latest
            artifact-name: linux-x64-musl
            use-cross: true
          - target: aarch64-unknown-linux-musl
            os: ubuntu-latest
            artifact-name: linux-arm64-musl
            use-cross: true
          - target: x86_64-pc-windows-msvc
            os: windows-latest
            artifact-name: windows-x64
          - target: aarch64-pc-windows-msvc
            os: ubuntu-latest
            artifact-name: windows-arm64
            use-cargo-xwin: true
    runs-on: ${{ matrix.os }}
    steps:
      - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2

      - uses: jdx/mise-action@1648a7812b9aeae629881980618f079932869151 # v4.0.1

      - name: Install Rust toolchain
        if: "!matrix.use-cross"
        run: rustup target add ${{ matrix.target }}

      - uses: Swatinem/rust-cache@c19371144df3bb44fab255c43d04cbc2ab54d1c4 # v2.9.1
        with:
          key: ${{ matrix.target }}

      - name: Install cross-compilation tools
        if: matrix.use-cross
        run: cargo install cross

      - name: Install cargo-xwin
        if: matrix.use-cargo-xwin
        run: cargo install cargo-xwin

      - name: Cache xwin MSVC CRT
        if: matrix.use-cargo-xwin
        uses: actions/cache@27d5ce7f107fe9357f9df03efb73ab90386fccae # v5.0.5
        with:
          path: ~/.cache/cargo-xwin
          key: cargo-xwin-msvc

      - name: Build (cross)
        if: matrix.use-cross
        run: cross build --release --target ${{ matrix.target }}

      - name: Build (cargo-xwin)
        if: matrix.use-cargo-xwin
        run: cargo xwin build --release --target ${{ matrix.target }}

      - name: Build (native)
        if: ${{ !matrix.use-cross && !matrix.use-cargo-xwin }}
        run: cargo build --release --target ${{ matrix.target }}

      - name: Get version
        id: version
        shell: bash
        run: echo "VERSION=${GITHUB_REF_NAME#v}" >> $GITHUB_OUTPUT

      - name: Create zip
        shell: bash
        run: |
          if [[ "${{ matrix.target }}" == *windows* ]]; then
            BIN=nsis-lsp.exe
          else
            BIN=nsis-lsp
          fi
          7z a "nsis-lsp-${{ steps.version.outputs.VERSION }}-${{ matrix.artifact-name }}.zip" \
            "./target/${{ matrix.target }}/release/${BIN}" LICENSE-APACHE LICENSE-MIT

      - name: Upload artifact
        uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1
        with:
          name: nsis-lsp-${{ matrix.artifact-name }}
          path: nsis-lsp-*.zip

      - name: Upload binary for npm
        uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1
        with:
          name: nsis-lsp-bin-${{ matrix.artifact-name }}
          path: target/${{ matrix.target }}/release/nsis-lsp${{ contains(matrix.target, 'windows') && '.exe' || '' }}

  create-release:
    needs: build
    runs-on: ubuntu-latest
    steps:
      - name: Download artifacts
        uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8.0.1
        with:
          merge-multiple: true

      - name: Create release
        uses: softprops/action-gh-release@b4309332981a82ec1c5618f44dd2e27cc8bfbfda # v3.0.0
        with:
          files: nsis-lsp-*.zip

  publish-to-crates:
    needs: build
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2

      - uses: jdx/mise-action@1648a7812b9aeae629881980618f079932869151 # v4.0.1

      - name: Publish to crates.io
        run: cargo publish
        env:
          CARGO_REGISTRY_TOKEN: ${{ secrets.CARGO_REGISTRY_TOKEN }}

  publish-to-npm:
    needs: build
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2

      - uses: actions/setup-node@48b55a011bda9f5d6aeb4c2d9c7362e8dae4041e # v6.4.0
        with:
          node-version: 22
          registry-url: https://registry.npmjs.org

      - name: Download all binary artifacts
        uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8.0.1
        with:
          pattern: nsis-lsp-bin-*
          path: artifacts/

      - name: Copy binaries into platform packages
        shell: bash
        run: |
          declare -A MAP=(
            [darwin-arm64]=lsp-darwin-arm64
            [darwin-x64]=lsp-darwin-x64
            [linux-arm64]=lsp-linux-arm64
            [linux-x64]=lsp-linux-x64
            [linux-x64-musl]=lsp-linux-x64-musl
            [linux-arm64-musl]=lsp-linux-arm64-musl
            [windows-x64]=lsp-win32-x64
            [windows-arm64]=lsp-win32-arm64
          )
          for key in "${!MAP[@]}"; do
            pkg="packages/${MAP[$key]}"
            if [[ "$key" == windows* ]]; then
              cp "artifacts/nsis-lsp-bin-${key}/nsis-lsp.exe" "$pkg/"
            else
              cp "artifacts/nsis-lsp-bin-${key}/nsis-lsp" "$pkg/"
              chmod +x "$pkg/nsis-lsp"
            fi
          done

      - name: Set version from tag
        shell: bash
        run: |
          VERSION="${GITHUB_REF_NAME#v}"
          for pkg in packages/*/package.json; do
            sed -i "s/\"version\": \"0\.0\.0\"/\"version\": \"$VERSION\"/" "$pkg"
            sed -i "s/\": \"0\.0\.0\"/\": \"$VERSION\"/g" "$pkg"
          done

      - name: Publish platform packages
        shell: bash
        run: |
          for pkg in packages/lsp-*/; do
            cd "$pkg"
            npm publish --access public
            cd "$GITHUB_WORKSPACE"
          done
        env:
          NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }}

      - name: Publish main package
        working-directory: packages/lsp
        run: npm publish --access public
        env:
          NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }}
