name: Release Rust

on:
  workflow_call:
    inputs:
      version:
        required: true
        type: string

permissions:
  contents: write
  id-token: write

defaults:
  run:
    shell: bash

jobs:
  version:
    name: read version
    runs-on: ubuntu-latest
    outputs:
      version: ${{ steps.version.outputs.version }}
    steps:
      - name: Checkout
        uses: actions/checkout@v5

      - name: Read version from package.json
        id: version
        working-directory: rust
        run: |
          if [ -n "${{ inputs.version }}" ]; then
            version="${{ inputs.version }}"
          else
            version=$(node -p "require('./package.json').version")
          fi
          echo "version=${version}" >> "$GITHUB_OUTPUT"

  crates-publish:
    needs: version
    uses: ./.github/workflows/crates-publish.yml
    with:
      version: ${{ needs.version.outputs.version }}
    secrets: inherit

  npm-rust-publish:
    needs: version
    uses: ./.github/workflows/npm-rust-publish.yml
    with:
      version: ${{ needs.version.outputs.version }}
    secrets: inherit

  create-release:
    name: create GitHub release
    needs:
      - version
      - crates-publish
      - npm-rust-publish
    if: ${{ always() && needs.crates-publish.result != 'failure' && needs.npm-rust-publish.result != 'failure' }}
    runs-on: ubuntu-latest
    steps:
      - name: Checkout
        uses: actions/checkout@v5

      - name: Resolve published packages
        id: packages
        working-directory: rust
        run: |
          version="${{ needs.version.outputs.version }}"
          published=""
          failed=""

          # ── crates.io packages ──
          for toml in crates/*/Cargo.toml; do
            name=$(grep '^name = ' "$toml" | head -1 | sed 's/name = "\(.*\)"/\1/')
            local_ver=$(grep '^version = ' "$toml" | head -1 | sed 's/version = "\(.*\)"/\1/')
            if [ -z "$name" ] || [ -z "$local_ver" ]; then
              continue
            fi
            max_ver=$(curl -sfH "Accept: application/json" -H "User-Agent: jscpd-ci (github.com/kucherenko/jscpd)" "https://crates.io/api/v1/crates/${name}" 2>/dev/null \
              | node -e "let d='';process.stdin.on('data',c=>d+=c);process.stdin.on('end',()=>{try{const c=JSON.parse(d);process.stdout.write(c.crate.max_version)}catch(e){process.stdout.write('')}})" || echo "")
            if [ "$max_ver" = "$local_ver" ]; then
              published="${published}  - \`${name}@${local_ver}\` on crates.io\n"
            else
              failed="${failed}  - \`${name}@${local_ver}\` (published: ${max_ver:-none})\n"
            fi
          done

          # ── npm packages ──
          npm_pkgs=(cpd jscpd cpd-darwin-arm64 cpd-darwin-x64 cpd-linux-x64-gnu cpd-linux-arm64-gnu cpd-linux-x64-musl cpd-windows-x64-msvc)
          for pkg in "${npm_pkgs[@]}"; do
            pub_ver=$(npm view "${pkg}@${version}" version 2>/dev/null || echo "")
            if [ "$pub_ver" = "$version" ]; then
              published="${published}  - \`${pkg}@${version}\` on npm\n"
            else
              latest_ver=$(npm view "${pkg}" version 2>/dev/null || echo "")
              failed="${failed}  - \`${pkg}@${version}\` (published: ${latest_ver:-none})\n"
            fi
          done

          {
            echo "published<<EOF"
            echo -e "$published"
            echo "EOF"
            echo "failed<<EOF"
            echo -e "$failed"
            echo "EOF"
          } >> "$GITHUB_OUTPUT"

      - name: Download binary artifacts
        uses: actions/download-artifact@v4
        with:
          pattern: cpd-binary-*
          path: release-assets
          merge-multiple: true
        continue-on-error: true

      - name: Create GitHub Release
        env:
          GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
        run: |
          version="${{ needs.version.outputs.version }}"
          tag="cpd-v${version}"

          notes="Rust-based cpd (jscpd) release v${version}

          ## Platform Packages
          Install via npm:
          \`\`\`bash
          npm install -g cpd
          \`\`\`

          ## Install jscpd (wrapper)
          \`\`\`bash
          npm install -g jscpd
          \`\`\`

          ## Install via Cargo
          \`\`\`bash
          cargo install jscpd
          \`\`\`

          The binary command is \`cpd\`."

          # Extract release notes from rust/CHANGELOG.md if available
          if [ -f rust/CHANGELOG.md ]; then
            changelog_notes=$(node -e "
              const fs = require('fs');
              const ver = process.argv[1];
              const changelog = fs.readFileSync('rust/CHANGELOG.md', 'utf8');
              const escaped = ver.replace(/\./g, '\\\\.');
              const re = new RegExp('^## .*' + escaped);
              const lines = changelog.split('\n');
              let found = false;
              const out = [];
              for (const line of lines) {
                if (!found && re.test(line)) { found = true; continue; }
                if (found && /^## /.test(line)) break;
                if (found && /^---$/.test(line)) break;
                if (found) out.push(line);
              }
              process.stdout.write(out.join('\n'));
            " "$version")
            if [ -n "$changelog_notes" ]; then
              notes="${changelog_notes}"
            fi
          fi

          # ── Append published packages info ──
          # Use single-quoted assignments so markdown backticks in package
          # names are not interpreted as command substitution.
          published='${{ steps.packages.outputs.published }}'
          failed='${{ steps.packages.outputs.failed }}'
          if [ -n "$published" ]; then
            notes="${notes}

          ## Published Packages

          ${published}"
          fi
          if [ -n "$failed" ]; then
            notes="${notes}

          ## Not Yet Published

          ${failed}"
          fi

          # Collect binary assets if they exist
          assets=""
          if [ -d release-assets ] && ls release-assets/*.tar.gz >/dev/null 2>&1; then
            for f in release-assets/*.tar.gz; do
              assets="$assets $f"
            done
          fi

          if [ -n "$assets" ]; then
            gh release create "${tag}" \
              --title "cpd v${version}" \
              --notes "${notes}" \
              $assets
          else
            gh release create "${tag}" \
              --title "cpd v${version}" \
              --notes "${notes}"
          fi