name: Add "status:"-label to PRs based on current state

on:
  workflow_run:
    workflows:
      - PR-Review submitted
    types: [completed]

permissions:
  pull-requests: write
  issues: write

jobs:
  review_update:
    runs-on: ubuntu-latest
    steps:
      - name: 'Download artifact'
        uses: actions/github-script@v8
        with:
          script: |
            let allArtifacts = await github.rest.actions.listWorkflowRunArtifacts({
               owner: context.repo.owner,
               repo: context.repo.repo,
               run_id: context.payload.workflow_run.id,
            });
            let matchArtifact = allArtifacts.data.artifacts.filter((artifact) => {
              return artifact.name == "review-event"
            })[0];
            let download = await github.rest.actions.downloadArtifact({
               owner: context.repo.owner,
               repo: context.repo.repo,
               artifact_id: matchArtifact.id,
               archive_format: 'zip',
            });
            const fs = require('fs');
            const path = require('path');
            const temp = '${{ runner.temp }}/artifacts';
            if (!fs.existsSync(temp)){
              fs.mkdirSync(temp);
            }
            fs.writeFileSync(path.join(temp, 'review-event.zip'), Buffer.from(download.data));

      - name: 'Unzip artifact'
        run: unzip "${{ runner.temp }}/artifacts/review-event.zip" -d "${{ runner.temp }}/artifacts"

      - name: Update status labels based on review
        uses: actions/github-script@v8
        with:
          script: |
            const fs = require('fs');
            const data = JSON.parse(fs.readFileSync('${{ runner.temp }}/artifacts/event.json', 'utf8'));

            const owner = data.repository.owner;
            const repo = data.repository.name;
            const prNumber = data.pull_request.number;
            const reviewState = data.review.state;
            const reviewBody = data.review.body;
            const R = data.review.reviewer;      // reviewer
            const P = data.pull_request.author;  // PR author
            const O = owner;                     // repo owner (by repo name)

            // 1. Remove all "status:[...]" labels
            const { data: existingLabels } = await github.rest.issues.listLabelsOnIssue({
              owner,
              repo,
              issue_number: prNumber
            })

            const statusLabels = existingLabels.filter(l => l.name.startsWith('status:'))
            for (const label of statusLabels) {
              await github.rest.issues.removeLabel({
                owner,
                repo,
                issue_number: prNumber,
                name: label.name
              }).catch(() => {}) // ignore if already removed
            }

            // 2. Determine new label
            let newLabel = null

            // https://github.com/Reviewable/Reviewable/issues/1163
            // other users cannot approve reviewers, requires permissions to actually say `reviewState == 'approved'`
            const is_approved = reviewState === 'approved' || reviewBody.includes("complete! all files reviewed, all discussions resolved")

            if (is_approved && R === O) {
              newLabel = 'status:approved'  // standard way of approval: owner appoves PR
            } else if (is_approved && P === O && R !== O) {
              newLabel = 'status:approved'  // if owner is author, someone else must approve
            } else if (P === R) {
              newLabel = 'status:waiting for review'
            } else if (P !== R) {
              newLabel = 'status:waiting for author'
            } else {
              core.info('No matching condition for new label.')
              core.info(`Review state: ${reviewState}, PR author: ${P}, Reviewer: ${R}, Repo owner: ${O}`)
            }

            if (newLabel) {
              await github.rest.issues.addLabels({
                owner,
                repo,
                issue_number: prNumber,
                labels: [newLabel]
              })
              core.info(`Added label: ${newLabel}`)
            } else {
              core.info('No new status label added.')
            }
