#!/usr/bin/env bash
# ==============================================================
#  kd — Kill Dev
# --------------------------------------------------------------
#  Author   : Kris Yotam (aka. khr1st)
#  Contact  : krisyotam@protonmail.com
#  License  : GNU GPLv3
#  Date     : 2026-03-25
# --------------------------------------------------------------
#  Description:
#    Kill dev servers and clean up stale lock files.
#    Detects Next.js, Vite, Webpack, Hugo, and other common
#    dev servers by process name and listening port.
# ==============================================================

set -eu

RED='\033[0;31m'
GREEN='\033[0;32m'
YELLOW='\033[0;33m'
BOLD='\033[1m'
RESET='\033[0m'

DEV_PORTS=(3000 3001 3080 3081 4000 4200 5000 5173 5174 8000 8080 8888)
DEV_PATTERNS=("next-server" "next dev" "vite" "webpack-dev" "hugo server" "gatsby" "nuxt" "remix" "astro" "turbopack")
LOCK_PATTERNS=(".next/dev/lock" ".next/server.lock")

usage() {
  cat <<EOF
${BOLD}kd${RESET} — kill dev servers

${BOLD}Usage:${RESET}
  kd                  Kill port 3000 + clean lock files (default)
  kd --port <port>    Kill a specific port
  kd --all            Find and kill all dev servers
  kd --clean          Remove stale lock files only
  kd --scan           Show running dev servers without killing
  kd --help           Show this help

${BOLD}Examples:${RESET}
  kd                  Quick kill 3000
  kd --port 5173      Kill Vite on 5173
  kd --all            Nuke everything
  kd --scan           See what's running
EOF
}

log() { printf "${GREEN}[kd]${RESET} %s\n" "$1"; }
warn() { printf "${YELLOW}[kd]${RESET} %s\n" "$1"; }
err() { printf "${RED}[kd]${RESET} %s\n" "$1"; }

kill_port() {
  local port="$1"
  local pids
  pids=$(fuser "$port/tcp" 2>/dev/null | tr -s ' ') || true

  if [ -z "$pids" ]; then
    warn "Nothing on port $port"
    return
  fi

  for pid in $pids; do
    local name
    name=$(ps -p "$pid" -o comm= 2>/dev/null || echo "unknown")
    log "Killing $name (PID $pid) on port $port"
    kill -9 "$pid" 2>/dev/null || true
  done
}

clean_locks() {
  local found=0
  # search common dev directories
  for dir in "$HOME"/dev/*/; do
    [ -d "$dir" ] || continue
    for pattern in "${LOCK_PATTERNS[@]}"; do
      local lockfile="$dir$pattern"
      if [ -f "$lockfile" ]; then
        rm -f "$lockfile"
        log "Removed $lockfile"
        found=1
      fi
    done
  done

  if [ "$found" -eq 0 ]; then
    warn "No stale lock files found"
  fi
}

scan_devs() {
  local found=0
  printf "${BOLD}%-8s %-8s %-20s %s${RESET}\n" "PORT" "PID" "PROCESS" "CMD"
  printf "%-8s %-8s %-20s %s\n" "----" "---" "-------" "---"

  for port in "${DEV_PORTS[@]}"; do
    local pids
    pids=$(fuser "$port/tcp" 2>/dev/null | tr -s ' ') || true
    [ -z "$pids" ] && continue

    for pid in $pids; do
      local name cmd
      name=$(ps -p "$pid" -o comm= 2>/dev/null || echo "unknown")
      cmd=$(ps -p "$pid" -o args= 2>/dev/null | head -c 60 || echo "")
      printf "%-8s %-8s %-20s %s\n" "$port" "$pid" "$name" "$cmd"
      found=1
    done
  done

  # also check for dev processes not on standard ports
  for pattern in "${DEV_PATTERNS[@]}"; do
    while IFS= read -r line; do
      local pid name
      pid=$(echo "$line" | awk '{print $1}')
      name=$(echo "$line" | awk '{for(i=2;i<=NF;i++) printf "%s ", $i; print ""}')
      # skip if we already found this pid above
      printf "%-8s %-8s %-20s %s\n" "?" "$pid" "${pattern}" "$name"
      found=1
    done < <(pgrep -af "$pattern" 2>/dev/null | grep -v "grep\|kd" || true)
  done

  if [ "$found" -eq 0 ]; then
    warn "No dev servers detected"
  fi
}

kill_all() {
  log "Scanning for dev servers..."

  # kill by known ports
  for port in "${DEV_PORTS[@]}"; do
    local pids
    pids=$(fuser "$port/tcp" 2>/dev/null | tr -s ' ') || true
    [ -z "$pids" ] && continue
    kill_port "$port"
  done

  # kill by process pattern
  for pattern in "${DEV_PATTERNS[@]}"; do
    local pids
    pids=$(pgrep -f "$pattern" 2>/dev/null | grep -v "$$" || true)
    [ -z "$pids" ] && continue

    for pid in $pids; do
      local name
      name=$(ps -p "$pid" -o comm= 2>/dev/null || echo "unknown")
      log "Killing $name (PID $pid) matching '$pattern'"
      kill -9 "$pid" 2>/dev/null || true
    done
  done

  clean_locks
  log "Done"
}

# --- main ---

case "${1:-}" in
  --port|-p)
    [ -z "${2:-}" ] && { err "Specify a port: kd --port 3000"; exit 1; }
    kill_port "$2"
    clean_locks
    ;;
  --all|-a)
    kill_all
    ;;
  --clean|-c)
    clean_locks
    ;;
  --scan|-s)
    scan_devs
    ;;
  --help|-h)
    usage
    ;;
  "")
    kill_port 3000
    clean_locks
    ;;
  *)
    # if it's a number, treat as port
    if [[ "$1" =~ ^[0-9]+$ ]]; then
      kill_port "$1"
      clean_locks
    else
      err "Unknown option: $1"
      usage
      exit 1
    fi
    ;;
esac
