#!/usr/bin/env bash
set -euo pipefail

self="$(cd "$(dirname "$0")" && pwd)"

# ── Colors (auto-off when not a TTY) ───────────────────────────
if [ -t 1 ]; then
    BOLD=$(tput bold 2>/dev/null || true)
    CYAN=$(tput setaf 6 2>/dev/null || true)
    DIM=$(tput dim 2>/dev/null || true)
    RESET=$(tput sgr0 2>/dev/null || true)
else
    BOLD=""; CYAN=""; DIM=""; RESET=""
fi

# ── Collect available commands ─────────────────────────────────
_pos_commands() {
    local cmds=()
    local f
    for f in "$self"/pos-*; do
        [ -x "$f" ] || continue
        local name="${f##*/pos-}"
        cmds+=("$name")
    done
    echo "${cmds[*]}"
}

# ── Category list (sorted, filename-derived) ─────────────────────
# Nested sub-tools (pos-<cat>-<a>-<b> where pos-<cat>-<a> exists) are
# omitted from the cheat-sheet line — they are shown under their parent tool.
_pos_category_list() {
    local -A cats=()
    local cmd cat f
    for f in "$self"/pos-*; do
        [ -x "$f" ] || continue
        cmd="${f##*/pos-}"
        cat="${cmd%%-*}"
        [ "$cat" = "$cmd" ] && continue
        cats["$cat"]+="${cmd#*-} "
    done
    local c subs joined s s2 top=() is_nested
    for c in $(printf '%s\n' "${!cats[@]}" | sort); do
        subs=(${cats[$c]})
        top=()
        for s in "${subs[@]}"; do
            is_nested=0
            for s2 in "${subs[@]}"; do
                [ "$s2" = "$s" ] && continue
                if [[ "$s" == "$s2-"* ]]; then is_nested=1; break; fi
            done
            [ "$is_nested" -eq 1 ] || top+=("$s")
        done
        joined="$(IFS='|'; echo "${top[*]}")"
        printf "  %-14s%s\n" "$c" "$joined"
    done
}

# ── Category helpers ────────────────────────────────────────────
_pos_category_exists() {
    local cat="${1:-}" f
    [ -n "$cat" ] || return 1
    for f in "$self"/pos-"$cat"-*; do
        [ -x "$f" ] && return 0
    done
    return 1
}

_pos_category_help() {
    local cat="$1" s s2 extra d sc deps
    # Lazy registry load — plain dispatch paths never pay the scan cost.
    source "$self/../lib/registry.sh" 2>/dev/null || source "$self/registry.sh"
    reg_scan "$self"

    local files=()
    local t
    while IFS= read -r t; do
        [ -n "$t" ] || continue
        files+=("${t#"$cat"-}")
    done < <(reg_tools_in "$cat")
    mapfile -t files < <(printf '%s\n' "${files[@]}" | sort -u)

    local -A desc subcmds _deps
    for s in "${files[@]}"; do
        d="$(reg_lookup "$cat-$s" desc)"
        [ -n "$d" ] && desc["$s"]="$d"
        sc="$(reg_lookup "$cat-$s" subcmds)"
        [ -n "$sc" ] && subcmds["$s"]="$sc"
        deps="$(reg_lookup "$cat-$s" deps)"
        [ -n "$deps" ] && _deps["$s"]="$deps"
    done

    # Nested sub-tools: pos-<cat>-<a>-<b> lists "b" under <a>.
    local s2 extra
    for s in "${files[@]}"; do
        for s2 in "${files[@]}"; do
            [ "$s2" = "$s" ] && continue
            if [[ "$s2" == "$s-"* ]]; then
                extra="${s2#$s-}"
                case " ${subcmds[$s]:-} " in
                    *" $extra "*) ;;
                    *) subcmds["$s"]="${subcmds[$s]:-}${subcmds[$s]:+ }$extra" ;;
                esac
            fi
        done
    done

    echo "pos $cat — $cat tools"
    echo
    echo "USAGE"
    echo "  pos $cat <command> [args]"
    echo
    echo "COMMANDS"
    local is_nested c
    for s in "${files[@]}"; do
        is_nested=0
        for s2 in "${files[@]}"; do
            [ "$s2" = "$s" ] && continue
            if [[ "$s" == "$s2-"* ]]; then is_nested=1; break; fi
        done
        [ "$is_nested" -eq 1 ] && continue
        printf '  %-28s%s\n' "$s" "${desc[$s]:-}"
        [ -n "${_deps[$s]:-}" ] && printf '    [deps: %s]\n' "${_deps[$s]}"
        for c in ${subcmds[$s]:-}; do
            printf '    %s %s\n' "$s" "$c"
        done
    done
    echo
    echo "Run 'pos $cat <command> --help' for details on a command."
    exit 0
}

# ── Help text ──────────────────────────────────────────────────
usage() {
    local cats
    cats="$(_pos_category_list)"
    cat <<EOF
pos — Personal OS Toolkit

  A unified CLI for network, docker, media, system, SSH,
  USB, communication, and entertainment tools on Debian/Ubuntu.

USAGE
  pos <category> <command> [args]

CATEGORIES
$cats
EXAMPLES
  pos network ip                          Show interfaces, routes, public IP
  pos network checkport 10.0.0.1:80       Check if a TCP port is open
  pos network scan 192.168.1.0/24         Fast parallel ping sweep
  pos network hotspot                     Launch wihotspot-gui
  pos network download add <url>          Enqueue an aria2 download (--tmux = live view)

  pos docker ps                           List containers (health, IPs, ports)
  pos docker compose ls                   List available ScaleTail services
  pos docker compose up jellyfin          Deploy a service with Tailscale
  pos docker health                       One-glance health dashboard
  pos docker stack                        Containers grouped by compose stack
  pos docker stack -a                     Include stopped/exited containers

  pos media mp3 <url>                     Download audio as MP3
  pos media mp4 <url>                     Download video as MP4
  pos media ytsync sync                   Incremental YouTube channel sync

  pos system firewall                     Interactive UFW manager
  pos system backup /srv/project          Encrypted (AES-256) folder snapshot
  pos system backup --service             Pick a folder from /srv or ~/srv
  pos share nfs server share /mnt/hdd      Share a folder via NFS
  pos share nfs client persist 10.0.0.5:/srv/data /mnt/nfs/data
                                          Persistent NFS mount (systemd)
  pos share smb server share /mnt/hdd media --users bob
                                          Share a folder via SMB (Samba)
  pos share smb client persist //10.0.0.5/media /mnt/smb/media bob
                                          Persistent SMB mount (automount)

  pos ssh load-keys                       Load all SSH keys into agent

  pos share usb server --ls               List USB devices + connected clients

  pos communication telegram sender send "Backup done"
                                          Send a Telegram message
  pos communication telegram listener     Edit the /command → bash map
  pos communication telegram listener --enable
                                          Install the Telegram bot listener

  pos communication matrix sender send "Backup done"
                                          Send a Matrix room message
  pos communication matrix sender login --user @me:example.org
                                          Fetch a Matrix access token
  pos communication matrix listener       Edit the /command → bash map

  pos entertainment send weather          Fetch Open-Meteo weather → Telegram
  pos entertainment send joke --print     Preview a joke locally (no send)
  pos entertainment enable weather 5m     Auto-send weather to Telegram every 5 min
  pos entertainment status                Show enabled plugins + next run

  pos system schedule list                 Show scheduled jobs + last results
  pos system schedule enable               Start all job timers (per-job intervals)
  pos system schedule migrate              Convert old event.env rules to jobs

  pos ai gemini ask "Explain DNS in one line"
                                          Ask Google Gemini a one-shot question
  pos ai gemini chat                      Interactive multi-turn chat
  pos ai gemini models                    List available Gemini models

  pos config telegram                     Edit Telegram config interactively
  pos config                              Pick a config scope to edit

  pos tree                                Show the command tree (categories + subcommands)

  pos docker vbox create lab1              Create disposable Docker VM
  pos docker vbox create lab1 --dir .      Create VM using current directory
  pos docker vbox enter lab1               Shell into a Docker VM
  pos docker vbox ls                       List Docker VMs

HELP
  pos <category> --help    Show a category's commands
  pos help <command>       Show help for a command
  pos --help               Show this help

LEGACY WRAPPERS
  wr-ip, wr-checkport, wr-scan-ping, wr-docker,
  wr-compose, wr-ufw, mp3, mp4, vbox, ssh-load-all
  still work and forward to pos.
EOF
    exit 0
}

# ── Handle --help / -h ─────────────────────────────────────────
case "${1:-}" in
    -h|--help|"") usage ;;
esac

# ── pos help <command> ─────────────────────────────────────────
if [ "${1:-}" = "help" ]; then
    shift
    [ $# -eq 0 ] && usage
    cmd="pos-$*"
    cmd="${cmd// /-}"
    if command -v "$cmd" &>/dev/null; then
        exec "$cmd" --help
    fi
    [ -x "$self/$cmd" ] && exec "$self/$cmd" --help
    echo "pos: unknown command '$*'" >&2
    echo "Run 'pos --help' to see available commands." >&2
    exit 1
fi

# ── Dispatch ───────────────────────────────────────────────────
args=("$@")
n=${#args[@]}

# ── Category help: pos <category> [--help] ─────────────────────
if _pos_category_exists "${args[0]:-}"; then
    if [ "$n" -eq 1 ] || { [ "$n" -eq 2 ] && { [ "${args[1]}" = "-h" ] || [ "${args[1]}" = "--help" ]; }; }; then
        _pos_category_help "${args[0]}"
    fi
fi

# ── Logging setup ──────────────────────────────────────────────
LOG_DIR="$HOME/.local/share/linux_post_install/logs"
mkdir -p "$LOG_DIR" 2>/dev/null || true
CMD_SAFE=$(echo "${args[*]}" | tr ' /' '__')
LOG_FILE="$LOG_DIR/$(date +%Y%m%d_%H%M%S)_pos_${CMD_SAFE}.log"
MAIN_LOG="$LOG_DIR/pos.log"
log_cmd() { echo "[$(date '+%Y-%m-%d %H:%M:%S')] $* → exit $2" >> "$MAIN_LOG"; }

# Commands that read from stdin interactively — only log invocation
INTERACTIVE_CMDS="docker-compose docker-vbox network-hotspot system-firewall media-mp4 media-sync system-backup system-uninstall share-usb-server share-smb-server share-smb-client share-nfs-client share-nfs-server communication-telegram-listener communication-matrix-listener ai ai-gemini ai-openrouter ai-alias system-schedule entertainment-config config"

for ((i=n-1; i>=0; i--)); do
    cmd="pos"
    for ((j=0; j<=i; j++)); do
        cmd="${cmd}-${args[$j]}"
    done

    resolved=""
    if command -v "$cmd" &>/dev/null; then
        resolved="$cmd"
    elif [ -x "$self/$cmd" ]; then
        resolved="$self/$cmd"
    fi

    [ -z "$resolved" ] && continue

    sub="${cmd#pos-}"
    if [[ " $INTERACTIVE_CMDS " == *" $sub "* ]]; then
        # Interactive: log invocation only, then exec normally
        log_cmd "pos $*" "" 0
        exec "$resolved" "${args[@]:i+1}"
    else
        # Non-interactive: capture full output
        "$resolved" "${args[@]:i+1}" 2>&1 | tee "$LOG_FILE"
        rc=${PIPESTATUS[0]}
        log_cmd "pos $*" "$LOG_FILE" "$rc"
        exit "$rc"
    fi
done

echo "pos: unknown command '${args[0]}'" >&2
echo "Run 'pos --help' to see available commands." >&2
exit 1
