#!/usr/bin/env bash
# =============================================================================
# Harness Docs Freshness Check
# =============================================================================
#
# PURPOSE:
#   Detects when a PR or commit contains architecture-significant changes but
#   does NOT include updates to harness documentation (.github/copilot-instructions.md, AGENTS.md,
#   ARCHITECTURE.md, specs, etc.). Prints a warning with remediation steps.
#
#   By default this is a soft gate (exits 0 with a warning). To make it a hard
#   gate that blocks merges, change EXIT_CODE_ON_WARNING to 1.
#
# USAGE:
#   ./check-harness-docs.sh [base-branch]
#
#   Examples:
#     ./check-harness-docs.sh              # compare against main
#     ./check-harness-docs.sh develop       # compare against develop
#
# INSTALLATION:
#   Option 1 -- CI check (GitHub Actions):
#     - name: Check harness docs freshness
#       run: bash templates/hooks/check-harness-docs.sh ${{ github.base_ref }}
#
#   Option 2 -- Pre-merge hook:
#     cp templates/hooks/check-harness-docs.sh .githooks/pre-merge
#     chmod +x .githooks/pre-merge
#     git config core.hooksPath .githooks
#
# CUSTOMIZATION:
#   - Set EXIT_CODE_ON_WARNING=1 to make this a hard gate
#   - Add project-specific doc paths to HARNESS_DOC_PATTERNS
#   - Adjust SIGNIFICANT_FILE_COUNT threshold for your project
#
# =============================================================================

set -euo pipefail

# ---------------------------------------------------------------------------
# Configuration
# ---------------------------------------------------------------------------
BASE_BRANCH="${1:-main}"
EXIT_CODE_ON_WARNING=0         # Set to 1 to block merges when docs are stale
SIGNIFICANT_FILE_COUNT=15      # Trigger warning if more than this many files changed

# ---------------------------------------------------------------------------
# Colors for output
# ---------------------------------------------------------------------------
RED='\033[0;31m'
YELLOW='\033[1;33m'
GREEN='\033[0;32m'
CYAN='\033[0;36m'
BOLD='\033[1m'
NC='\033[0m'

# ---------------------------------------------------------------------------
# State
# ---------------------------------------------------------------------------
warnings=()
harness_docs_changed=false

# ---------------------------------------------------------------------------
# Helper: record a detected significant change
# ---------------------------------------------------------------------------
add_warning() {
  warnings+=("$1")
}

# ---------------------------------------------------------------------------
# Get the list of changed files vs the base branch
# ---------------------------------------------------------------------------
if ! git rev-parse --is-inside-work-tree > /dev/null 2>&1; then
  echo -e "${RED}ERROR${NC}: Not inside a git repository."
  echo "  Run this script from within a git repository."
  exit 1
fi

# Ensure the base branch ref is available (needed in CI shallow clones)
if ! git rev-parse --verify "${BASE_BRANCH}" > /dev/null 2>&1; then
  # Try with origin/ prefix for CI environments
  if git rev-parse --verify "origin/${BASE_BRANCH}" > /dev/null 2>&1; then
    BASE_BRANCH="origin/${BASE_BRANCH}"
  else
    echo -e "${RED}ERROR${NC}: Base branch '${BASE_BRANCH}' not found."
    echo "  FIX: Fetch the base branch first:"
    echo "    git fetch origin ${1:-main}"
    exit 1
  fi
fi

MERGE_BASE=$(git merge-base "${BASE_BRANCH}" HEAD 2>/dev/null || echo "${BASE_BRANCH}")
CHANGED_FILES=$(git diff --name-only "${MERGE_BASE}" HEAD 2>/dev/null || true)

if [ -z "$CHANGED_FILES" ]; then
  echo -e "${GREEN}No changes detected vs ${BASE_BRANCH}. Nothing to check.${NC}"
  exit 0
fi

CHANGED_FILE_COUNT=$(echo "$CHANGED_FILES" | wc -l | tr -d ' ')

echo -e "${BOLD}Harness Docs Freshness Check${NC}"
echo -e "Base: ${CYAN}${BASE_BRANCH}${NC}  |  Changed files: ${CYAN}${CHANGED_FILE_COUNT}${NC}"
echo ""

# ---------------------------------------------------------------------------
# Check 1: Were any harness docs updated in this diff?
# ---------------------------------------------------------------------------
HARNESS_DOC_PATTERNS=(
  ".github/copilot-instructions.md"
  ".github/instructions/*.instructions.md"
  ".github/prompts/*.prompt.md"
  ".github/agents/*.md"
  "AGENTS.md"
  "ARCHITECTURE.md"
  "docs/*.md"
  "specs/*.md"
  # [CUSTOMIZE] Add project-specific doc paths below
  # "doc/*.md"
)

for pattern in "${HARNESS_DOC_PATTERNS[@]}"; do
  # Use grep with fnmatch-style matching
  if echo "$CHANGED_FILES" | grep -qiE "^${pattern//\*/[^/]*}$" 2>/dev/null; then
    harness_docs_changed=true
    break
  fi
  # Also check case-insensitive basename match for root-level docs
  if echo "$CHANGED_FILES" | grep -qi "$(basename "$pattern")" 2>/dev/null; then
    harness_docs_changed=true
    break
  fi
done

# ---------------------------------------------------------------------------
# Check 2: New top-level or second-level directories created
# ---------------------------------------------------------------------------
NEW_FILES=$(git diff --name-only --diff-filter=A "${MERGE_BASE}" HEAD 2>/dev/null || true)

if [ -n "$NEW_FILES" ]; then
  new_dirs=""
  while IFS= read -r file; do
    # Extract top-level directory
    top_dir=$(echo "$file" | cut -d'/' -f1)
    # Extract second-level path (e.g., src/newmodule)
    second_dir=$(echo "$file" | cut -d'/' -f1-2)

    # Check if this top-level dir is entirely new (no files existed before)
    if ! git ls-tree -r --name-only "${MERGE_BASE}" 2>/dev/null | grep -q "^${top_dir}/" 2>/dev/null; then
      new_dirs="${new_dirs}  - New top-level directory: ${top_dir}/\n"
    fi

    # Check second-level directories too
    if echo "$second_dir" | grep -q "/" 2>/dev/null; then
      if ! git ls-tree -r --name-only "${MERGE_BASE}" 2>/dev/null | grep -q "^${second_dir}/" 2>/dev/null; then
        new_dirs="${new_dirs}  - New directory: ${second_dir}/\n"
      fi
    fi
  done <<< "$NEW_FILES"

  if [ -n "$new_dirs" ]; then
    # Deduplicate
    unique_dirs=$(echo -e "$new_dirs" | sort -u)
    add_warning "New directories created:\n${unique_dirs}"
  fi
fi

# ---------------------------------------------------------------------------
# Check 3: Dependency files changed
# ---------------------------------------------------------------------------
DEP_FILES=(
  "package.json"
  "go.mod"
  "Cargo.toml"
  "pyproject.toml"
  "Gemfile"
  "Package.swift"
  "requirements.txt"
  "pom.xml"
  "build.gradle"
  "build.gradle.kts"
)

changed_deps=""
for dep_file in "${DEP_FILES[@]}"; do
  if echo "$CHANGED_FILES" | grep -q "${dep_file}" 2>/dev/null; then
    changed_deps="${changed_deps}  - ${dep_file}\n"
  fi
done

if [ -n "$changed_deps" ]; then
  add_warning "Dependency files changed:\n${changed_deps}"
fi

# ---------------------------------------------------------------------------
# Check 4: Entry point files changed
# ---------------------------------------------------------------------------
ENTRY_PATTERNS=(
  "main\."
  "index\."
  "app\."
  "routes\."
  "server\."
  "cmd/"
)

changed_entries=""
for pattern in "${ENTRY_PATTERNS[@]}"; do
  matches=$(echo "$CHANGED_FILES" | grep -E "(^|/)${pattern}" 2>/dev/null || true)
  if [ -n "$matches" ]; then
    while IFS= read -r match; do
      changed_entries="${changed_entries}  - ${match}\n"
    done <<< "$matches"
  fi
done

if [ -n "$changed_entries" ]; then
  add_warning "Entry point files changed:\n${changed_entries}"
fi

# ---------------------------------------------------------------------------
# Check 5: CI/CD configuration changed
# ---------------------------------------------------------------------------
changed_ci=""
ci_matches=$(echo "$CHANGED_FILES" | grep -E "^\.github/workflows/" 2>/dev/null || true)
ci_matches="${ci_matches}$(echo "$CHANGED_FILES" | grep -E "(Dockerfile|docker-compose|\.gitlab-ci|Jenkinsfile|\.circleci)" 2>/dev/null || true)"

if [ -n "$ci_matches" ]; then
  while IFS= read -r match; do
    [ -z "$match" ] && continue
    changed_ci="${changed_ci}  - ${match}\n"
  done <<< "$ci_matches"
fi

if [ -n "$changed_ci" ]; then
  add_warning "CI/CD configuration changed:\n${changed_ci}"
fi

# ---------------------------------------------------------------------------
# Check 6: High file count (broad change)
# ---------------------------------------------------------------------------
if [ "$CHANGED_FILE_COUNT" -gt "$SIGNIFICANT_FILE_COUNT" ]; then
  add_warning "Large change set: ${CHANGED_FILE_COUNT} files changed (threshold: ${SIGNIFICANT_FILE_COUNT})"
fi

# ---------------------------------------------------------------------------
# Results
# ---------------------------------------------------------------------------
echo ""

if [ ${#warnings[@]} -eq 0 ]; then
  echo -e "${GREEN}PASS${NC}: No architecture-significant changes detected."
  exit 0
fi

if [ "$harness_docs_changed" = true ]; then
  echo -e "${GREEN}PASS${NC}: Architecture-significant changes detected AND harness docs were updated."
  echo ""
  echo "Detected changes:"
  for warning in "${warnings[@]}"; do
    echo -e "  ${CYAN}*${NC} $(echo -e "$warning" | head -1)"
  done
  exit 0
fi

# Architecture-significant changes exist but no harness docs were updated
echo -e "${YELLOW}${BOLD}WARNING: Architecture-significant changes detected but no harness docs were updated.${NC}"
echo ""
echo -e "${BOLD}Detected changes:${NC}"
for warning in "${warnings[@]}"; do
  echo -e "  ${YELLOW}!${NC} $(echo -e "$warning")"
done

echo ""
echo -e "${BOLD}Harness docs that may need updating:${NC}"
echo "  - .github/copilot-instructions.md         (project overview, architecture section, tech stack)"
echo "  - ARCHITECTURE.md   (domain map, module boundaries, data flow)"
echo "  - AGENTS.md         (structure section, conventions)"
echo "  - docs/*.md         (relevant design docs or specs)"
echo ""
echo -e "${BOLD}Recommended action:${NC}"
echo "  Run the maintain-harness-docs playbook to update documentation:"
echo "    agent/playbooks/maintain-harness-docs.md"
echo ""
echo "  Or manually update the relevant docs in this same PR."
echo "  Principle: harness doc updates belong in the same PR as the feature."
echo ""

if [ "$EXIT_CODE_ON_WARNING" -eq 1 ]; then
  echo -e "${RED}This check is configured as a hard gate. Merge is blocked.${NC}"
  echo "  To proceed, update harness docs or set EXIT_CODE_ON_WARNING=0 to make this a soft gate."
  exit 1
else
  echo -e "${YELLOW}This is a soft warning (exit code 0). To make it a hard gate,${NC}"
  echo -e "${YELLOW}set EXIT_CODE_ON_WARNING=1 in this script.${NC}"
  exit 0
fi
