#!/usr/bin/env bash
# Analyze cProfile data from the bot process.
# Usage: tools/profile [OPTIONS] [FILE]
#
# Options:
#   -n NUM      Show top NUM entries (default: 30)
#   -s SORT     Sort by: cumtime, tottime, calls, name (default: cumtime)
#   -f PATTERN  Filter to entries matching PATTERN
#   -c          Callers view (who calls the hot functions)
#   -h          Show this help
#
# Examples:
#   tools/profile                        # top 30 by cumulative time
#   tools/profile -s tottime -n 20       # top 20 by total time
#   tools/profile -f mumble              # only mumble-related functions
#   tools/profile -c -f stream_audio     # who calls stream_audio
#   tools/profile data/old.prof          # analyze a specific file

# shellcheck source=tools/_common.sh
source "$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)/_common.sh"

DEFAULT_PROF="$PROJECT_DIR/data/derp.prof"
TOP=30
SORT="cumtime"
PATTERN=""
CALLERS=false

usage() {
    sed -n '2,/^$/s/^# \?//p' "$0"
    exit 0
}

while getopts ":n:s:f:ch" opt; do
    case $opt in
        n) TOP="$OPTARG" ;;
        s) SORT="$OPTARG" ;;
        f) PATTERN="$OPTARG" ;;
        c) CALLERS=true ;;
        h) usage ;;
        :) err "option -$OPTARG requires an argument"; exit 2 ;;
        *) err "unknown option -$OPTARG"; exit 2 ;;
    esac
done
shift $((OPTIND - 1))

PROF="${1:-$DEFAULT_PROF}"

if [[ ! -f "$PROF" ]]; then
    err "profile not found: $PROF"
    dim "run the bot with --cprofile and stop it gracefully"
    exit 1
fi

# Validate sort key
case "$SORT" in
    cumtime|tottime|calls|name) ;;
    *) err "invalid sort key: $SORT (use cumtime, tottime, calls, name)"; exit 2 ;;
esac

# Profile metadata
size=$(stat -c %s "$PROF" 2>/dev/null || stat -f %z "$PROF" 2>/dev/null)
human=$(numfmt --to=iec-i --suffix=B "$size" 2>/dev/null || echo "${size}B")
modified=$(stat -c %y "$PROF" 2>/dev/null | cut -d. -f1)

printf '%b%s%b\n' "$BLU" "Profile" "$RST"
dim "$PROF ($human, $modified)"
echo

# Build pstats script
read -r -d '' PYSCRIPT << 'PYEOF' || true
import pstats
import sys
import io

prof_path = sys.argv[1]
sort_key  = sys.argv[2]
top_n     = int(sys.argv[3])
pattern   = sys.argv[4]
callers   = sys.argv[5] == "1"

p = pstats.Stats(prof_path, stream=sys.stdout)
p.strip_dirs()
p.sort_stats(sort_key)

if pattern:
    if callers:
        p.print_callers(pattern, top_n)
    else:
        p.print_stats(pattern, top_n)
else:
    if callers:
        p.print_callers(top_n)
    else:
        p.print_stats(top_n)
PYEOF

exec python3 -c "$PYSCRIPT" "$PROF" "$SORT" "$TOP" "$PATTERN" "$( $CALLERS && echo 1 || echo 0 )"
