#!/bin/bash
# Edit an existing comment on a GitHub pull request, addressed by comment id.
#
# Usage:
#   edit-pr-comment.sh <comment-id> --body "<markdown body>"
#   edit-pr-comment.sh <comment-id> --body-file <path-to-markdown-file>
#
# Use --body-file for any body longer than a few lines — the file is read
# whole and sent as JSON, so shell quoting cannot mangle the markdown.
#
# Motivation: until this script existed a posted comment was final. On PR #212 a
# comment carried a wrong figure and had to be answered with a second comment,
# leaving the wrong number in place above the correction. Get the id from
# list-pr-comments.sh, then correct the comment itself.
#
# The comment is read back from GitHub after the write and compared to what was
# submitted; the script exits nonzero on any mismatch. That read-back is the
# reason this is a wrapper rather than a bare gh call: an edit reported as
# landed but actually mangled is worse than one that failed. See lib.sh.
#
# Runs: gh api --method PATCH repos/{owner}/{repo}/issues/comments/<comment-id>
# gh expands {owner} and {repo} from the git remote of the current repository,
# so neither is hardcoded. The endpoint covers conversation comments on a PR,
# which is what pr-comment.sh posts.

set -e

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

usage() {
    echo "Usage: $0 <comment-id> (--body \"<text>\" | --body-file <path>)" >&2
}

COMMENT_ID="$1"
shift || true

if [ -z "$COMMENT_ID" ]; then
    echo "Error: missing comment id" >&2
    echo "Get it from: list-pr-comments.sh <pr-number>" >&2
    usage
    exit 1
fi

case "$COMMENT_ID" in
    *[!0-9]*)
        echo "Error: the first argument must be a numeric comment id, got: $COMMENT_ID" >&2
        echo "A comment id is not a PR number; get it from list-pr-comments.sh <pr-number>." >&2
        usage
        exit 1
        ;;
esac

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

BODY=""
BODY_FILE=""

while [ -n "$1" ]; do
    case "$1" in
        --body)
            BODY="$2"
            if [ -z "$BODY" ]; then
                echo "Error: --body requires a non-empty value" >&2
                exit 1
            fi
            shift 2
            ;;
        --body-file)
            BODY_FILE="$2"
            if [ -z "$BODY_FILE" ] || [ ! -f "$BODY_FILE" ]; then
                echo "Error: --body-file requires a path to an existing file (got: ${BODY_FILE:-<empty>})" >&2
                exit 1
            fi
            shift 2
            ;;
        *)
            echo "Error: unknown argument: $1" >&2
            echo "The body is passed with --body or --body-file, never positionally." >&2
            usage
            exit 1
            ;;
    esac
done

if [ -n "$BODY" ] && [ -n "$BODY_FILE" ]; then
    echo "Error: --body and --body-file are mutually exclusive" >&2
    exit 1
fi

if [ -z "$BODY" ] && [ -z "$BODY_FILE" ]; then
    echo "Error: a comment body is required (--body or --body-file)" >&2
    usage
    exit 1
fi

if [ -n "$BODY_FILE" ]; then
    BODY="$(cat "$BODY_FILE")"
fi

# jq builds the JSON payload so the body reaches GitHub byte for byte, whatever
# quotes, backticks or newlines it carries. It is built into a variable rather
# than piped into gh: in a pipeline a failure in jq would leave gh reading an
# empty payload, and the pipeline's exit status is gh's, so a comment could be
# blanked by a call that looked like it worked.
PAYLOAD="$(jq -n --arg body "$BODY" '{body: $body}')"

if ! gh api --method PATCH "repos/{owner}/{repo}/issues/comments/$COMMENT_ID" \
        --input - \
        --jq '.html_url' <<< "$PAYLOAD"; then
    echo "Error: GitHub did not accept the edit of comment $COMMENT_ID." >&2
    echo "gh reported the failure above. Read the comment with" >&2
    echo "get-pr-comment.sh $COMMENT_ID to see what is actually there." >&2
    exit 1
fi

# Nothing below this line runs unless the read-back agrees with what was sent:
# verify_pr_comment_content returns nonzero on a mismatch and on a failed read
# alike, and set -e ends the script there, so the success line cannot be printed
# over an unverified edit.
verify_pr_comment_content "$COMMENT_ID" "$BODY"

echo "Read-back verified: comment $COMMENT_ID on GitHub matches the submitted body."
