#!/usr/bin/env bash
# Regression: issue-view.sh must show comment BODIES, on both paths, and must name
# the failure tea actually reported instead of guessing a credential cause (#1357).
#
# Four defects, each with its own case below:
#   F1  tea exits 1 in any repo with extensions.worktreeconfig=true; the wrapper must
#       say so (git-config condition) and fall back to the API.
#   F2  the API fallback dumped raw issue JSON, which carries only a comment COUNT.
#   F3  the tea path never passed --comments, so tea prompted (non-interactively: nothing).
#   F4  on ANY tea failure the wrapper printed the REVOKED OR STALE TOKEN note.
#
# Verification bar (plan §6): assert a real comment BODY appears, not a count and not
# `grep -c comment` (that instrument matched the issue title and read inverted).
#
# Hermetic: mock tea and curl on PATH, sandboxed repo. Resolves no real credentials.
set -euo pipefail

WORK_ROOT="${AGENT_WORK_ROOT:-${TMPDIR:-/tmp}}"
SANDBOX="$WORK_ROOT/issue-view-comments-test-$$"
MOCK_BIN="$SANDBOX/bin"; REPO_DIR="$SANDBOX/repo"; CALLS="$SANDBOX/calls.log"
cleanup() { rm -rf "$SANDBOX"; }
trap cleanup EXIT

SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
TARGET="$SCRIPT_DIR/issue-view.sh"
[ -f "$TARGET" ] || { echo "FAIL: issue-view.sh not found beside this test"; exit 1; }
fail() { echo "FAIL: $*"; exit 1; }

mkdir -p "$MOCK_BIN" "$REPO_DIR" || fail "setup: cannot create sandbox under $WORK_ROOT"
: > "$CALLS"                     || fail "setup: cannot write calls log at $CALLS"
cd "$REPO_DIR"                   || fail "setup: cannot cd into $REPO_DIR"
git init -q                      || fail "setup: git init failed"
git remote add origin https://git.mosaicstack.dev/mosaicstack/stack.git || fail "setup: git remote add failed"
export PATH="$MOCK_BIN:$PATH" CALLS
export GITEA_URL="https://git.mosaicstack.dev"
export GITEA_TOKEN="redacted-test-token"
# The identity ladder must not reach for this seat's real login; the mock tea below
# defines the only login that exists in this sandbox.
unset MOSAIC_GIT_IDENTITY
# No fleet in the sandbox: on a host that runs one, get_gitea_token fails closed for an
# identity-less caller (by design), which would make this test measure the host, not
# the wrapper. An empty brain home makes the sandbox the same on every host.
export MOSAIC_BRAIN_HOME="$SANDBOX/brain"
mkdir -p "$MOSAIC_BRAIN_HOME" || fail "setup: cannot create sandbox brain home"

# Distinctive strings: a comment body that appears nowhere else, and an issue title
# that contains the word "comment" so a count-of-the-word instrument would misread.
BODY_MARKER="zebra-quill-comment-body-7731"
ISSUE_TITLE="wrapper never shows a comment"

# --- mock curl: serves the issue and its comments; logs every call --------------
cat > "$MOCK_BIN/curl" <<EOF
#!/bin/bash
url=""
while [ \$# -gt 0 ]; do
    case "\$1" in
        http*) url="\$1"; shift ;;
        *) shift ;;
    esac
done
printf 'curl %s\n' "\$url" >> "$CALLS"
case "\$url" in
    */issues/77/comments)
        if [ "\${MOCK_NO_COMMENTS:-}" = "1" ]; then echo '[]'; else
        echo '[{"id":1,"user":{"login":"alice"},"created_at":"2026-08-21T00:00:00Z","body":"$BODY_MARKER"}]'; fi ;;
    */issues/77)
        echo '{"number":77,"title":"$ISSUE_TITLE","state":"open","user":{"login":"bob"},"created_at":"2026-08-21T00:00:00Z","labels":[],"milestone":null,"html_url":"https://git.mosaicstack.dev/mosaicstack/stack/issues/77","body":"issue body","comments":1}' ;;
    *) echo '{}' ;;
esac
exit 0
EOF
chmod +x "$MOCK_BIN/curl"

# --- mock tea: MOCK_TEA_MODE selects the behaviour under test --------------------
#   ok         : prints the issue, and the comment body ONLY when --comments is passed (F3)
#   wtconfig   : exits 1 with the repositoryformatversion error (F1/F4)
#   badtoken   : exits 1 with tea's credential error (F4 control: credential wording allowed)
cat > "$MOCK_BIN/tea" <<EOF
#!/bin/bash
printf 'tea %s\n' "\$*" >> "$CALLS"
if [[ "\$*" == *"login list"* ]]; then
    echo '[{"name":"git.mosaicstack.dev","url":"https://git.mosaicstack.dev"}]'; exit 0
fi
case "\${MOCK_TEA_MODE:-ok}" in
    wtconfig) echo 'Error: core.repositoryformatversion does not support extension: worktreeconfig' >&2; exit 1 ;;
    badtoken) echo 'Failed to create Gitea client: invalid username, password or token' >&2; exit 1 ;;
esac
echo "# #77 $ISSUE_TITLE (open)"
echo "issue body"
if [[ "\$*" == *"--comments"* ]]; then echo "$BODY_MARKER"; fi
exit 0
EOF
chmod +x "$MOCK_BIN/tea"

[ "$(command -v tea)" = "$MOCK_BIN/tea" ]   || fail "setup: tea does not resolve inside the sandbox"
[ "$(command -v curl)" = "$MOCK_BIN/curl" ] || fail "setup: curl does not resolve inside the sandbox"

run() { bash "$TARGET" -i 77 >"$SANDBOX/out" 2>"$SANDBOX/err"; echo $?; }

# F3: tea path shows the comment body, which the mock emits only under --comments.
: > "$CALLS"
rc=$(MOCK_TEA_MODE=ok run)
[ "$rc" = 0 ] || fail "F3: expected rc=0 on the tea path, got $rc: $(cat "$SANDBOX/err")"
grep -q -- '--comments' "$CALLS"        || fail "F3: tea was not invoked with --comments: $(cat "$CALLS")"
grep -q "$BODY_MARKER" "$SANDBOX/out"   || fail "F3: comment body missing from tea-path output"
if grep -q '^curl' "$CALLS"; then fail "F3: tea path succeeded but the API fallback ran anyway"; fi

# F1 + F2: worktreeconfig failure is named as a git-config condition, falls back to
# the API, and the API rendering includes the comment BODY.
: > "$CALLS"
rc=$(MOCK_TEA_MODE=wtconfig run)
[ "$rc" = 0 ] || fail "F1: expected rc=0 via API fallback, got $rc: $(cat "$SANDBOX/err")"
grep -q 'worktreeconfig' "$SANDBOX/err" || fail "F1: stderr does not name the worktreeconfig cause: $(cat "$SANDBOX/err")"
grep -q 'not a credential problem' "$SANDBOX/err" || fail "F1: stderr does not rule out the credential cause"
grep -q 'issues/77/comments' "$CALLS"   || fail "F2: API fallback never fetched /comments: $(cat "$CALLS")"
grep -q "$BODY_MARKER" "$SANDBOX/out"   || fail "F2: comment body missing from API-path output"
grep -q "$ISSUE_TITLE" "$SANDBOX/out"   || fail "F2: issue title missing from API-path output"
if grep -q 'REVOKED OR STALE' "$SANDBOX/err"; then fail "F4: stale-token note printed for a git-config failure"; fi
if grep -q '"comments": 1' "$SANDBOX/out"; then fail "F2: output is still raw JSON (comment count instead of bodies)"; fi

# F4 control: a real credential error from tea may still carry the credential note,
# and tea's own line must be relayed so the reader sees the actual cause.
: > "$CALLS"
rc=$(MOCK_TEA_MODE=badtoken run)
[ "$rc" = 0 ] || fail "F4 control: expected rc=0 via API fallback, got $rc"
grep -q 'invalid username, password or token' "$SANDBOX/err" || fail "F4: tea's own error line was not relayed"
if grep -q 'worktreeconfig' "$SANDBOX/err"; then fail "F4: git-config wording printed for a credential failure"; fi

# Negative control: an issue with no comments prints no comment section on the API
# path. Without this, a renderer that always prints a section would pass F2.
: > "$CALLS"
rc=$(MOCK_TEA_MODE=wtconfig MOCK_NO_COMMENTS=1 run)
[ "$rc" = 0 ] || fail "negative control: expected rc=0, got $rc"
if grep -q -- '--- Comments' "$SANDBOX/out"; then fail "negative control: comment section printed for an issue with no comments"; fi
if grep -q "$BODY_MARKER" "$SANDBOX/out"; then fail "negative control: a comment body appeared for an issue with no comments"; fi

echo "issue-view comments regression harness passed"
