#!/usr/bin/env bash
# ayf-scan -- Lightweight project scanner
# Detects stack, installed tools, existing config, and suggests optimizations.
# Runs during install and available standalone via: ayf scan
#
# Works on macOS, Linux, Windows (Git Bash)

set -euo pipefail

PROJECT_DIR="${1:-$(pwd)}"

# Colors
if [[ -t 1 ]] && [[ "${TERM:-dumb}" != "dumb" ]]; then
  GREEN='\033[0;32m'; YELLOW='\033[1;33m'; BLUE='\033[0;34m'
  CYAN='\033[0;36m'; BOLD='\033[1m'; DIM='\033[2m'; NC='\033[0m'
else
  GREEN=''; YELLOW=''; BLUE=''; CYAN=''; BOLD=''; DIM=''; NC=''
fi

ok()   { echo -e "  ${GREEN}+${NC} $1"; }
info() { echo -e "  ${BLUE}>${NC} $1"; }
warn() { echo -e "  ${YELLOW}!${NC} $1"; }
dim()  { echo -e "  ${DIM}  $1${NC}"; }

# Output JSON for programmatic use
JSON_OUT=""
json_set() { JSON_OUT="${JSON_OUT}\"$1\":$2,"; }
json_set_str() { JSON_OUT="${JSON_OUT}\"$1\":\"$2\","; }
json_set_arr() { JSON_OUT="${JSON_OUT}\"$1\":[$2],"; }

# ── Language & Stack Detection ──────────────────────────────────────────────

detect_stack() {
  local langs="" frameworks="" pkg_manager=""

  # JavaScript/TypeScript
  if [[ -f "$PROJECT_DIR/package.json" ]]; then
    langs="$langs,typescript,javascript"
    pkg_manager="npm"
    [[ -f "$PROJECT_DIR/bun.lockb" ]] && pkg_manager="bun"
    [[ -f "$PROJECT_DIR/pnpm-lock.yaml" ]] && pkg_manager="pnpm"
    [[ -f "$PROJECT_DIR/yarn.lock" ]] && pkg_manager="yarn"

    local pkg
    pkg=$(cat "$PROJECT_DIR/package.json" 2>/dev/null)

    # Frameworks
    echo "$pkg" | grep -q '"next"' && frameworks="$frameworks,nextjs"
    echo "$pkg" | grep -q '"react"' && frameworks="$frameworks,react"
    echo "$pkg" | grep -q '"vue"' && frameworks="$frameworks,vue"
    echo "$pkg" | grep -q '"svelte"' && frameworks="$frameworks,svelte"
    echo "$pkg" | grep -q '"express"' && frameworks="$frameworks,express"
    echo "$pkg" | grep -q '"fastify"' && frameworks="$frameworks,fastify"
    echo "$pkg" | grep -q '"hono"' && frameworks="$frameworks,hono"
    echo "$pkg" | grep -q '"@supabase"' && frameworks="$frameworks,supabase"
    echo "$pkg" | grep -q '"stripe"' && frameworks="$frameworks,stripe"
    echo "$pkg" | grep -q '"prisma"' && frameworks="$frameworks,prisma"
    echo "$pkg" | grep -q '"drizzle"' && frameworks="$frameworks,drizzle"
    echo "$pkg" | grep -q '"vitest"' && frameworks="$frameworks,vitest"
    echo "$pkg" | grep -q '"jest"' && frameworks="$frameworks,jest"
    echo "$pkg" | grep -q '"playwright"' && frameworks="$frameworks,playwright"
    echo "$pkg" | grep -q '"turborepo"' && frameworks="$frameworks,turborepo"
    echo "$pkg" | grep -q '"turbo"' && frameworks="$frameworks,turborepo"
  fi

  # Python
  [[ -f "$PROJECT_DIR/pyproject.toml" || -f "$PROJECT_DIR/setup.py" || -f "$PROJECT_DIR/requirements.txt" ]] && langs="$langs,python"
  [[ -f "$PROJECT_DIR/pyproject.toml" ]] && grep -q "django" "$PROJECT_DIR/pyproject.toml" 2>/dev/null && frameworks="$frameworks,django"
  [[ -f "$PROJECT_DIR/pyproject.toml" ]] && grep -q "fastapi" "$PROJECT_DIR/pyproject.toml" 2>/dev/null && frameworks="$frameworks,fastapi"
  [[ -f "$PROJECT_DIR/pyproject.toml" ]] && grep -q "flask" "$PROJECT_DIR/pyproject.toml" 2>/dev/null && frameworks="$frameworks,flask"

  # Rust
  [[ -f "$PROJECT_DIR/Cargo.toml" ]] && langs="$langs,rust"

  # Go
  [[ -f "$PROJECT_DIR/go.mod" ]] && langs="$langs,go"

  # Ruby
  [[ -f "$PROJECT_DIR/Gemfile" ]] && langs="$langs,ruby"
  [[ -f "$PROJECT_DIR/Gemfile" ]] && grep -q "rails" "$PROJECT_DIR/Gemfile" 2>/dev/null && frameworks="$frameworks,rails"

  # PHP
  [[ -f "$PROJECT_DIR/composer.json" ]] && langs="$langs,php"
  [[ -f "$PROJECT_DIR/composer.json" ]] && grep -q "laravel" "$PROJECT_DIR/composer.json" 2>/dev/null && frameworks="$frameworks,laravel"

  # Java/Kotlin
  [[ -f "$PROJECT_DIR/pom.xml" || -f "$PROJECT_DIR/build.gradle" || -f "$PROJECT_DIR/build.gradle.kts" ]] && langs="$langs,java"

  # Clean leading commas
  langs="${langs#,}"
  frameworks="${frameworks#,}"

  echo "$langs|$frameworks|$pkg_manager"
}

# ── Project Structure Detection ─────────────────────────────────────────────

detect_structure() {
  local structure="single"

  # Monorepo detection
  [[ -f "$PROJECT_DIR/turbo.json" ]] && structure="monorepo-turborepo"
  [[ -f "$PROJECT_DIR/lerna.json" ]] && structure="monorepo-lerna"
  [[ -f "$PROJECT_DIR/nx.json" ]] && structure="monorepo-nx"
  [[ -f "$PROJECT_DIR/pnpm-workspace.yaml" ]] && structure="monorepo-pnpm"
  [[ -d "$PROJECT_DIR/packages" && -d "$PROJECT_DIR/apps" ]] && structure="monorepo"

  # Multi-service
  [[ -f "$PROJECT_DIR/docker-compose.yml" || -f "$PROJECT_DIR/docker-compose.yaml" ]] && structure="multi-service"

  echo "$structure"
}

# ── Installed Tools Detection ───────────────────────────────────────────────

detect_tools() {
  local tools=""

  # RTK (token optimizer)
  command -v rtk &>/dev/null && tools="$tools,rtk"

  # sheal (session intelligence)
  command -v sheal &>/dev/null && tools="$tools,sheal"

  # gstack
  [[ -d "$HOME/.claude/skills/gstack" ]] && tools="$tools,gstack"

  # GSD (get-shit-done)
  ls "$HOME/.claude/skills/gsd-"* &>/dev/null 2>&1 && tools="$tools,gsd"

  # ay-framework
  [[ -d "$PROJECT_DIR/.ay" ]] && tools="$tools,ay-framework"

  # Git
  command -v git &>/dev/null && tools="$tools,git"

  # Docker
  command -v docker &>/dev/null && tools="$tools,docker"

  # Claude Code
  command -v claude &>/dev/null && tools="$tools,claude-code"

  # Cursor
  command -v cursor &>/dev/null && tools="$tools,cursor"

  # Gemini CLI
  command -v gemini &>/dev/null && tools="$tools,gemini-cli"

  tools="${tools#,}"
  echo "$tools"
}

# ── Existing Config Detection ───────────────────────────────────────────────

detect_config() {
  local configs=""

  [[ -f "$PROJECT_DIR/CLAUDE.md" ]] && configs="$configs,CLAUDE.md"
  [[ -f "$PROJECT_DIR/.cursorrules" ]] && configs="$configs,.cursorrules"
  [[ -f "$PROJECT_DIR/.cursorindexingignore" ]] && configs="$configs,.cursorindexingignore"
  [[ -d "$PROJECT_DIR/.claude" ]] && configs="$configs,.claude/"
  [[ -d "$PROJECT_DIR/.claude/commands" ]] && configs="$configs,commands"
  [[ -d "$PROJECT_DIR/.claude/skills" ]] && configs="$configs,skills"
  [[ -d "$PROJECT_DIR/.claude/hooks" ]] && configs="$configs,hooks"
  [[ -d "$PROJECT_DIR/.claude/agents" ]] && configs="$configs,agents"
  [[ -f "$PROJECT_DIR/.claude/settings.json" ]] && configs="$configs,settings.json"
  [[ -d "$PROJECT_DIR/.ay" ]] && configs="$configs,.ay/"

  configs="${configs#,}"
  echo "$configs"
}

# ── Size & Git Info ─────────────────────────────────────────────────────────

detect_size() {
  local file_count=0 dir_count=0 contributors=0 last_commit=""

  file_count=$(find "$PROJECT_DIR" -maxdepth 3 -type f -not -path '*/node_modules/*' -not -path '*/.git/*' -not -path '*/dist/*' -not -path '*/.next/*' 2>/dev/null | wc -l | tr -d ' ')
  dir_count=$(find "$PROJECT_DIR" -maxdepth 2 -type d -not -path '*/node_modules/*' -not -path '*/.git/*' 2>/dev/null | wc -l | tr -d ' ')

  if [[ -d "$PROJECT_DIR/.git" ]]; then
    contributors=$(cd "$PROJECT_DIR" && git shortlog -sn --all 2>/dev/null | wc -l | tr -d ' ')
    last_commit=$(cd "$PROJECT_DIR" && git log -1 --format="%ar" 2>/dev/null || echo "unknown")
  fi

  echo "$file_count|$dir_count|$contributors|$last_commit"
}

# ── Optimization Suggestions ────────────────────────────────────────────────

suggest_optimizations() {
  local tools="$1" configs="$2" stack_info="$3"
  local suggestions=""

  local tool_str=" ${tools:-} "
  local config_str=" ${configs:-} "

  # RTK not installed
  if [[ ! "$tool_str" =~ "rtk" ]]; then
    suggestions="$suggestions|Install rtk for 60-90% token savings on CLI operations"
  fi

  # sheal not installed
  if [[ ! " $tool_str " =~ " sheal " ]]; then
    suggestions="$suggestions|Install sheal for session intelligence: npm install -g sheal"
  fi

  # No hooks
  if [[ ! " $config_str " =~ " hooks " ]]; then
    suggestions="$suggestions|Add Claude Code hooks for automated optimization"
  fi

  # No settings.json
  if [[ ! " $config_str " =~ " settings.json " ]]; then
    suggestions="$suggestions|Create .claude/settings.json with MCP servers for your stack"
  fi

  # No .ay
  if [[ ! " $config_str " =~ " .ay/ " ]]; then
    suggestions="$suggestions|Run ayf init to set up task tracking and coordination"
  fi

  # Stack-specific
  local langs="${stack_info%%|*}"
  if [[ "$langs" == *"typescript"* ]] && [[ ! " $config_str " =~ " .cursorrules " ]]; then
    suggestions="$suggestions|Add .cursorrules for Cursor IDE integration"
  fi

  suggestions="${suggestions#|}"
  echo "$suggestions"
}

# ── Env -> Service Detection (task 20) ──────────────────────────────────────

# Map a single detected service to its recommended MCP server name (or "" if
# there is no well-known MCP for it, e.g. raw LLM-provider keys).
service_mcp() {
  case "$1" in
    supabase) echo "supabase" ;;
    postgres) echo "postgres" ;;
    mysql)    echo "mysql" ;;
    github)   echo "github" ;;
    stripe)   echo "stripe" ;;
    vercel)   echo "vercel" ;;
    resend)   echo "resend" ;;
    *)        echo "" ;;   # openai / anthropic: keys, no standard MCP server
  esac
}

# Turn a comma-separated list into a JSON array body ("a","b"); empty -> "".
csv_json() {
  [[ -z "$1" ]] && { printf ''; return; }
  echo "$1" | tr ',' '\n' | sed 's/.*/"&"/' | paste -sd, -
}

# Read .env / .env.local / .env.example in PROJECT_DIR, map well-known key
# prefixes to service names, and derive recommended MCPs.
# Emits: "services_csv|mcps_csv"
detect_services() {
  local services="" mcps="" seen_svc=" " seen_mcp=" "
  local f path line key val svc mcp
  for f in .env .env.local .env.example; do
    path="$PROJECT_DIR/$f"
    [[ -f "$path" ]] || continue
    while IFS= read -r line || [[ -n "$line" ]]; do
      line="${line#"${line%%[![:space:]]*}"}"          # ltrim
      [[ -z "$line" || "$line" == \#* ]] && continue    # skip blanks/comments
      line="${line#export }"
      [[ "$line" != *=* ]] && continue                  # no key=value
      key="${line%%=*}"
      key="${key%%[[:space:]]*}"                         # drop trailing spaces
      val="${line#*=}"
      case "$key" in
        SUPABASE_*)  svc="supabase" ;;
        OPENAI_*)    svc="openai" ;;
        ANTHROPIC_*) svc="anthropic" ;;
        STRIPE_*)    svc="stripe" ;;
        RESEND_*)    svc="resend" ;;
        GITHUB_*)    svc="github" ;;
        VERCEL_*)    svc="vercel" ;;
        DATABASE_URL)
          if [[ "$val" == *mysql* ]]; then svc="mysql"; else svc="postgres"; fi ;;
        *) svc="" ;;
      esac
      [[ -z "$svc" ]] && continue
      if [[ "$seen_svc" != *" $svc "* ]]; then
        seen_svc="$seen_svc$svc "
        services="$services,$svc"
      fi
    done < "$path"
  done
  services="${services#,}"

  if [[ -n "$services" ]]; then
    local s
    IFS=',' read -ra _svcs <<< "$services"
    for s in "${_svcs[@]}"; do
      mcp="$(service_mcp "$s")"
      [[ -z "$mcp" ]] && continue
      if [[ "$seen_mcp" != *" $mcp "* ]]; then
        seen_mcp="$seen_mcp$mcp "
        mcps="$mcps,$mcp"
      fi
    done
  fi
  mcps="${mcps#,}"

  echo "$services|$mcps"
}

# Write .ay/detected-services.json = {services:[...], mcps:[...]}.
write_services_json() {
  local services="$1" mcps="$2" aydir="$PROJECT_DIR/.ay"
  mkdir -p "$aydir" 2>/dev/null || return 0
  printf '{\n  "services": [%s],\n  "mcps": [%s]\n}\n' \
    "$(csv_json "$services")" "$(csv_json "$mcps")" > "$aydir/detected-services.json"
}

# Human-readable services + recommended-MCP table.
print_services_human() {
  local services="$1" mcps="$2" s m
  echo -e "  ${BOLD}Detected Services${NC}"
  if [[ -n "$services" ]]; then
    IFS=',' read -ra _svcs <<< "$services"
    for s in "${_svcs[@]}"; do
      m="$(service_mcp "$s")"
      if [[ -n "$m" ]]; then
        ok "$s  ${DIM}-> MCP: $m${NC}"
      else
        ok "$s  ${DIM}(no standard MCP)${NC}"
      fi
    done
    [[ -n "$mcps" ]] && info "Recommended MCPs: $mcps"
  else
    warn "No services detected in .env / .env.local / .env.example"
  fi
  echo ""
}

# ── Main Output ─────────────────────────────────────────────────────────────

main() {
  local format="${2:-human}"

  # Env -> service detection (task 20). Computed in every mode.
  local services_raw services mcps
  services_raw=$(detect_services)
  IFS='|' read -r services mcps <<< "$services_raw"

  # `detect` mode: env -> services only (used by `ayf detect`).
  if [[ "$format" == "detect" ]]; then
    echo ""
    echo -e "  ${BOLD}${CYAN}Service Detection${NC}"
    echo "  ────────────────────────────────────────"
    echo ""
    print_services_human "$services" "$mcps"
    write_services_json "$services" "$mcps"
    return
  fi

  # Run all detectors
  local stack_raw tools configs structure size_raw
  stack_raw=$(detect_stack)
  tools=$(detect_tools)
  configs=$(detect_config)
  structure=$(detect_structure)
  size_raw=$(detect_size)

  IFS='|' read -r langs frameworks pkg_manager <<< "$stack_raw"
  IFS='|' read -r file_count dir_count contributors last_commit <<< "$size_raw"

  local suggestions
  suggestions=$(suggest_optimizations "$tools" "$configs" "$stack_raw")

  if [[ "$format" == "json" ]]; then
    # JSON output for programmatic use
    local langs_json frameworks_json tools_json configs_json suggestions_json

    langs_json=$(echo "$langs" | tr ',' '\n' | sed 's/.*/"&"/' | paste -sd, -)
    frameworks_json=$(echo "$frameworks" | tr ',' '\n' | sed 's/.*/"&"/' | paste -sd, -)
    tools_json=$(echo "$tools" | tr ',' '\n' | sed 's/.*/"&"/' | paste -sd, -)
    configs_json=$(echo "$configs" | tr ',' '\n' | sed 's/.*/"&"/' | paste -sd, -)
    suggestions_json=$(echo "$suggestions" | tr '|' '\n' | sed 's/.*/"&"/' | paste -sd, -)
    local services_json mcps_json
    services_json=$(csv_json "$services")
    mcps_json=$(csv_json "$mcps")

    cat <<ENDJSON
{
  "project": "$(basename "$PROJECT_DIR")",
  "path": "$PROJECT_DIR",
  "structure": "$structure",
  "languages": [${langs_json:-}],
  "frameworks": [${frameworks_json:-}],
  "package_manager": "${pkg_manager:-none}",
  "files": $file_count,
  "directories": $dir_count,
  "contributors": $contributors,
  "last_commit": "${last_commit:-never}",
  "tools_installed": [${tools_json:-}],
  "existing_config": [${configs_json:-}],
  "services": [${services_json:-}],
  "mcps": [${mcps_json:-}],
  "suggestions": [${suggestions_json:-}]
}
ENDJSON
    return
  fi

  # Human output
  echo ""
  echo -e "  ${BOLD}${CYAN}Project Scan${NC}"
  echo "  ────────────────────────────────────────"
  echo ""

  echo -e "  ${BOLD}Project${NC}"
  echo -e "  Name:          $(basename "$PROJECT_DIR")"
  echo -e "  Structure:     $structure"
  echo -e "  Files:         $file_count"
  [[ -n "$last_commit" && "$last_commit" != "unknown" ]] && echo -e "  Last commit:   $last_commit"
  [[ "$contributors" -gt 0 ]] && echo -e "  Contributors:  $contributors"
  echo ""

  if [[ -n "$langs" ]]; then
    echo -e "  ${BOLD}Stack${NC}"
    echo -e "  Languages:     $langs"
    [[ -n "$frameworks" ]] && echo -e "  Frameworks:    $frameworks"
    [[ -n "$pkg_manager" ]] && echo -e "  Pkg manager:   $pkg_manager"
    echo ""
  fi

  # Detected services from .env (task 20) + persist the machine-readable file.
  print_services_human "$services" "$mcps"
  write_services_json "$services" "$mcps"

  echo -e "  ${BOLD}Tools Installed${NC}"
  if [[ -n "$tools" ]]; then
    IFS=',' read -ra t <<< "$tools"
    for tool in "${t[@]}"; do
      ok "$tool"
    done
  else
    warn "No tools detected"
  fi
  echo ""

  echo -e "  ${BOLD}Existing Config${NC}"
  if [[ -n "$configs" ]]; then
    IFS=',' read -ra c <<< "$configs"
    for cfg in "${c[@]}"; do
      ok "$cfg"
    done
  else
    warn "No config files found"
  fi
  echo ""

  if [[ -n "$suggestions" ]]; then
    echo -e "  ${BOLD}Suggestions${NC}"
    IFS='|' read -ra s <<< "$suggestions"
    for suggestion in "${s[@]}"; do
      info "$suggestion"
    done
    echo ""
  fi
}

main "$@"
