#!/usr/bin/env bash
# ============================================================================
# nightshift — unified CLI for autonomous-agent-nightshift
# ============================================================================
# Dispatches to bundled scripts and templates regardless of install path
# (git clone, npm global, Homebrew, or skill at ~/.claude/skills/).
# ============================================================================

set -euo pipefail

VERSION="1.5.2"
REPO_URL="https://github.com/noluyorAbi/autonomous-agent-nightshift"

# ---- Locate ROOT (where scripts/, templates/, docs/ live) ----
resolve_root() {
    # Explicit override
    if [ -n "${NIGHTSHIFT_ROOT:-}" ] && [ -f "$NIGHTSHIFT_ROOT/SKILL.md" ]; then
        echo "$NIGHTSHIFT_ROOT"; return
    fi
    # Resolve symlinks for the executable
    local src="${BASH_SOURCE[0]}"
    while [ -L "$src" ]; do
        local dir
        dir="$(cd -P "$(dirname "$src")" && pwd)"
        src="$(readlink "$src")"
        [[ $src != /* ]] && src="$dir/$src"
    done
    local script_dir
    script_dir="$(cd -P "$(dirname "$src")" && pwd)"

    # Walk up looking for SKILL.md
    local d="$script_dir"
    for _ in 1 2 3 4; do
        if [ -f "$d/SKILL.md" ]; then echo "$d"; return; fi
        d="$(dirname "$d")"
    done

    echo "ERROR: cannot locate nightshift install root (looked from $script_dir upward)" >&2
    echo "       set NIGHTSHIFT_ROOT to the install directory" >&2
    exit 1
}

ROOT="$(resolve_root)"
SCRIPTS="$ROOT/scripts"
TEMPLATES="$ROOT/templates"

# ---- Colors ----
# Use ANSI-C quoting ($'...') so vars contain real ESC bytes, not literal \033.
# This matters because `cat <<EOF` does NOT interpret backslash escapes — it
# outputs the variable contents byte-for-byte. With single-quoted '\033[1m',
# users would see literal "\033[1m" in help output instead of bold.
if [ -t 1 ]; then
    BOLD=$'\033[1m'; DIM=$'\033[2m'; NC=$'\033[0m'
    RED=$'\033[0;31m'; GREEN=$'\033[0;32m'; CYAN=$'\033[0;36m'
else
    BOLD=''; DIM=''; NC=''; RED=''; GREEN=''; CYAN=''
fi

# ---- Helpers ----
die() { echo -e "${RED}error:${NC} $*" >&2; exit 1; }
info() { echo -e "${CYAN}::${NC} $*"; }
ok() { echo -e "${GREEN}ok${NC} $*"; }

# ---- Update check ----
# Checks npm registry once per 24h. Caches result. Fails silent on network errors.
# Disable: NIGHTSHIFT_NO_UPDATE_CHECK=1
check_for_update() {
    [ -n "${NIGHTSHIFT_NO_UPDATE_CHECK:-}" ] && return 0
    # Skip in non-interactive contexts (CI, pipes)
    [ -t 1 ] || return 0

    local cache_dir="${XDG_CACHE_HOME:-$HOME/.cache}/nightshift"
    local cache_file="$cache_dir/latest-version"
    mkdir -p "$cache_dir" 2>/dev/null || return 0

    # Refresh cache if missing or older than 24h
    local age=86401
    if [ -f "$cache_file" ]; then
        local mtime
        mtime=$(stat -f %m "$cache_file" 2>/dev/null || stat -c %Y "$cache_file" 2>/dev/null || echo 0)
        age=$(( $(date +%s) - mtime ))
    fi

    if [ "$age" -gt 86400 ]; then
        local latest
        latest=$(curl -fsSL --max-time 3 https://registry.npmjs.org/autonomous-agent-nightshift/latest 2>/dev/null \
            | grep -o '"version":"[^"]*"' | head -1 | cut -d'"' -f4)
        if [ -n "$latest" ]; then
            echo "$latest" > "$cache_file"
        else
            # Network failed — touch cache to avoid retrying every run
            touch "$cache_file" 2>/dev/null || true
            return 0
        fi
    fi

    local latest
    latest=$(cat "$cache_file" 2>/dev/null)
    [ -z "$latest" ] && return 0

    # Compare semver (string compare works for X.Y.Z within same major)
    if [ "$latest" != "$VERSION" ] && version_lt "$VERSION" "$latest"; then
        cat >&2 <<EOF

${YELLOW:-}  ┌─ Update available${NC:-}
${YELLOW:-}  │  $VERSION → $latest${NC:-}
${YELLOW:-}  │  Run: ${BOLD:-}nightshift update${NC:-}${YELLOW:-} (or npm install -g autonomous-agent-nightshift)${NC:-}
${YELLOW:-}  └─ Silence: NIGHTSHIFT_NO_UPDATE_CHECK=1${NC:-}

EOF
    fi
}

# Returns 0 if $1 < $2 (semver). Pure bash.
version_lt() {
    [ "$1" = "$2" ] && return 1
    local left right
    IFS='.' read -ra left <<< "$1"
    IFS='.' read -ra right <<< "$2"
    for i in 0 1 2; do
        local l="${left[$i]:-0}" r="${right[$i]:-0}"
        # Strip non-numeric suffixes (e.g., "1.0.0-rc1" -> "1.0.0")
        l="${l%%[^0-9]*}"; r="${r%%[^0-9]*}"
        l="${l:-0}"; r="${r:-0}"
        if [ "$l" -lt "$r" ]; then return 0; fi
        if [ "$l" -gt "$r" ]; then return 1; fi
    done
    return 1
}

# ============================================================================
# Subcommands
# ============================================================================

cmd_init() {
    local name="${1:-feature}"
    local date_str
    date_str="$(date +%Y_%m_%d)"
    local todo="todo-${date_str}_${name}.md"

    [ -f "$todo" ] && die "$todo already exists"

    info "Bootstrapping nightshift in $(pwd)..."

    cp "$TEMPLATES/todo-template.md" "$todo"
    cp "$SCRIPTS/run-agent-loop.sh" ./run-agent-loop.sh
    cp "$SCRIPTS/start-nightshift.sh" ./start-nightshift.sh
    chmod +x ./run-agent-loop.sh ./start-nightshift.sh

    # Update TODO_FILE reference inside the runner
    if [ "$(uname)" = "Darwin" ]; then
        sed -i '' "s|TODO_FILE=\"todo-YYYY_MM_DD_name.md\"|TODO_FILE=\"$todo\"|" ./run-agent-loop.sh
    else
        sed -i "s|TODO_FILE=\"todo-YYYY_MM_DD_name.md\"|TODO_FILE=\"$todo\"|" ./run-agent-loop.sh
    fi

    # .gitignore additions
    if [ -f .gitignore ]; then
        grep -q "^\.agent-logs" .gitignore || echo ".agent-logs/" >> .gitignore
        grep -q "^\.claude_iterations" .gitignore || echo ".claude_iterations" >> .gitignore
    fi

    ok "Bootstrapped:"
    echo "  $todo                  (edit: add Implementation+Validation tasks)"
    echo "  run-agent-loop.sh      (edit: paste codebase context heredoc, set validation gate)"
    echo "  start-nightshift.sh    (no edits)"
    echo ""
    echo "Next:"
    echo "  1. \$EDITOR $todo"
    echo "  2. \$EDITOR run-agent-loop.sh    # CODEBASE_CONTEXT + run_full_validation()"
    echo "  3. ./start-nightshift.sh start"
    echo ""
    echo "Docs: $REPO_URL"
}

cmd_bulletproof_init() {
    local plan="${1:-BULLETPROOF-STEPS.md}"

    [ -f "$plan" ] && die "$plan already exists"

    info "Bootstrapping Bulletproof run in $(pwd)..."

    if [ -f "$ROOT/examples/bulletproof-steps-example.md" ]; then
        cp "$ROOT/examples/bulletproof-steps-example.md" "$plan"
    else
        cp "$TEMPLATES/todo-template.md" "$plan"
    fi
    cp "$SCRIPTS/nightshift-bulletproof.sh" ./nightshift-bulletproof.sh
    chmod +x ./nightshift-bulletproof.sh

    ok "Bootstrapped:"
    echo "  $plan                          (edit: add Step N entries)"
    echo "  nightshift-bulletproof.sh       (edit: PLAN_FILE, GITHUB_REPO, codebase context)"
    echo ""
    echo "Pre-flight needs: gh auth status + gh auth refresh -s repo"
}

cmd_start() {
    [ -x ./start-nightshift.sh ] || die "no ./start-nightshift.sh in cwd. Run 'nightshift init' first."
    ./start-nightshift.sh start
}

cmd_stop() {
    [ -x ./start-nightshift.sh ] || die "no ./start-nightshift.sh in cwd"
    ./start-nightshift.sh stop
}

cmd_status() {
    if [ -x ./start-nightshift.sh ]; then
        ./start-nightshift.sh status
    else
        die "no ./start-nightshift.sh in cwd"
    fi
}

cmd_tail() {
    [ -x ./start-nightshift.sh ] || die "no ./start-nightshift.sh in cwd"
    ./start-nightshift.sh tail
}

cmd_review() {
    local summary=".agent-logs/nightshift-summary.log"
    [ -f "$summary" ] || die "no $summary found. Has the run completed?"

    echo "${BOLD}=== Summary ===${NC}"
    tail -30 "$summary"
    echo ""
    echo "${BOLD}=== Review-flagged tasks ===${NC}"
    grep -E 'REVIEW|FAILED' todo-*.md 2>/dev/null || echo "  (none — clean run)"
    echo ""
    echo "${BOLD}=== Diff stat ===${NC}"
    git diff --stat 2>/dev/null || echo "  (not a git repo)"
    echo ""
    echo "${BOLD}=== Next steps ===${NC}"
    echo "  1. Read each REVIEW-flagged task body + .agent-logs/task-{N}.log"
    echo "  2. Spot-check screenshots: ls .agent-logs/screenshots/"
    echo "  3. Stage what you accept: git add -p"
    echo "  4. Commit: git commit"
}

cmd_resume() {
    [ -x ./start-nightshift.sh ] || die "no ./start-nightshift.sh in cwd"
    info "Resume protocol:"
    echo "  1. Diagnose why it stopped (iteration cap / rate limit / auth / dev-server)"
    echo "  2. Fix root cause"
    echo "  3. Optional: reset counter for fresh budget: echo '0' > .claude_iterations"
    echo "  4. ./start-nightshift.sh start"
    echo ""
    echo "Full protocol: $REPO_URL/blob/main/commands/nightshift-resume.md"
}

cmd_version() {
    echo "nightshift $VERSION"
    echo "Install root: $ROOT"
    echo "Repo: $REPO_URL"
}

cmd_update() {
    info "Detecting install channel..."

    # Detect how nightshift was installed
    local channel=""
    case "$ROOT" in
        */node_modules/autonomous-agent-nightshift*) channel="npm" ;;
        */Cellar/nightshift/*|*/homebrew/*) channel="brew" ;;
        *.claude/skills/*) channel="skill" ;;
        *.claude/plugins/marketplaces/*) channel="plugin" ;;
        *) channel="git" ;;
    esac

    info "Detected: $channel"
    echo ""

    case "$channel" in
        npm)
            info "Running: npm install -g autonomous-agent-nightshift@latest"
            npm install -g autonomous-agent-nightshift@latest
            ;;
        brew)
            info "Running: brew upgrade nightshift"
            brew upgrade nightshift || brew install --HEAD https://raw.githubusercontent.com/noluyorAbi/autonomous-agent-nightshift/main/Formula/nightshift.rb
            ;;
        skill|plugin|git)
            info "Pulling latest from git in $ROOT"
            git -C "$ROOT" pull --ff-only
            ;;
        *)
            die "Could not detect install channel. Re-install manually from: $REPO_URL"
            ;;
    esac

    ok "Updated. Run: nightshift version"
    # Invalidate update-check cache
    rm -f "${XDG_CACHE_HOME:-$HOME/.cache}/nightshift/latest-version" 2>/dev/null || true
}

cmd_help() {
    cat <<EOF
${BOLD}nightshift${NC} $VERSION — autonomous Claude Code agent runner

${BOLD}USAGE${NC}
  nightshift <command> [args]

${BOLD}COMMANDS${NC}
  ${GREEN}init${NC} [name]              Bootstrap a new nightshift in the current dir
  ${GREEN}bulletproof-init${NC} [plan]  Bootstrap a Bulletproof PR-sweep run
  ${GREEN}start${NC}                    Launch the configured run (detached)
  ${GREEN}stop${NC}                     Halt the running nightshift
  ${GREEN}status${NC}                   Is it alive? What task?
  ${GREEN}tail${NC}                     Follow the summary log
  ${GREEN}review${NC}                   Morning report: summary, REVIEW flags, diff
  ${GREEN}resume${NC}                   Diagnose + restart after a stop
  ${GREEN}help${NC} [cmd]               Show this help
  ${GREEN}version${NC}                  Print version + install root
  ${GREEN}update${NC}                   Self-update via detected install channel (npm/brew/git)

${BOLD}TYPICAL FLOW${NC}
  ${DIM}# Setup${NC}
  cd your-project
  nightshift init add-dark-mode
  \$EDITOR todo-*.md            ${DIM}# write tasks${NC}
  \$EDITOR run-agent-loop.sh    ${DIM}# paste codebase context, set validation gate${NC}

  ${DIM}# Launch${NC}
  nightshift start
  nightshift tail               ${DIM}# follow log${NC}

  ${DIM}# Sleep${NC}

  ${DIM}# Review${NC}
  nightshift status
  nightshift review
  git diff --stat
  git add -p && git commit

${BOLD}REQUIREMENTS${NC}
  claude CLI (https://docs.claude.com/en/docs/claude-code)
  bash 4+
  Your project's lint, type-check, test, build commands

${BOLD}DOCS${NC}
  $REPO_URL
  $ROOT/docs/01-playbook.md     ${DIM}(master guide)${NC}
  $ROOT/docs/07-cost-and-safety.md  ${DIM}(read before launching)${NC}

${BOLD}COST${NC}
  ~\$0.50/task (Sonnet)  ·  ~\$1.50/task (Opus)
  Default overnight run: \$8-50.  Always set MAX_ITERATIONS as your cost cap.
EOF
}

# ============================================================================
# Dispatch
# ============================================================================

main() {
    if [ $# -eq 0 ]; then
        cmd_help
        exit 0
    fi

    local cmd="$1"; shift || true

    # Run update check for most commands (skip for version/help/update itself
    # to avoid noise or recursion)
    case "$cmd" in
        version|--version|-v|help|--help|-h|""|update) ;;
        *) check_for_update ;;
    esac

    case "$cmd" in
        init)              cmd_init "$@" ;;
        bulletproof-init)  cmd_bulletproof_init "$@" ;;
        start)             cmd_start "$@" ;;
        stop)              cmd_stop "$@" ;;
        status)            cmd_status "$@" ;;
        tail)              cmd_tail "$@" ;;
        review)            cmd_review "$@" ;;
        resume)            cmd_resume "$@" ;;
        update|self-update) cmd_update ;;
        version|--version|-v) cmd_version ;;
        help|--help|-h|"") cmd_help ;;
        *)
            echo "Unknown command: $cmd" >&2
            echo "Run 'nightshift help' for available commands." >&2
            exit 1
            ;;
    esac
}

main "$@"
