#!/usr/bin/env bash
# kj-tail — Real-time pipeline monitor for Karajan Code
# Follows the run log and displays colorized, filtered output.

set -euo pipefail

VERSION="1.38.0"

# ── Colors ──────────────────────────────────────────────
RED='\033[0;31m'
GREEN='\033[0;32m'
YELLOW='\033[0;33m'
BLUE='\033[0;34m'
CYAN='\033[0;36m'
MAGENTA='\033[0;35m'
GRAY='\033[0;90m'
BOLD='\033[1m'
DIM='\033[2m'
RESET='\033[0m'

# ── Defaults ────────────────────────────────────────────
VERBOSE=false
SHOW_AGENT_OUTPUT=false
SHOW_TIMESTAMPS=false
FOLLOW=true
NUM_LINES=0
PROJECT_DIR=""

# ── Help ────────────────────────────────────────────────
show_help() {
  cat <<EOF
${BOLD}kj-tail${RESET} — Real-time pipeline monitor for Karajan Code

${BOLD}USAGE${RESET}
  kj-tail [options] [project-dir]

${BOLD}DESCRIPTION${RESET}
  Follows the Karajan run log (<project>/.kj/run.log) and displays
  colorized, filtered output. By default shows the same pipeline
  progress view as 'kj run': stages, results, iterations, and errors.

  Run this in a separate terminal while kj executes via MCP/CLI.

${BOLD}OPTIONS${RESET}
  -v, --verbose       Show agent heartbeats, budget, and metadata
  -a, --agent-output  Show raw agent output lines (very noisy)
  -t, --timestamps    Show timestamps on each line
  -n, --lines <N>     Show last N lines then follow (default: follow only new)
  -s, --snapshot      Show current log (no follow) — like 'cat' with colors
  -h, --help          Show this help
  --version           Show version

${BOLD}EXAMPLES${RESET}
  kj-tail                  # Follow current directory's run log
  kj-tail /path/to/project # Follow a specific project's log
  kj-tail -v               # Verbose: include heartbeats and budget
  kj-tail -a               # Show everything including agent output
  kj-tail -n 50            # Show last 50 lines then follow
  kj-tail -s               # Snapshot: show full log and exit
  kj-tail -t               # Show timestamps

${BOLD}LOG LOCATION${RESET}
  <project-dir>/.kj/run.log
  Created automatically when kj_run, kj_code, or kj_review starts.

EOF
  exit 0
}

# ── Parse args ──────────────────────────────────────────
while [[ $# -gt 0 ]]; do
  case "$1" in
    -h|--help) show_help ;;
    --version) echo "kj-tail $VERSION"; exit 0 ;;
    -v|--verbose) VERBOSE=true; shift ;;
    -a|--agent-output) SHOW_AGENT_OUTPUT=true; VERBOSE=true; shift ;;
    -t|--timestamps) SHOW_TIMESTAMPS=true; shift ;;
    -s|--snapshot) FOLLOW=false; shift ;;
    -n|--lines)
      shift
      NUM_LINES="${1:-50}"
      shift
      ;;
    -*)
      echo -e "${RED}Unknown option: $1${RESET}" >&2
      echo "Run 'kj-tail --help' for usage." >&2
      exit 1
      ;;
    *) PROJECT_DIR="$1"; shift ;;
  esac
done

PROJECT_DIR="${PROJECT_DIR:-$(pwd)}"
LOG_FILE="${PROJECT_DIR}/.kj/run.log"

# ── Locate log ──────────────────────────────────────────
# When the log does not exist yet, kj-tail stays open and polls until any
# `kj` / `kj_*` invocation creates it. Exit with Ctrl-C. This used to be a
# hard exit, which forced the user to time `kj-tail` start vs. the command;
# too easy to miss early lines. Follow-mode and snapshot mode both get this.
if [[ ! -f "$LOG_FILE" ]]; then
  if [[ "$FOLLOW" == "false" ]]; then
    # Snapshot mode (-s): nothing to print, say so and exit cleanly.
    echo -e "${YELLOW}No run log at ${LOG_FILE} yet.${RESET}"
    echo ""
    echo "The log is created when Karajan starts a pipeline — run any of:"
    echo "  kj run \"...\"    kj audit    kj code    kj review    kj plan"
    echo "  mcp__karajan-mcp__kj_run / kj_audit / kj_code / kj_review / kj_plan ..."
    echo ""
    exit 0
  fi

  echo -e "${YELLOW}Waiting for run log to appear at ${LOG_FILE}${RESET}"
  echo -e "${DIM}(It is created the moment you run any kj command that invokes the orchestrator or a role.${RESET}"
  echo -e "${DIM} Ctrl-C to stop waiting. Triggers: kj run/audit/code/review/plan/discover/triage/researcher/architect, or the same via MCP.)${RESET}"
  echo ""
  # Ensure parent dir exists so we can poll even on a fresh project
  mkdir -p "$(dirname "$LOG_FILE")" 2>/dev/null || true
  # Poll every 500ms until the file shows up (low CPU, visible responsiveness).
  # Cap at 4h (28800 ticks) to avoid infinite stuck monitors; after the cap we
  # exit 0 so tmux/screen panes don't linger as errors.
  tick=0
  while [[ ! -f "$LOG_FILE" ]]; do
    sleep 0.5
    tick=$((tick + 1))
    if (( tick >= 28800 )); then
      echo -e "${YELLOW}Still no run log after 4h — exiting. Re-run kj-tail when ready.${RESET}"
      exit 0
    fi
  done
  echo -e "${GREEN}Log appeared — streaming...${RESET}"
  echo ""
fi

# ── Filter & colorize ──────────────────────────────────
filter_line() {
  local line="$1"
  local ts=""
  local clean="$line"

  # Extract and optionally strip timestamp (HH:MM:SS.mmm)
  if [[ "$clean" =~ ^([0-9]{2}:[0-9]{2}:[0-9]{2}\.[0-9]{3})\ (.*) ]]; then
    ts="${BASH_REMATCH[1]}"
    clean="${BASH_REMATCH[2]}"
  fi

  # Skip noise in default mode
  if [[ "$VERBOSE" == "false" ]]; then
    # Skip agent heartbeats
    [[ "$clean" == *"[agent:heartbeat]"* ]] && return
    [[ "$clean" == *"heartbeat"* ]] && return
    # Skip budget lines
    [[ "$clean" == *"Budget:"* ]] && return
    # Skip agent raw output
    [[ "$clean" == *"[agent:output]"* ]] && return
    # Skip internal metadata
    [[ "$clean" == *"[agent:start]"* ]] && return
    [[ "$clean" == *"[agent:end]"* ]] && return
    # Skip noisy JSON dumps (system init, tool lists, etc.)
    [[ "${#clean}" -gt 500 ]] && return
  fi

  if [[ "$SHOW_AGENT_OUTPUT" == "false" ]]; then
    # Skip raw agent output (often JSON/stream data)
    [[ "$clean" == "{"* ]] && [[ "$clean" == *"}" ]] && return
    [[ "$clean" == *'"type":'* ]] && [[ "${#clean}" -gt 200 ]] && return
  fi

  # Build prefix
  local prefix=""
  if [[ "$SHOW_TIMESTAMPS" == "true" ]] && [[ -n "$ts" ]]; then
    prefix="${DIM}${ts}${RESET} "
  fi

  # ── Colorize by content ──────────────────────────────
  # Session markers
  if [[ "$clean" == "---"* ]]; then
    echo -e "${prefix}${BOLD}${CYAN}${clean}${RESET}"
    return
  fi

  # Stage: started/finished
  if [[ "$clean" == *"started"* ]] && [[ "$clean" == *"[kj_"* ]]; then
    echo -e "${prefix}${BOLD}${CYAN}▶ ${clean}${RESET}"
    return
  fi
  if [[ "$clean" == *"finished"* ]] && [[ "$clean" == *"[kj_"* ]]; then
    echo -e "${prefix}${BOLD}${GREEN}✓ ${clean}${RESET}"
    return
  fi

  # Iterations
  if [[ "$clean" == *"[iteration]"* ]] || [[ "$clean" == *"Iteration "* ]]; then
    echo -e "${prefix}${BOLD}${clean}${RESET}"
    return
  fi

  # Coder
  if [[ "$clean" == *"[coder"* ]] || [[ "$clean" == *"Coder"* ]]; then
    echo -e "${prefix}${GREEN}  ├─ 🔨 ${clean}${RESET}"
    return
  fi

  # Reviewer
  if [[ "$clean" == *"APPROVED"* ]]; then
    echo -e "${prefix}${GREEN}  ├─ ✅ ${clean}${RESET}"
    return
  fi
  if [[ "$clean" == *"REJECTED"* ]]; then
    echo -e "${prefix}${RED}  ├─ ❌ ${clean}${RESET}"
    return
  fi
  if [[ "$clean" == *"[reviewer"* ]]; then
    echo -e "${prefix}${YELLOW}  ├─ 👁️  ${clean}${RESET}"
    return
  fi

  # Solomon
  if [[ "$clean" == *"[solomon"* ]] || [[ "$clean" == *"Solomon"* ]]; then
    echo -e "${prefix}${MAGENTA}  ├─ ⚖️  ${clean}${RESET}"
    return
  fi

  # Sonar
  if [[ "$clean" == *"[sonar"* ]] || [[ "$clean" == *"SonarQube"* ]] || [[ "$clean" == *"Quality gate"* ]]; then
    echo -e "${prefix}${BLUE}  ├─ 🔍 ${clean}${RESET}"
    return
  fi

  # Tester
  if [[ "$clean" == *"[tester"* ]] || [[ "$clean" == *"Tester"* ]]; then
    echo -e "${prefix}${CYAN}  ├─ 🧪 ${clean}${RESET}"
    return
  fi

  # Security
  if [[ "$clean" == *"[security"* ]] || [[ "$clean" == *"Security"* ]]; then
    echo -e "${prefix}${CYAN}  ├─ 🔒 ${clean}${RESET}"
    return
  fi

  # Researcher
  if [[ "$clean" == *"[researcher"* ]] || [[ "$clean" == *"Researcher"* ]]; then
    echo -e "${prefix}${CYAN}  ├─ 🔬 ${clean}${RESET}"
    return
  fi

  # Architect
  if [[ "$clean" == *"[architect"* ]] || [[ "$clean" == *"Architect"* ]]; then
    echo -e "${prefix}${CYAN}  ├─ 🏗️  ${clean}${RESET}"
    return
  fi

  # Planner
  if [[ "$clean" == *"[planner"* ]] || [[ "$clean" == *"Planner"* ]]; then
    echo -e "${prefix}${CYAN}  ├─ 🧠 ${clean}${RESET}"
    return
  fi

  # Triage
  if [[ "$clean" == *"[triage"* ]] || [[ "$clean" == *"Triage"* ]]; then
    echo -e "${prefix}${CYAN}  ├─ 📋 ${clean}${RESET}"
    return
  fi

  # Audit
  if [[ "$clean" == *"[audit"* ]] || [[ "$clean" == *"Audit"* ]]; then
    echo -e "${prefix}${CYAN}  ├─ 📊 ${clean}${RESET}"
    return
  fi

  # Preflight
  if [[ "$clean" == *"[preflight"* ]] || [[ "$clean" == *"Preflight"* ]]; then
    echo -e "${prefix}${GRAY}  ├─ ⚙️  ${clean}${RESET}"
    return
  fi

  # Skills (addyosmani catalog + OpenSkills marketplace)
  if [[ "$clean" == *"[skills:"* ]] || [[ "$clean" == *"[skills]"* ]]; then
    # Highlight failures/unavailability in yellow, successes in magenta
    if [[ "$clean" == *"unavailable"* ]] || [[ "$clean" == *"would have used"* ]]; then
      echo -e "${prefix}${YELLOW}  ├─ 🎯 ${clean}${RESET}"
    else
      echo -e "${prefix}${MAGENTA}  ├─ 🎯 ${clean}${RESET}"
    fi
    return
  fi

  # TDD
  if [[ "$clean" == *"TDD"* ]] || [[ "$clean" == *"tdd"* ]]; then
    echo -e "${prefix}${GREEN}  ├─ 📋 ${clean}${RESET}"
    return
  fi

  # Errors / failures
  if [[ "$clean" == *"fail"*  || "$clean" == *"FAIL"* || "$clean" == *"error"* || "$clean" == *"ERROR"* ]]; then
    echo -e "${prefix}${RED}  ├─ ⚠️  ${clean}${RESET}"
    return
  fi

  # Standby / rate limit
  if [[ "$clean" == *"[standby]"* ]] || [[ "$clean" == *"standby"* ]] || [[ "$clean" == *"rate limit"* ]]; then
    echo -e "${prefix}${YELLOW}  ├─ ⏸️  ${clean}${RESET}"
    return
  fi

  # Model fallback
  if [[ "$clean" == *"not supported"* ]] || [[ "$clean" == *"retrying with"* ]]; then
    echo -e "${prefix}${YELLOW}  ├─ 🔄 ${clean}${RESET}"
    return
  fi

  # Result line
  if [[ "$clean" == *"Result:"* ]]; then
    echo -e "${prefix}${BOLD}${GREEN}🏁 ${clean}${RESET}"
    return
  fi

  # Budget (verbose only — already filtered above)
  if [[ "$clean" == *"Budget:"* ]]; then
    echo -e "${prefix}${GRAY}  ├─ 💰 ${clean}${RESET}"
    return
  fi

  # Agent heartbeat (verbose only)
  if [[ "$clean" == *"heartbeat"* ]] || [[ "$clean" == *"active —"* ]] || [[ "$clean" == *"elapsed"* ]]; then
    echo -e "${prefix}${GRAY}  ├─ • ${clean}${RESET}"
    return
  fi

  # Default
  echo -e "${prefix}  ├─ ${clean}"
}

# ── Header ──────────────────────────────────────────────
echo -e "${BOLD}${CYAN}kj-tail${RESET} ${DIM}v${VERSION} — ${LOG_FILE}${RESET}"
if [[ "$FOLLOW" == "true" ]]; then
  echo -e "${GRAY}Ctrl+C to stop${RESET}${VERBOSE:+ ${DIM}(verbose)${RESET}}"
fi
echo ""

# ── Run ─────────────────────────────────────────────────
if [[ "$FOLLOW" == "false" ]]; then
  # Snapshot mode: show full log and exit
  while IFS= read -r line; do
    filter_line "$line"
  done < "$LOG_FILE"
  exit 0
fi

if [[ "$NUM_LINES" -gt 0 ]]; then
  # Show last N lines then follow
  tail -n "$NUM_LINES" -F "$LOG_FILE" 2>/dev/null | while IFS= read -r line; do
    filter_line "$line"
  done
else
  # Follow only new lines
  tail -n 0 -F "$LOG_FILE" 2>/dev/null | while IFS= read -r line; do
    filter_line "$line"
  done
fi
