name: Release

on:
  push:
    tags:
      - 'v[0-9]+.[0-9]+.[0-9]+'

permissions:
  contents: write

env:
  CARGO_TERM_COLOR: always

jobs:
  create-release:
    name: Create Release
    runs-on: ubuntu-latest
    outputs:
      upload_url: ${{ steps.create_release.outputs.upload_url }}
      version: ${{ steps.get_version.outputs.version }}
    steps:
      - uses: actions/checkout@v4

      - name: Get version from tag
        id: get_version
        run: echo "version=${GITHUB_REF#refs/tags/v}" >> $GITHUB_OUTPUT

      - name: Read release notes
        id: release_notes
        run: |
          VERSION=${{ steps.get_version.outputs.version }}
          NOTES_FILE="docs/release-notes/v${VERSION}.md"
          if [ -f "$NOTES_FILE" ]; then
            {
              echo "body<<EOF"
              cat "$NOTES_FILE"
              echo "EOF"
            } >> $GITHUB_OUTPUT
          else
            echo "body=Release v${VERSION}" >> $GITHUB_OUTPUT
          fi

      - name: Create Release
        id: create_release
        uses: softprops/action-gh-release@v1
        with:
          name: Release ${{ steps.get_version.outputs.version }}
          body: ${{ steps.release_notes.outputs.body }}
          draft: false
          prerelease: false

  build:
    name: Build ${{ matrix.target }}
    needs: create-release
    strategy:
      fail-fast: false
      matrix:
        include:
          - target: x86_64-unknown-linux-gnu
            os: ubuntu-latest
            artifact_name: gcop-rs
            platform: linux-amd64

          - target: aarch64-unknown-linux-gnu
            os: ubuntu-24.04-arm
            artifact_name: gcop-rs
            platform: linux-arm64

          - target: x86_64-apple-darwin
            os: macos-latest
            artifact_name: gcop-rs
            platform: macos-amd64

          - target: aarch64-apple-darwin
            os: macos-latest
            artifact_name: gcop-rs
            platform: macos-arm64

          - target: x86_64-pc-windows-msvc
            os: windows-latest
            artifact_name: gcop-rs.exe
            platform: windows-amd64.exe

          - target: aarch64-pc-windows-msvc
            os: windows-latest
            artifact_name: gcop-rs.exe
            platform: windows-aarch64.exe
            
    runs-on: ${{ matrix.os }}
    steps:
      - uses: actions/checkout@v4

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

      - uses: Swatinem/rust-cache@v2

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

      - name: Strip binary (Linux/macOS)
        if: matrix.os != 'windows-latest'
        run: strip target/${{ matrix.target }}/release/${{ matrix.artifact_name }}

      - name: Prepare release binary
        shell: bash
        run: |
          VERSION=${{ needs.create-release.outputs.version }}
          cd target/${{ matrix.target }}/release
          # Rename: gcop-rs -> gcop-rs-v0.1.0-linux-amd64
          cp ${{ matrix.artifact_name }} gcop-rs-v${VERSION}-${{ matrix.platform }}

      - name: Upload binary to release
        uses: softprops/action-gh-release@v1
        with:
          files: target/${{ matrix.target }}/release/gcop-rs-v${{ needs.create-release.outputs.version }}-${{ matrix.platform }}
        env:
          GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}

  publish-crates:
    name: Publish to crates.io
    needs: build
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4

      - uses: dtolnay/rust-toolchain@stable

      - uses: Swatinem/rust-cache@v2

      - name: Verify package
        run: cargo package --list

      - name: Dry run publish
        run: cargo publish --dry-run

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

  update-homebrew:
    name: Update Homebrew Tap
    needs: [create-release, build]
    runs-on: ubuntu-latest
    steps:
      - name: Download release assets and calculate SHA256
        id: sha256
        run: |
          VERSION=${{ needs.create-release.outputs.version }}
          BASE_URL="https://github.com/AptS-1547/gcop-rs/releases/download/v${VERSION}"

          # Download and calculate SHA256 for each platform
          curl -sL "${BASE_URL}/gcop-rs-v${VERSION}-macos-arm64" -o macos-arm64
          curl -sL "${BASE_URL}/gcop-rs-v${VERSION}-macos-amd64" -o macos-amd64
          curl -sL "${BASE_URL}/gcop-rs-v${VERSION}-linux-arm64" -o linux-arm64
          curl -sL "${BASE_URL}/gcop-rs-v${VERSION}-linux-amd64" -o linux-amd64

          echo "macos_arm64=$(sha256sum macos-arm64 | cut -d' ' -f1)" >> $GITHUB_OUTPUT
          echo "macos_amd64=$(sha256sum macos-amd64 | cut -d' ' -f1)" >> $GITHUB_OUTPUT
          echo "linux_arm64=$(sha256sum linux-arm64 | cut -d' ' -f1)" >> $GITHUB_OUTPUT
          echo "linux_amd64=$(sha256sum linux-amd64 | cut -d' ' -f1)" >> $GITHUB_OUTPUT

      - name: Update Homebrew Formula
        uses: actions/github-script@v7
        with:
          github-token: ${{ secrets.HOMEBREW_TAP_TOKEN }}
          script: |
            const version = '${{ needs.create-release.outputs.version }}';
            const sha256 = {
              macos_arm64: '${{ steps.sha256.outputs.macos_arm64 }}',
              macos_amd64: '${{ steps.sha256.outputs.macos_amd64 }}',
              linux_arm64: '${{ steps.sha256.outputs.linux_arm64 }}',
              linux_amd64: '${{ steps.sha256.outputs.linux_amd64 }}'
            };

            const formula = `# typed: false
            # frozen_string_literal: true

            class GcopRs < Formula
              desc "AI-powered Git commit message generator and code reviewer"
              homepage "https://github.com/AptS-1547/gcop-rs"
              version "${version}"
              license "MIT"

              on_macos do
                on_arm do
                  url "https://github.com/AptS-1547/gcop-rs/releases/download/v#{version}/gcop-rs-v#{version}-macos-arm64"
                  sha256 "${sha256.macos_arm64}"

                  def install
                    bin.install "gcop-rs-v#{version}-macos-arm64" => "gcop-rs"
                  end
                end

                on_intel do
                  url "https://github.com/AptS-1547/gcop-rs/releases/download/v#{version}/gcop-rs-v#{version}-macos-amd64"
                  sha256 "${sha256.macos_amd64}"

                  def install
                    bin.install "gcop-rs-v#{version}-macos-amd64" => "gcop-rs"
                  end
                end
              end

              on_linux do
                on_arm do
                  url "https://github.com/AptS-1547/gcop-rs/releases/download/v#{version}/gcop-rs-v#{version}-linux-arm64"
                  sha256 "${sha256.linux_arm64}"

                  def install
                    bin.install "gcop-rs-v#{version}-linux-arm64" => "gcop-rs"
                  end
                end

                on_intel do
                  url "https://github.com/AptS-1547/gcop-rs/releases/download/v#{version}/gcop-rs-v#{version}-linux-amd64"
                  sha256 "${sha256.linux_amd64}"

                  def install
                    bin.install "gcop-rs-v#{version}-linux-amd64" => "gcop-rs"
                  end
                end
              end

              test do
                assert_match version.to_s, shell_output("#{bin}/gcop-rs --version")
              end
            end
            `.split('\n').map(line => line.replace(/^            /, '')).join('\n');

            // Get current file (if exists) to get its SHA
            let fileSha;
            try {
              const { data } = await github.rest.repos.getContent({
                owner: 'AptS-1547',
                repo: 'homebrew-gcop-rs',
                path: 'Formula/gcop-rs.rb'
              });
              fileSha = data.sha;
            } catch (e) {
              // File doesn't exist yet
              fileSha = undefined;
            }

            // Create or update the formula file
            await github.rest.repos.createOrUpdateFileContents({
              owner: 'AptS-1547',
              repo: 'homebrew-gcop-rs',
              path: 'Formula/gcop-rs.rb',
              message: `chore: bump gcop-rs to v${version}`,
              content: Buffer.from(formula).toString('base64'),
              sha: fileSha
            });

  publish-pypi:
    name: Build Python wheels (${{ matrix.target }})
    needs: create-release
    runs-on: ${{ matrix.os }}
    strategy:
      fail-fast: false
      matrix:
        include:
          - os: ubuntu-latest
            target: x86_64-unknown-linux-gnu
          - os: ubuntu-24.04-arm
            target: aarch64-unknown-linux-gnu
          - os: macos-latest
            target: x86_64-apple-darwin
          - os: macos-latest
            target: aarch64-apple-darwin
          - os: windows-latest
            target: x86_64-pc-windows-msvc
          - os: windows-latest
            target: aarch64-pc-windows-msvc
    steps:
      - uses: actions/checkout@v4

      - name: Update version
        shell: bash
        run: |
          VERSION=${{ needs.create-release.outputs.version }}
          sed -i.bak "s/^version = .*/version = \"${VERSION}\"/" python/pyproject.toml

      - name: Build wheels
        uses: PyO3/maturin-action@v1
        with:
          target: ${{ matrix.target }}
          args: --release --out dist
          working-directory: python
          manylinux: auto

      - name: Upload wheels
        uses: actions/upload-artifact@v4
        with:
          name: wheels-${{ matrix.target }}
          path: python/dist

  publish-pypi-upload:
    name: Upload to PyPI
    needs: publish-pypi
    runs-on: ubuntu-latest
    steps:
      - uses: actions/download-artifact@v4
        with:
          pattern: wheels-*
          merge-multiple: true
          path: dist

      - name: Publish to PyPI
        uses: pypa/gh-action-pypi-publish@release/v1
        with:
          password: ${{ secrets.PYPI_API_TOKEN }}

