name: Release

on:
  push:
    tags:
      - "v*"

permissions:
  contents: write

env:
  CARGO_TERM_COLOR: always
  NODE_VERSION: "22.12.0"

jobs:
  preflight:
    name: Release Preflight
    runs-on: ubuntu-latest
    env:
      NPM_TOKEN: ${{ secrets.NPM_TOKEN }}
      CARGO_REGISTRY_TOKEN: ${{ secrets.CARGO_REGISTRY_TOKEN }}
      VSCE_PAT: ${{ secrets.VSCE_PAT }}
    steps:
      - uses: actions/checkout@v6
      - uses: actions/setup-node@v6
        with:
          node-version: ${{ env.NODE_VERSION }}
      - name: Verify release secrets
        run: |
          missing=0
          for name in NPM_TOKEN CARGO_REGISTRY_TOKEN VSCE_PAT; do
            if [ -z "${!name:-}" ]; then
              echo "::error::Missing required release secret: ${name}"
              missing=1
            fi
          done
          exit "${missing}"
      - name: Verify tag matches package versions
        run: |
          tag_version="${GITHUB_REF_NAME#v}"
          cargo_version=$(sed -n 's/^version = "\(.*\)"/\1/p' Cargo.toml | head -n 1)
          npm_version=$(node -p "require('./packages/npm/package.json').version")
          vscode_version=$(node -p "require('./vscode-extension/package.json').version")
          vscode_lock_version=$(node -p "require('./vscode-extension/package-lock.json').version")

          for entry in \
            "Cargo.toml:${cargo_version}" \
            "packages/npm/package.json:${npm_version}" \
            "vscode-extension/package.json:${vscode_version}" \
            "vscode-extension/package-lock.json:${vscode_lock_version}"
          do
            file="${entry%%:*}"
            version="${entry#*:}"
            if [ "${version}" != "${tag_version}" ]; then
              echo "::error::${file} version ${version} does not match tag ${tag_version}"
              exit 1
            fi
          done

  build:
    name: Build ${{ matrix.target }}
    needs: preflight
    runs-on: ${{ matrix.os }}
    strategy:
      matrix:
        include:
          - target: x86_64-unknown-linux-gnu
            os: ubuntu-latest
            artifact: foxguard-linux-x86_64
          - target: aarch64-unknown-linux-gnu
            os: ubuntu-latest
            artifact: foxguard-linux-aarch64
          - target: x86_64-apple-darwin
            os: macos-latest
            artifact: foxguard-macos-x86_64
          - target: aarch64-apple-darwin
            os: macos-latest
            artifact: foxguard-macos-aarch64
          - target: x86_64-pc-windows-msvc
            os: windows-latest
            artifact: foxguard-windows-x86_64.exe

    steps:
      - uses: actions/checkout@v6

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

      - name: Install cross-compilation tools
        if: matrix.target == 'aarch64-unknown-linux-gnu'
        run: |
          sudo apt-get update
          sudo apt-get install -y gcc-aarch64-linux-gnu
          echo "CARGO_TARGET_AARCH64_UNKNOWN_LINUX_GNU_LINKER=aarch64-linux-gnu-gcc" >> $GITHUB_ENV

      - uses: actions/cache@v5
        with:
          path: |
            ~/.cargo/registry
            ~/.cargo/git
            target
          key: ${{ runner.os }}-${{ matrix.target }}-cargo-release-${{ hashFiles('**/Cargo.lock') }}
          restore-keys: ${{ runner.os }}-${{ matrix.target }}-cargo-release-

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

      - name: Rename binary (unix)
        if: runner.os != 'Windows'
        run: cp target/${{ matrix.target }}/release/foxguard ${{ matrix.artifact }}

      - name: Rename binary (windows)
        if: runner.os == 'Windows'
        run: cp target/${{ matrix.target }}/release/foxguard.exe ${{ matrix.artifact }}

      - uses: actions/upload-artifact@v7
        with:
          name: ${{ matrix.artifact }}
          path: ${{ matrix.artifact }}

  github-release:
    name: Create GitHub Release
    needs: build
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v6

      - uses: actions/download-artifact@v8
        with:
          path: artifacts

      - name: Collect binaries
        run: |
          mkdir -p release
          find artifacts -type f -exec cp {} release/ \;
          ls -la release/

      - name: Create GitHub Release
        uses: softprops/action-gh-release@v2
        with:
          generate_release_notes: true
          files: release/*
        env:
          GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}

  publish-crates:
    name: Publish crates.io
    needs: github-release
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v6
      - uses: dtolnay/rust-toolchain@stable
      - name: Publish crate
        run: cargo publish --token "${{ secrets.CARGO_REGISTRY_TOKEN }}"

  publish-npm:
    name: Publish npm
    needs: github-release
    runs-on: ubuntu-latest
    defaults:
      run:
        working-directory: packages/npm
    steps:
      - uses: actions/checkout@v6
      - uses: actions/setup-node@v6
        with:
          node-version: ${{ env.NODE_VERSION }}
          registry-url: "https://registry.npmjs.org"
      - name: Publish npm package
        run: npm publish --access public
        env:
          NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }}

  publish-vscode:
    name: Publish VS Code Extension
    needs: github-release
    runs-on: ubuntu-latest
    defaults:
      run:
        working-directory: vscode-extension
    steps:
      - uses: actions/checkout@v6
      - uses: actions/setup-node@v6
        with:
          node-version: ${{ env.NODE_VERSION }}
          cache: npm
          cache-dependency-path: vscode-extension/package-lock.json
      - run: npm ci
      - run: npm run compile
      - name: Publish extension
        run: npx @vscode/vsce publish -p "${VSCE_PAT}"
        env:
          VSCE_PAT: ${{ secrets.VSCE_PAT }}
