#!/usr/bin/env bash
#MISE depends=["test:build-perf-workspace"]
#MISE description="Run performance tests"
# shellcheck disable=SC2086,SC2129
set -euo pipefail

runs="${RUNS:-1}"
warmups="${PERF_WARMUPS:-2}"
# Empirical noise floor on the CI runners is roughly ±10% on the small means
# we measure here, so a 10% threshold flagged near-every PR. Bump to 15% so
# a "regression" warning corresponds to something larger than baseline drift.
threshold="${PERF_THRESHOLD:-15}"
cd perf-workspace
mkdir -p flamegraphs
MISE_DATA_DIR="${MISE_DATA_DIR:-$HOME/.local/share/mise}"
declare -A benchmarks
declare -A alt_benchmarks
names=()

if [ -v MISE_ALT ]; then
	which mise
	which "$MISE_ALT"
fi

# Time a single invocation in milliseconds, suppressing all output.
time_one() {
	local cmd="$1"
	shift
	local start_time end_time
	start_time=$(date +%s%N)
	timeout -v 20 "$cmd" "$@" >/dev/null 2>&1 || true
	end_time=$(date +%s%N)
	echo $(((end_time - start_time) / 1000000))
}

# Median of stdin lines, integer. Portable: sort numerically, then average
# the middle one or two values (handles even and odd counts).
median() {
	sort -n | awk '{a[NR]=$1} END {
		if (NR % 2) print a[(NR+1)/2];
		else print int((a[NR/2] + a[NR/2+1]) / 2);
	}'
}

# Run mise and (if set) MISE_ALT $runs times each, interleaved, with $warmups
# warmup invocations of each first. Interleaving keeps runner-load drift from
# biasing one binary; medians make a single slow iteration not move the result.
benchmark() {
	local name="$1"
	shift
	local out=() alt_out=()
	echo "benchmarking $name ($* — $runs runs each, $warmups warmups)" >&2
	for _ in $(seq 1 "$warmups"); do
		time_one mise "$@" >/dev/null
		[ -n "${MISE_ALT:-}" ] && time_one "$MISE_ALT" "$@" >/dev/null
	done
	for _ in $(seq 1 "$runs"); do
		out+=("$(time_one mise "$@")")
		[ -n "${MISE_ALT:-}" ] && alt_out+=("$(time_one "$MISE_ALT" "$@")")
	done
	benchmarks["$name-cached"]=$(printf '%s\n' "${out[@]}" | median)
	if [ -n "${MISE_ALT:-}" ]; then
		alt_benchmarks["$name-cached"]=$(printf '%s\n' "${alt_out[@]}" | median)
	fi
	names+=("$name")
}

mise install
benchmark install install
benchmark ls ls
benchmark bin-paths bin-paths
benchmark task-ls task ls
set +x

get_performance_emoji() {
	local variance="$1"
	if [ ${variance#-} -gt $threshold ]; then
		if [ $variance -gt 0 ]; then
			echo "✅ "
		else
			echo "⚠️ "
		fi
	fi
}

get_performance_warning() {
	local name="$1"
	local variance="$2"
	local type="$3"
	if [ ${variance#-} -gt $threshold ]; then
		if [ $variance -gt 0 ]; then
			echo "✅  Performance improvement: $name $type is ${variance}%"
		else
			local msg="⚠️  Warning: $name $type performance variance is ${variance}%"
			echo "::warning file=xtasks/test/perf::$msg" >&2
			echo "$msg"
		fi
	fi
}

print_performance_table() {
	local output_file="$1"
	if [ -n "${MISE_ALT:-}" ]; then
		echo "| Command    | $MISE_ALT | mise | Variance |" >>"$output_file"
		echo "|------------|-----------|------|----------|" >>"$output_file"
		for name in "${names[@]}"; do
			cached_variance=$(((${alt_benchmarks["$name-cached"]} - ${benchmarks["$name-cached"]}) * 100 / ${benchmarks["$name-cached"]}))
			cached_emoji=$(get_performance_emoji "$cached_variance")
			printf "| %-10s | %6dms | %s%6dms | %+d%% |\n" \
				"$name (cached)" \
				"${alt_benchmarks["$name-cached"]}" \
				"$cached_emoji" \
				"${benchmarks["$name-cached"]}" \
				"$cached_variance" >>"$output_file"
		done
	else
		echo "| Command    | Time   |" >>"$output_file"
		echo "|------------|--------|" >>"$output_file"
		for name in "${names[@]}"; do
			printf "| %-10s | %6dms |\n" "$name (cached)" "${benchmarks["$name-cached"]}" >>"$output_file"
		done
	fi
}

print_performance_warnings() {
	local output_file="$1"
	if [ -n "${MISE_ALT:-}" ]; then
		for name in "${names[@]}"; do
			cached_variance=$(((${alt_benchmarks["$name-cached"]} - ${benchmarks["$name-cached"]}) * 100 / ${benchmarks["$name-cached"]}))
			warning=$(get_performance_warning "$name" "$cached_variance" "cached")
			if [ -n "$warning" ]; then
				echo "$warning" >>"$output_file"
			fi
		done
	fi
}

# Print table to console
print_performance_table "/dev/stdout"

if [ -v GITHUB_STEP_SUMMARY ]; then
	# shellcheck disable=SC2016
	echo '## `xtasks/test/perf`' >>../comment.md

	print_performance_table "../comment.md"
	echo "" >>../comment.md
	print_performance_warnings "../comment.md"
fi
