name: Update CHANGELOG

on:
  workflow_dispatch:
    inputs:
      tag:
        description: Release tag to add to CHANGELOG.md
        required: true
        type: string
  release:
    types: [published]

jobs:
  build-changelog:
    runs-on: ubuntu-latest
    permissions:
      contents: read
    outputs:
      has_changes: ${{ steps.patch.outputs.has_changes }}
    steps:
      - uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0
        with:
          ref: main
          persist-credentials: false

      - name: Get release info and update CHANGELOG
        env:
          GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
          RELEASE_TAG: ${{ github.event.release.tag_name || inputs.tag }}
        run: |
          set -euo pipefail
          scripts/generate_changelog.sh \
            --repo "${{ github.repository }}" \
            --tag "$RELEASE_TAG" \
            --prepend-to CHANGELOG.md

      - name: Create changelog patch
        id: patch
        env:
          PATCH_PATH: ${{ runner.temp }}/changelog.patch
        run: |
          set -euo pipefail
          git add --intent-to-add -- CHANGELOG.md
          if git diff --quiet -- CHANGELOG.md; then
            echo "has_changes=false" >> "$GITHUB_OUTPUT"
            exit 0
          fi
          git diff --binary -- CHANGELOG.md > "$PATCH_PATH"
          echo "has_changes=true" >> "$GITHUB_OUTPUT"
      - name: Upload changelog patch
        if: steps.patch.outputs.has_changes == 'true'
        uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1
        with:
          name: changelog-patch
          path: ${{ runner.temp }}/changelog.patch
          if-no-files-found: error

  create-changelog-pr:
    needs: build-changelog
    if: needs.build-changelog.outputs.has_changes == 'true'
    runs-on: ubuntu-latest
    permissions:
      contents: read
    steps:
      - uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0
        with:
          ref: main
          fetch-depth: 0
          persist-credentials: false
      - name: Download changelog patch
        uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8.0.1
        with:
          name: changelog-patch
          path: ${{ runner.temp }}
      # Use the GitHub App token so branch and PR events run normal checks.
      - name: Create GitHub App token
        id: app-token
        uses: actions/create-github-app-token@bcd2ba49218906704ab6c1aa796996da409d3eb1 # v3.2.0
        with:
          app-id: ${{ secrets.GENERATED_DOCS_APP_ID }}
          private-key: ${{ secrets.GENERATED_DOCS_APP_PRIVATE_KEY }}
      - name: Create or update changelog PR
        env:
          GH_TOKEN: ${{ steps.app-token.outputs.token }}
          PATCH_PATH: ${{ runner.temp }}/changelog.patch
          TARGET_REPO: ${{ github.repository }}
          RELEASE_TAG: ${{ github.event.release.tag_name || inputs.tag }}
        run: |
          set -euo pipefail
          tag_name="$RELEASE_TAG"
          safe_tag="$(printf '%s' "$tag_name" | tr -c 'A-Za-z0-9._-' '-')"
          sync_branch="docs/changelog-${safe_tag}"

          git apply --index --whitespace=nowarn "$PATCH_PATH"
          if git diff --staged --quiet; then
            exit 0
          fi
          git config user.name "github-actions[bot]"
          git config user.email "github-actions[bot]@users.noreply.github.com"
          git commit -m "docs: update CHANGELOG.md for ${tag_name}"

          remote_url="https://x-access-token:${GH_TOKEN}@github.com/${TARGET_REPO}.git"
          remote_sha="$(git ls-remote --heads "$remote_url" "$sync_branch" | awk '{print $1}')"
          if [ -n "$remote_sha" ]; then
            git push --force-with-lease="refs/heads/${sync_branch}:${remote_sha}" \
              "$remote_url" \
              "HEAD:refs/heads/${sync_branch}"
          else
            git push "$remote_url" "HEAD:refs/heads/${sync_branch}"
          fi

          pr_body="$(mktemp)"
          cat > "$pr_body" <<EOF
          Updates CHANGELOG.md for ${tag_name}.

          This PR was created automatically after publishing ${GITHUB_EVENT_NAME} ${GITHUB_SHA}.
          EOF

          target_owner="${TARGET_REPO%%/*}"
          existing_pr="$(
            gh pr list \
              --repo "$TARGET_REPO" \
              --base main \
              --head "${target_owner}:${sync_branch}" \
              --state open \
              --json number \
              --jq '.[0].number // empty'
          )"

          if [ -n "$existing_pr" ]; then
            gh pr edit "$existing_pr" \
              --repo "$TARGET_REPO" \
              --title "Update CHANGELOG for ${tag_name}" \
              --body-file "$pr_body"
          else
            gh pr create \
              --repo "$TARGET_REPO" \
              --base main \
              --head "${target_owner}:${sync_branch}" \
              --title "Update CHANGELOG for ${tag_name}" \
              --body-file "$pr_body"
          fi
