#!/usr/bin/env bash
#
# update-issue-progress.sh
#
# Synchronises the GitHub issue body's `### Progress` table with the run's
# state.flags. Idempotent  -  running twice with the same state produces the
# same body and a no-op edit.
#
# Replaces the python `update-issue-from-registry.py` referenced in the issue
# body comment legend. Same contract: the table is owned by the pipeline,
# never hand-edited.
#
# Usage:
#   update-issue-progress.sh <task-id>
#
# Inputs:
#   $HOME/.claude/logs/multi-agent/{project}/{taskId}/agent-state.json
#     .githubIssue.owner, .githubIssue.repo, .githubIssue.number
#     .flags.implementation, .flags.testing, .flags.codeConnect, .flags.wiki
#
# Side effects:
#   gh issue edit --body-file <updated body>
#
# Exit codes:
#   0 success (or no-op when body unchanged)
#   2 missing agent-state.json
#   3 missing required flags
#   4 GitHub edit failed

set -euo pipefail

# Rewrite the `### Progress` block of the body file ($2) with $1 and print the
# result to stdout. The replaced region is bounded at the FIRST of:
#   - a line starting with `<!--` (the legend comment, printed and kept), or
#   - the next heading line (^#, printed and kept), or
#   - EOF.
# Bounding at the next heading matters: bodies without the legend comment used
# to have everything from the table to EOF silently dropped and persisted.
rewrite_progress_body() {
  # Block passed via environment: BSD awk rejects literal newlines in -v
  # assignments ("newline in string"), so -v cannot carry the table.
  NEW_BLOCK_ENV="$1" awk '
    BEGIN { new_block = ENVIRON["NEW_BLOCK_ENV"] }
    BEGIN { in_progress = 0 }
    /^### Progress/ {
      print
      print ""
      print new_block
      print ""
      in_progress = 1
      next
    }
    in_progress && /^<!--/ { in_progress = 0; print; next }
    in_progress && /^#/    { in_progress = 0; print; next }
    in_progress { next }
    { print }
  ' "$2"
}

build_progress_block() {
  cat <<EOF
| Flag | State |
|---|---|
| Implementation | ${1} |
| Testing        | ${2} |
| Code Connect   | ${3} |
| Wiki           | ${4} |
EOF
}

TASK_ID="${1:-}"
if [ -z "$TASK_ID" ]; then
  echo "usage: update-issue-progress.sh <task-id>" >&2
  exit 64
fi

# Internal test seam: `--rewrite <body-file>` runs only the Progress-block
# rewrite (placeholder glyphs) and prints the result. No state, no gh.
if [ "$TASK_ID" = "--rewrite" ]; then
  BODY_IN="${2:-}"
  if [ -z "$BODY_IN" ] || [ ! -f "$BODY_IN" ]; then
    echo "usage: update-issue-progress.sh --rewrite <body-file>" >&2
    exit 64
  fi
  rewrite_progress_body "$(build_progress_block "pending" "pending" "pending" "pending")" "$BODY_IN"
  exit 0
fi

# Resolve agent-state.json. multi-repo-pipeline.sh writes it under a
# per-project directory ($HOME/.claude/logs/multi-agent/{project}/{taskId}/)
# - not the ~/.claude/projects/*/state/ path this used to glob, which no
# writer in the pipeline ever populates.
AGENT_STATE=""
for candidate in "$HOME"/.claude/logs/multi-agent/*/"$TASK_ID"/agent-state.json; do
  if [ -f "$candidate" ]; then
    AGENT_STATE="$candidate"
    break
  fi
done

if [ -z "$AGENT_STATE" ]; then
  echo "update-issue-progress: no agent-state.json found for task=$TASK_ID" >&2
  exit 2
fi

# agent-state.schema.json has no `.issue`/`.repos` properties (additionalProperties
# is false) - the real GitHub-issue coordinates live at `.githubIssue.{owner,repo,number}`.
ISSUE_NUM=$(jq -r '.githubIssue.number // empty' "$AGENT_STATE")
ORG_REPO=$(jq -r 'if .githubIssue then (.githubIssue.owner + "/" + .githubIssue.repo) else empty end' "$AGENT_STATE")

if [ -z "$ORG_REPO" ] || [ -z "$ISSUE_NUM" ]; then
  echo "update-issue-progress: no githubIssue in state for task=$TASK_ID (Jira-originated task, or issue not yet linked)" >&2
  exit 3
fi

# Read the four flags (default false).
F_IMPL=$(jq -r '.flags.implementation // false' "$AGENT_STATE")
F_TEST=$(jq -r '.flags.testing       // false' "$AGENT_STATE")
F_CC=$(jq   -r '.flags.codeConnect   // false' "$AGENT_STATE")
F_WIKI=$(jq -r '.flags.wiki          // false' "$AGENT_STATE")

# Each flag may be: true | false | "yellow" (validated against older impl).
glyph_for() {
  case "$1" in
    true)   echo "done" ;;
    yellow) echo "partial" ;;
    *)      echo "pending" ;;
  esac
}

G_IMPL=$(glyph_for "$F_IMPL")
G_TEST=$(glyph_for "$F_TEST")
G_CC=$(glyph_for "$F_CC")
G_WIKI=$(glyph_for "$F_WIKI")

# Fetch current body, replace the Progress table, write back.
TMP_BODY=$(mktemp /tmp/issue-progress-"${TASK_ID}"-XXXXXX.md)
trap 'rm -f "$TMP_BODY"' EXIT

gh issue view "$ISSUE_NUM" --repo "$ORG_REPO" --json body --jq .body > "$TMP_BODY"

# Build the new Progress block.
NEW_BLOCK=$(build_progress_block "$G_IMPL" "$G_TEST" "$G_CC" "$G_WIKI")

# Replace the table between `### Progress` and the first terminator (legend
# comment, next heading, or EOF)  -  see rewrite_progress_body above.
rewrite_progress_body "$NEW_BLOCK" "$TMP_BODY" > "${TMP_BODY}.new"

# Check if body actually changed (idempotent no-op).
if cmp -s "$TMP_BODY" "${TMP_BODY}.new"; then
  echo "update-issue-progress: no change for #$ISSUE_NUM (idempotent no-op)" >&2
  exit 0
fi

# Apply.
if ! gh issue edit "$ISSUE_NUM" --repo "$ORG_REPO" --body-file "${TMP_BODY}.new" >/dev/null; then
  echo "update-issue-progress: gh issue edit failed for #$ISSUE_NUM" >&2
  exit 4
fi

echo "update-issue-progress: updated #$ISSUE_NUM (Impl=$G_IMPL Test=$G_TEST CC=$G_CC Wiki=$G_WIKI)"
