#!/bin/bash
# List the comments on a GitHub pull request, with the id of each.
#
# Usage:
#   list-pr-comments.sh <pr-number>
#   list-pr-comments.sh <pr-number> --full
#
# Motivation: a comment that lands wrong can only be corrected in place by its
# id, and no other script here prints one. On PR #212 a posted comment carried a
# wrong figure; with no way to get the id, a second comment had to be posted
# instead of fixing the first. This script supplies the ids that
# edit-pr-comment.sh takes, and lets a caller see whether a comment is already
# there before posting another one.
#
# The default listing is one line per comment with a truncated preview. --full
# prints each body whole, from the same response, for reading a whole thread at
# once. To correct a comment, do not start here: get-pr-comment.sh <id> prints
# one body raw and is what --body-file takes back.
#
# Runs: gh api repos/{owner}/{repo}/issues/<pr-number>/comments
# gh expands {owner} and {repo} from the git remote of the current repository,
# so neither is hardcoded. These are the conversation comments on the PR; review
# comments attached to a diff line are a different endpoint and are not listed.

set -e

SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
# shellcheck source=lib.sh
source "$SCRIPT_DIR/lib.sh"

usage() {
    echo "Usage: $0 <pr-number> [--full]" >&2
}

PR_NUMBER="$1"
shift || true

if [ -z "$PR_NUMBER" ]; then
    echo "Error: Missing PR number" >&2
    usage
    exit 1
fi

case "$PR_NUMBER" in
    *[!0-9]*)
        echo "Error: PR number must be digits only (got: $PR_NUMBER)" >&2
        usage
        exit 1
        ;;
esac

FULL="false"
while [ -n "$1" ]; do
    case "$1" in
        --full)
            FULL="true"
            shift
            ;;
        *)
            echo "Error: unknown argument: $1" >&2
            usage
            exit 1
            ;;
    esac
done

if ! command -v gh &> /dev/null; then
    echo "Error: GitHub CLI (gh) is not installed" >&2
    echo "Install: https://cli.github.com/" >&2
    exit 1
fi

require_repo_context

# --paginate walks every page; --jq '.[]' streams the objects out of each page
# array and jq -s gathers them back into one array, so a PR with more than a
# page of comments is listed whole.
#
# The gh call is kept out of the pipe into jq on purpose. Piped, a failed call
# still fed jq an empty stream, jq happily returned [], and the script announced
# that a real PR had no comments and exited 0. An agent checking whether it had
# already commented would be told no and would post a duplicate. A failed call
# and an empty list are different answers and are now told apart: only a
# successful call that genuinely returned nothing reaches the empty case below.
if ! RAW_COMMENTS="$(gh api --paginate "repos/{owner}/{repo}/issues/$PR_NUMBER/comments" --jq '.[]')"; then
    echo "Error: could not read the comments on PR #$PR_NUMBER." >&2
    echo "gh reported the failure above. Nothing is known about this PR's comments;" >&2
    echo "do not take this as the PR having none." >&2
    exit 1
fi

COMMENTS="$(jq -s '.' <<< "$RAW_COMMENTS")"
COUNT="$(jq 'length' <<< "$COMMENTS")"

if [ "$COUNT" -eq 0 ]; then
    echo "PR #$PR_NUMBER has no comments."
    exit 0
fi

if [ "$FULL" = "true" ]; then
    jq -r '
      .[]
      | "=== comment \(.id)  \(.user.login)  \(.created_at) ===\n\(.body // "")\n"
    ' <<< "$COMMENTS"
    exit 0
fi

echo "PR #$PR_NUMBER has $COUNT comment(s)."
echo
printf '%-12s  %-18s  %-20s  %s\n' "ID" "AUTHOR" "CREATED" "PREVIEW"
jq -r '
  .[]
  | [ (.id | tostring),
      .user.login,
      .created_at,
      ( (.body // "")
        | gsub("\r"; "")
        | gsub("\n"; " ")
        | gsub(" +"; " ")
        | if (. | length) > 70 then .[0:67] + "..." else . end )
    ]
  | @tsv' <<< "$COMMENTS" \
| while IFS=$'\t' read -r id author created preview; do
    printf '%-12s  %-18s  %-20s  %s\n' "$id" "$author" "$created" "$preview"
done

echo
echo "Read the whole thread: $0 $PR_NUMBER --full"
echo "Correct one: get-pr-comment.sh <id> > f.md, change f.md, edit-pr-comment.sh <id> --body-file f.md"
