#!/usr/bin/env bash
# CO-002 lint-substitute (Carve-Outs Register).
#
# Fails (exit 1) if any server-side .ts file contains a raw console.{log,info,
# warn,error,debug}() call that is NOT explicitly marked as an intentional
# carve-out by one of these markers within the two lines immediately preceding
# the call site:
#
#   // eslint-disable-next-line no-console
#   // CO-002: intentional raw console
#
# The CO-002 standard is: structured logging via the AegisLogger
# (server/lib/logger.ts) for every observability site. Direct console.* is
# reserved for the documented retirement-channel pattern and a handful of
# bootstrap/diagnostic carve-outs registered in the Carve-Outs Register
# (docs/regulatory/AEGIS_CYBER_LEGACY_CARVEOUTS.md).
#
# Run manually:
#   bash scripts/check-no-bare-console.sh
#
# Excluded:
#   - server/lib/logger.ts  (the logger itself owns the console.* sinks)
#   - non-server code (client/, shared/, scripts/, tests, *.config.*)

set -u

# Build the list of .ts files under server/ excluding the logger itself.
mapfile -t FILES < <(find server -type f -name "*.ts" ! -path "server/lib/logger.ts" | sort)

violations=0
violation_lines=""

for f in "${FILES[@]}"; do
  # Extract just the line numbers of every actual console.* call (excludes
  # comment-only mentions because grep matches the function-call shape).
  while IFS= read -r match_line; do
    [ -z "$match_line" ] && continue
    n="${match_line%%:*}"

    # Look at the two lines immediately above this call site.
    prev1=$(sed -n "$((n - 1))p" "$f" 2>/dev/null || true)
    prev2=$(sed -n "$((n - 2))p" "$f" 2>/dev/null || true)

    if echo "$prev1$prev2" | grep -Eq 'eslint-disable.*no-console|CO-002: intentional raw console'; then
      continue
    fi

    violations=$((violations + 1))
    violation_lines="$violation_lines\n$f:$n: $(sed -n "${n}p" "$f" | sed 's/^[[:space:]]*//')"
  done < <(grep -nE '^[[:space:]]*console\.(log|info|warn|error|debug)\(' "$f" 2>/dev/null || true)
done

if [ "$violations" -gt 0 ]; then
  echo "CO-002 regression detected — $violations bare console.* call site(s) in server/:"
  echo
  printf "%b\n" "$violation_lines"
  echo
  echo "Use the AegisLogger (server/lib/logger.ts) instead, e.g.:"
  echo "  import { logger } from \"./logger\";"
  echo "  const xLogger = logger.child(\"x\");"
  echo "  xLogger.info(\"...\"); xLogger.error(\"...\", { error: e });"
  echo
  echo "If the call site is an intentional carve-out (e.g. retirement-channel"
  echo "fallback that cannot route through the logger), add ONE of these"
  echo "markers on the line(s) immediately above the call:"
  echo "  // eslint-disable-next-line no-console"
  echo "  // CO-002: intentional raw console — <reason, e.g. FU-018 audit-log fallback>"
  exit 1
fi

count=$(grep -rE '^[[:space:]]*console\.(log|info|warn|error|debug)\(' server/ \
  --include='*.ts' \
  --exclude='logger.ts' \
  2>/dev/null | wc -l)
echo "CO-002 check passed — $count carved-out console.* site(s) in server/ all have CO-002 / no-console markers."
