#!/bin/bash
# agent-lint.sh — Audit agent configuration across all coding projects
#
# Usage:
#   agent-lint.sh                      # Scan all projects in ~/src/
#   agent-lint.sh --project <path>     # Scan single project
#   agent-lint.sh --json               # Output JSON for machine consumption
#   agent-lint.sh --verbose            # Show per-check details
#   agent-lint.sh --fix-hint           # Show fix commands for failures
#
# Checks per project:
#   1. Has runtime context file (CLAUDE.md or RUNTIME.md)?
#   2. Has AGENTS.md?
#   3. Runtime context file references conditional context/guides?
#   4. Runtime context file has quality gates?
#   5. For monorepos: sub-directories have AGENTS.md?

set -euo pipefail

# Defaults
SRC_DIR="$HOME/src"
SINGLE_PROJECT=""
JSON_OUTPUT=false
VERBOSE=false
FIX_HINT=false

# Exclusion patterns (not coding projects)
EXCLUDE_PATTERNS=(
  "_worktrees"
  ".backup"
  "_old"
  "_bak"
  "junk"
  "traefik"
  "infrastructure"
)

# Parse args
while [[ $# -gt 0 ]]; do
  case "$1" in
    --project) SINGLE_PROJECT="$2"; shift 2 ;;
    --json) JSON_OUTPUT=true; shift ;;
    --verbose) VERBOSE=true; shift ;;
    --fix-hint) FIX_HINT=true; shift ;;
    --src-dir) SRC_DIR="$2"; shift 2 ;;
    -h|--help)
      echo "Usage: agent-lint.sh [--project <path>] [--json] [--verbose] [--fix-hint] [--src-dir <dir>]"
      exit 0
      ;;
    *) echo "Unknown option: $1"; exit 1 ;;
  esac
done

# Colors (disabled for JSON mode)
if $JSON_OUTPUT; then
  GREEN="" RED="" YELLOW="" NC="" BOLD="" DIM=""
else
  GREEN='\033[0;32m' RED='\033[0;31m' YELLOW='\033[0;33m'
  NC='\033[0m' BOLD='\033[1m' DIM='\033[2m'
fi

# Determine if a directory is a coding project
is_coding_project() {
  local dir="$1"
  [[ -f "$dir/package.json" ]] || \
  [[ -f "$dir/pyproject.toml" ]] || \
  [[ -f "$dir/Cargo.toml" ]] || \
  [[ -f "$dir/go.mod" ]] || \
  [[ -f "$dir/Makefile" && -f "$dir/src/main.rs" ]] || \
  [[ -f "$dir/pom.xml" ]] || \
  [[ -f "$dir/build.gradle" ]]
}

# Check if directory should be excluded
is_excluded() {
  local dir_name
  dir_name=$(basename "$1")
  for pattern in "${EXCLUDE_PATTERNS[@]}"; do
    if [[ "$dir_name" == *"$pattern"* ]]; then
      return 0
    fi
  done
  return 1
}

# Detect if project is a monorepo
is_monorepo() {
  local dir="$1"
  [[ -f "$dir/pnpm-workspace.yaml" ]] || \
  [[ -f "$dir/turbo.json" ]] || \
  [[ -f "$dir/lerna.json" ]] || \
  (grep -q '"workspaces"' "$dir/package.json" 2>/dev/null)
}

# Resolve runtime context file (CLAUDE.md or RUNTIME.md)
runtime_context_file() {
  local dir="$1"
  if [[ -f "$dir/CLAUDE.md" ]]; then
    echo "$dir/CLAUDE.md"
    return
  fi
  if [[ -f "$dir/RUNTIME.md" ]]; then
    echo "$dir/RUNTIME.md"
    return
  fi
  echo ""
}

# Check for runtime context file
check_runtime_context() {
  [[ -n "$(runtime_context_file "$1")" ]]
}

# Check for AGENTS.md
check_agents_md() {
  [[ -f "$1/AGENTS.md" ]]
}

# Check conditional loading/context (references guides or conditional section)
check_conditional_loading() {
  local ctx
  ctx="$(runtime_context_file "$1")"
  [[ -n "$ctx" ]] && grep -qi "agent-guides\|~/.config/mosaic/guides\|conditional.*loading\|conditional.*documentation\|conditional.*context" "$ctx" 2>/dev/null
}

# Check quality gates
check_quality_gates() {
  local ctx
  ctx="$(runtime_context_file "$1")"
  [[ -n "$ctx" ]] && grep -qi "quality.gates\|must pass before\|lint\|typecheck\|test" "$ctx" 2>/dev/null
}

# Check monorepo sub-AGENTS.md
check_monorepo_sub_agents() {
  local dir="$1"
  local missing=()

  if ! is_monorepo "$dir"; then
    echo "N/A"
    return
  fi

  # Check apps/, packages/, services/, plugins/ directories
  for subdir_type in apps packages services plugins; do
    if [[ -d "$dir/$subdir_type" ]]; then
      for subdir in "$dir/$subdir_type"/*/; do
        [[ -d "$subdir" ]] || continue
        # Only check if it has its own manifest
        if [[ -f "$subdir/package.json" ]] || [[ -f "$subdir/pyproject.toml" ]]; then
          if [[ ! -f "$subdir/AGENTS.md" ]]; then
            missing+=("$(basename "$subdir")")
          fi
        fi
      done
    fi
  done

  if [[ ${#missing[@]} -eq 0 ]]; then
    echo "OK"
  else
    echo "MISS:${missing[*]}"
  fi
}

# Lint a single project
lint_project() {
  local dir="$1"
  local name
  name=$(basename "$dir")

  local has_runtime has_agents has_guides has_quality mono_status
  local score=0 max_score=4

  check_runtime_context "$dir" && has_runtime="OK" || has_runtime="MISS"
  check_agents_md "$dir" && has_agents="OK" || has_agents="MISS"
  check_conditional_loading "$dir" && has_guides="OK" || has_guides="MISS"
  check_quality_gates "$dir" && has_quality="OK" || has_quality="MISS"
  mono_status=$(check_monorepo_sub_agents "$dir")

  [[ "$has_runtime" == "OK" ]] && ((score++)) || true
  [[ "$has_agents" == "OK" ]] && ((score++)) || true
  [[ "$has_guides" == "OK" ]] && ((score++)) || true
  [[ "$has_quality" == "OK" ]] && ((score++)) || true

  if $JSON_OUTPUT; then
    cat <<JSONEOF
    {
      "project": "$name",
      "path": "$dir",
      "runtime_context": "$has_runtime",
      "agents_md": "$has_agents",
      "conditional_loading": "$has_guides",
      "quality_gates": "$has_quality",
      "monorepo_sub_agents": "$mono_status",
      "score": $score,
      "max_score": $max_score
    }
JSONEOF
  else
    # Color-code the status
    local c_runtime c_agents c_guides c_quality
    [[ "$has_runtime" == "OK" ]] && c_runtime="${GREEN}  OK  ${NC}" || c_runtime="${RED} MISS ${NC}"
    [[ "$has_agents" == "OK" ]] && c_agents="${GREEN}  OK  ${NC}" || c_agents="${RED} MISS ${NC}"
    [[ "$has_guides" == "OK" ]] && c_guides="${GREEN}  OK  ${NC}" || c_guides="${RED} MISS ${NC}"
    [[ "$has_quality" == "OK" ]] && c_quality="${GREEN}  OK  ${NC}" || c_quality="${RED} MISS ${NC}"

    local score_color="$RED"
    [[ $score -ge 3 ]] && score_color="$YELLOW"
    [[ $score -eq 4 ]] && score_color="$GREEN"

    printf "  %-35s %b %b %b %b  ${score_color}%d/%d${NC}" \
      "$name" "$c_runtime" "$c_agents" "$c_guides" "$c_quality" "$score" "$max_score"

    # Show monorepo status if applicable
    if [[ "$mono_status" != "N/A" && "$mono_status" != "OK" ]]; then
      printf "  ${YELLOW}(mono: %s)${NC}" "$mono_status"
    fi
    echo ""
  fi

  if $VERBOSE && ! $JSON_OUTPUT; then
    [[ "$has_runtime" == "MISS" ]] && echo "    ${DIM}  Runtime context file missing (CLAUDE.md or RUNTIME.md)${NC}"
    [[ "$has_agents" == "MISS" ]] && echo "    ${DIM}  AGENTS.md missing${NC}"
    [[ "$has_guides" == "MISS" ]] && echo "    ${DIM}  No conditional context/loading section detected${NC}"
    [[ "$has_quality" == "MISS" ]] && echo "    ${DIM}  No quality gates section${NC}"
    if [[ "$mono_status" == MISS:* ]]; then
      echo "    ${DIM}  Monorepo sub-AGENTS.md missing: ${mono_status#MISS:}${NC}"
    fi
  fi

  if $FIX_HINT && ! $JSON_OUTPUT; then
    if [[ "$has_runtime" == "MISS" || "$has_agents" == "MISS" ]]; then
      echo "    ${DIM}Fix: ~/.config/mosaic/tools/bootstrap/init-project.sh --name \"$name\" --type auto${NC}"
    elif [[ "$has_guides" == "MISS" ]]; then
      echo "    ${DIM}Fix: ~/.config/mosaic/tools/bootstrap/agent-upgrade.sh $dir --section conditional-loading${NC}"
    fi
  fi

  # Return score for summary
  echo "$score" > /tmp/agent-lint-score-$$
}

# Main
main() {
  local projects=()
  local total=0 passing=0 total_score=0

  if [[ -n "$SINGLE_PROJECT" ]]; then
    projects=("$SINGLE_PROJECT")
  else
    for dir in "$SRC_DIR"/*/; do
      [[ -d "$dir" ]] || continue
      is_excluded "$dir" && continue
      is_coding_project "$dir" && projects+=("${dir%/}")
    done
  fi

  if [[ ${#projects[@]} -eq 0 ]]; then
    echo "No coding projects found."
    exit 0
  fi

  if $JSON_OUTPUT; then
    echo '{ "audit_date": "'$(date -I)'", "projects": ['
    local first=true
    for dir in "${projects[@]}"; do
      $first || echo ","
      first=false
      lint_project "$dir"
    done
    echo '] }'
  else
    echo ""
    echo -e "${BOLD}Agent Configuration Audit — $(date +%Y-%m-%d)${NC}"
    echo "========================================================"
    printf "  %-35s %s  %s  %s  %s  %s\n" \
      "Project" "RUNTIME" "AGENTS" "Guides" "Quality" "Score"
    echo "  -----------------------------------------------------------------------"

    for dir in "${projects[@]}"; do
      lint_project "$dir"
      local score
      score=$(cat /tmp/agent-lint-score-$$ 2>/dev/null || echo 0)
      ((total++)) || true
      ((total_score += score)) || true
      [[ $score -eq 4 ]] && ((passing++)) || true
    done

    rm -f /tmp/agent-lint-score-$$

    echo "  -----------------------------------------------------------------------"
    local need_attention=$((total - passing))
    echo ""
    echo -e "  ${BOLD}Summary:${NC} $total projects | ${GREEN}$passing pass${NC} | ${RED}$need_attention need attention${NC}"
    echo ""

    if [[ $need_attention -gt 0 ]] && ! $FIX_HINT; then
      echo -e "  ${DIM}Run with --fix-hint for suggested fixes${NC}"
      echo -e "  ${DIM}Run with --verbose for per-check details${NC}"
      echo ""
    fi
  fi
}

main
