#!/usr/bin/env bash
# output-quality-check.sh  -  runs all output validators against the latest
# task's artifacts (commit message, PR body, Jira comment) and reports a
# pass/fail summary suitable for pre-push gating.
#
# Validators (best-effort  -  skips silently when a target is absent):
#   1. Commit message format (regex from section15 of REFACTOR_PLAN_v3.7.md)
#   2. PR body  -  real newlines, no HTML entities, required sections present
#   3. Jira comment format  -  real newlines, no \n literal, no HTML entities
#   4. Reviewer JSON  -  runs validate-reviewer.mjs (already exists)
#   5. Triage JSON    -  runs validate-triage.mjs (already exists)
#
# Usage:
#   output-quality-check.sh [--task <task_id>] [--strict]
#
#   --task    target a specific task; otherwise picks latest from logs/
#   --strict  exit non-zero on any 'warn' (default: only 'fail' triggers exit 1)

set -uo pipefail

STRICT=false
TASK=""
while [ "$#" -gt 0 ]; do
  case "$1" in
    --strict) STRICT=true; shift ;;
    --task)   TASK="$2"; shift 2 ;;
    *) shift ;;
  esac
done

LOGS_ROOT="$HOME/.claude/logs/multi-agent"
PASS=0; WARN=0; FAIL=0
ok()   { PASS=$((PASS+1)); echo "  ✓ $1"; }
warn() { WARN=$((WARN+1)); echo "  ⚠ $1"; }
bad()  { FAIL=$((FAIL+1)); echo "  ✗ $1"; }

# Locate task dir
if [ -z "$TASK" ]; then
  TASK_DIR=$(ls -dt "$LOGS_ROOT"/*/*/ 2>/dev/null | head -1)
else
  TASK_DIR=$(find "$LOGS_ROOT" -type d -name "*$TASK*" 2>/dev/null | head -1)
fi
if [ -z "${TASK_DIR:-}" ] || [ ! -d "$TASK_DIR" ]; then
  warn "no task artifacts found in $LOGS_ROOT (run a task first)"
  echo ""
  echo "══ output-quality: ${PASS} pass, ${WARN} warn, ${FAIL} fail ══"
  exit 0
fi

echo "→ Target task dir: $TASK_DIR"

# 1. Commit message format
COMMIT_MSG="$TASK_DIR/.commit-message.txt"
if [ -f "$COMMIT_MSG" ]; then
  SUBJECT=$(head -1 "$COMMIT_MSG")
  if echo "$SUBJECT" | grep -qE "^(feat|fix|refactor|perf|test|docs|chore|style|revert)(\([a-z0-9_-]+\))?: .{1,60}( \[(#[0-9]+|[A-Z]+-[0-9]+)\])?$"; then
    ok "commit subject matches Conventional Commits format"
  else
    bad "commit subject malformed: $SUBJECT"
  fi
  if [ ${#SUBJECT} -gt 72 ]; then
    bad "commit subject > 72 chars (${#SUBJECT})"
  else
    ok "commit subject ≤ 72 chars"
  fi
else
  warn "no .commit-message.txt in task dir (skipped commit-format check)"
fi

# 2. PR body
PR_BODY="$TASK_DIR/.pr-body.md"
if [ -f "$PR_BODY" ]; then
  if grep -q '\\n' "$PR_BODY"; then
    bad "PR body contains literal \\n (use real newlines via heredoc)"
  else
    ok "PR body uses real newlines"
  fi
  if grep -qE '&amp;|&lt;|&gt;|&quot;' "$PR_BODY"; then
    bad "PR body contains HTML entities"
  else
    ok "PR body free of HTML entities"
  fi
  # Canonical section set is channels/pr.md's: summary -> changes ->
  # architecture (cond.) -> verification -> dependencies (cond.) -> related.
  # Headings render in outputLanguage, so match the always-required three by
  # either language rather than pinning English. "## How to Test" was the old
  # phase-6 template's heading and is not part of the canonical set.
  for sec in "Summary|Özet" "Changes|Değişiklikler" "Verification|Doğrulama"; do
    label="${sec%%|*}"
    grep -qE "^## ($sec)" "$PR_BODY" \
      && ok "PR body has '$label' section" \
      || warn "PR body missing '$label' section (canonical set: channels/pr.md)"
  done
  if grep -qE '^h[1-6]\. |\{\{[A-Za-z_]' "$PR_BODY"; then
    bad "PR body contains Jira wiki markup (h2./{{code}}) - PR bodies are Markdown"
  else
    ok "PR body free of Jira wiki markup"
  fi
else
  warn "no .pr-body.md in task dir (skipped PR-body check)"
fi

# 2b. Tracker tile titles
#
# `rules.md` forbids HTML entities in "titles, commit messages, task subjects, or
# body text", but this check only ever looked at the PR body and the Jira comment.
# Tile titles are task subjects, and that is where the rule actually broke: a real
# run rendered `Phase 1: Build &amp; Launch` in the TaskList widget. The rule was
# right and its enforcement was scoped to the wrong two surfaces.
#
# `phase-tracker.sh add` now decodes at the funnel, so this is the backstop that
# says so: an entity reaching the stored state means the funnel was bypassed.
TRACKER_STATE="$TASK_DIR/tracker-state.json"
if [ -f "$TRACKER_STATE" ]; then
  BAD_TITLES=$(python3 -c "
import json, re, sys
try:
    d = json.load(open('$TRACKER_STATE'))
except Exception:
    sys.exit(0)
# named, decimal and hex - a pattern covering only the named forms would miss
# exactly the two spellings the first version of the decoder missed.
pat = re.compile(r'&(amp|lt|gt|quot|apos|nbsp|mdash|ndash|hellip|#[0-9]+|#[xX][0-9a-fA-F]+);')
for p in d.get('phases', []):
    n = p.get('name', '')
    if pat.search(n):
        print('%s: %s' % (p.get('id'), n))
" 2>/dev/null)
  if [ -n "$BAD_TITLES" ]; then
    bad "tracker tile title(s) carry HTML entities (they render literally):"
    printf '%s\n' "$BAD_TITLES" | sed 's/^/      /'
  else
    ok "tracker tile titles free of HTML entities"
  fi
fi

# 3. Jira comment
JIRA_COMMENT="$TASK_DIR/.jira-comment.txt"
if [ -f "$JIRA_COMMENT" ]; then
  if grep -q '\\n' "$JIRA_COMMENT"; then
    bad "Jira comment contains literal \\n"
  else
    ok "Jira comment uses real newlines"
  fi
  if grep -qE '&amp;|&lt;|&gt;' "$JIRA_COMMENT"; then
    bad "Jira comment contains HTML entities"
  else
    ok "Jira comment free of HTML entities"
  fi
fi

# 4 + 5. Reviewer / Triage JSON validators (delegate to existing scripts)
for kind in reviewer triage; do
  for f in "$TASK_DIR/.review-${kind}-"*.json; do
    [ -f "$f" ] || continue
    if [ -f "$HOME/.claude/scripts/validate-${kind}.mjs" ]; then
      if node "$HOME/.claude/scripts/validate-${kind}.mjs" "$f" >/dev/null 2>&1; then
        ok "$kind JSON valid: $(basename "$f")"
      else
        bad "$kind JSON invalid: $(basename "$f")"
      fi
    fi
  done
done

echo ""
echo "══ output-quality: ${PASS} pass, ${WARN} warn, ${FAIL} fail ══"
if [ "$FAIL" -gt 0 ]; then exit 1; fi
if [ "$STRICT" = true ] && [ "$WARN" -gt 0 ]; then exit 1; fi
exit 0
