#!/usr/bin/env bash
# cvloom pre-commit hook: block commits that introduce PII outside private/
#
# Scans the *added lines* of staged files for patterns that look like:
#   - email addresses
#   - phone numbers
#
# Two deliberate scoping rules keep this proportionate:
#
#   1. Only added lines are scanned, not whole files. A hook that re-scans
#      entire files fires on every commit that touches a file which has
#      always contained a placeholder, which trains you to pass --no-verify
#      reflexively — the exact habit that lets real PII through.
#
#   2. Values reserved for documentation and tests are allowed. Real contact
#      data never uses RFC 2606 / RFC 6761 reserved domains or the fictional
#      phone ranges, so matching them is a false positive by definition.
#
# Files inside private/ are intentionally excluded from scanning because
# they should already be gitignored. If a file inside private/ is staged,
# that itself is the problem and we block the commit immediately.

set -euo pipefail

RED='\033[0;31m'
YELLOW='\033[1;33m'
NC='\033[0m'

STAGED=$(git diff --cached --name-only --diff-filter=ACMR 2>/dev/null || true)

if [[ -z "$STAGED" ]]; then
  exit 0
fi

# 1. Block any file from private/ being staged at all.
PRIVATE_STAGED=$(echo "$STAGED" | grep -E '^private/' || true)
if [[ -n "$PRIVATE_STAGED" ]]; then
  echo -e "${RED}cvloom pre-commit: ERROR${NC}"
  echo "Files inside private/ must not be committed — they may contain PII."
  echo ""
  echo "Staged private files:"
  echo "$PRIVATE_STAGED" | sed 's/^/  /'
  echo ""
  echo "To fix: ensure 'private/' is in your .gitignore, then:"
  echo "  git rm --cached <file>"
  exit 1
fi

# 2. Scan added lines for PII patterns.
EMAIL_PATTERN='[a-zA-Z0-9._%+\-]+@[a-zA-Z0-9.\-]+\.[a-zA-Z]{2,}'
PHONE_PATTERN='(\+\d[\d \-()]{7,}\d|\(\d{3}\)\s*\d{3}[\- ]\d{4})'

# Reserved-for-documentation values (never real contact data):
#   RFC 2606 — example.com/.org/.net, .example, .test, .invalid
#   RFC 6761 — .localhost
EMAIL_ALLOW='@(example\.(com|org|net)|([a-zA-Z0-9\-]+\.)*(example|test|invalid|localhost))$'
#   NANP 555 exchange (North American fiction), Ofcom drama range (UK fiction)
PHONE_ALLOW='(\(555\)|[+ \-]555[ \-]|7700[ \-]?900)'

FOUND_PII=()

while IFS= read -r file; do
  [[ -z "$file" ]] && continue

  # Added lines only — strip the leading '+' and skip the '+++' file header.
  ADDED=$(git diff --cached -U0 --diff-filter=ACMR -- "$file" \
    | grep '^+' | grep -v '^+++' | cut -c2- || true)
  [[ -z "$ADDED" ]] && continue

  REAL_EMAILS=$(echo "$ADDED" | grep -oP "$EMAIL_PATTERN" 2>/dev/null \
    | grep -vP "$EMAIL_ALLOW" || true)
  if [[ -n "$REAL_EMAILS" ]]; then
    FOUND_PII+=("$file (email address: $(echo "$REAL_EMAILS" | head -3 | tr '\n' ' '))")
  fi

  REAL_PHONES=$(echo "$ADDED" | grep -oP "$PHONE_PATTERN" 2>/dev/null \
    | grep -vP "$PHONE_ALLOW" || true)
  if [[ -n "$REAL_PHONES" ]]; then
    FOUND_PII+=("$file (phone number: $(echo "$REAL_PHONES" | head -3 | tr '\n' ' '))")
  fi
done <<< "$STAGED"

if [[ ${#FOUND_PII[@]} -gt 0 ]]; then
  echo -e "${YELLOW}cvloom pre-commit: WARNING — possible PII in staged changes${NC}"
  echo ""
  echo "Added lines containing suspected PII:"
  for item in "${FOUND_PII[@]}"; do
    echo "  ✗ $item"
  done
  echo ""
  echo "If this is real contact information, move it to private/contact.yaml"
  echo "and reference it from your data files using the build system."
  echo ""
  echo "If it is a placeholder, prefer a reserved value the hook recognises:"
  echo "  email  someone@example.com     (also .example / .test / .invalid)"
  echo "  phone  +1 (555) 123-4567       (also UK +44 7700 900123)"
  echo ""
  echo "To bypass anyway:  git commit --no-verify"
  exit 1
fi

exit 0
