#!/bin/sh
umask 077

NODE_BIN="$1"
GATEWAY_SCRIPT="$2"
NODE_ARGS="$3"
shift 3

STATE_DIR=""
for arg in "$@"; do
	case "$arg" in
		--state-dir=*) STATE_DIR="${arg#--state-dir=}" ;;
	esac
done

if [ -z "$NODE_BIN" ] || [ -z "$GATEWAY_SCRIPT" ] || [ -z "$STATE_DIR" ]; then
	echo "Missing supervisor arguments."
	exit 2
fi

LOG="$STATE_DIR/launcher.log"
SUPERVISOR_PID="$STATE_DIR/supervisor.pid"
STOP_FILE="$STATE_DIR/supervisor.stop"
STATUS_FILE="$STATE_DIR/status.json"
MAX_RUNTIME_SECONDS="${NIWA_WA_SUPERVISOR_MAX_RUNTIME_SECONDS:-2700}"

case "$MAX_RUNTIME_SECONDS" in
	''|*[!0-9]*) MAX_RUNTIME_SECONDS=2700 ;;
esac

if [ "$MAX_RUNTIME_SECONDS" -lt 300 ]; then
	MAX_RUNTIME_SECONDS=300
fi

mkdir -p "$STATE_DIR"
echo "$$" > "$SUPERVISOR_PID"
rm -f "$STOP_FILE"

stop_supervisor() {
	echo "[$(date -u +%Y-%m-%dT%H:%M:%SZ)] supervisor stopping" >> "$LOG"
	rm -f "$SUPERVISOR_PID"
	exit 0
}

trap stop_supervisor TERM INT

process_is_active() {
	pid="$1"
	if [ -r "/proc/$pid/stat" ]; then
		stat="$(cat "/proc/$pid/stat" 2>/dev/null || true)"
		state="$(printf '%s' "$stat" | awk '{print $3}')"
		case "$state" in
			Z|X|x) return 1 ;;
		esac
	fi
	kill -0 "$pid" 2>/dev/null
}

rotate_supervisor() {
	echo "[$(date -u +%Y-%m-%dT%H:%M:%SZ)] supervisor rotating before host runtime limit" >> "$LOG"
	rm -f "$SUPERVISOR_PID"
	nohup /bin/sh "$0" "$NODE_BIN" "$GATEWAY_SCRIPT" "$NODE_ARGS" "$@" >> "$LOG" 2>&1 &
	echo "[$(date -u +%Y-%m-%dT%H:%M:%SZ)] supervisor replacement pid=$!" >> "$LOG"
	exit 0
}

while :; do
	if [ -f "$STOP_FILE" ]; then
		break
	fi

	echo "[$(date -u +%Y-%m-%dT%H:%M:%SZ)] supervisor launching gateway" >> "$LOG"
	if [ -n "$NODE_ARGS" ]; then
		"$NODE_BIN" $NODE_ARGS "$GATEWAY_SCRIPT" "$@" >> "$LOG" 2>&1 &
	else
		"$NODE_BIN" "$GATEWAY_SCRIPT" "$@" >> "$LOG" 2>&1 &
	fi
	child_pid="$!"
	started_at="$(date +%s)"

	while process_is_active "$child_pid"; do
		if [ -f "$STOP_FILE" ] || grep -q '"status"[[:space:]]*:[[:space:]]*"logged_out"' "$STATUS_FILE" 2>/dev/null; then
			kill "$child_pid" 2>/dev/null || true
			wait "$child_pid" 2>/dev/null || true
			break
		fi

		now="$(date +%s)"
		if [ $((now - started_at)) -ge "$MAX_RUNTIME_SECONDS" ]; then
			kill "$child_pid" 2>/dev/null || true
			sleep 5
			if process_is_active "$child_pid"; then
				kill -9 "$child_pid" 2>/dev/null || true
			fi
			wait "$child_pid" 2>/dev/null || true
			rotate_supervisor "$@"
		fi

		sleep 2
	done

	wait "$child_pid" 2>/dev/null
	code="$?"
	echo "[$(date -u +%Y-%m-%dT%H:%M:%SZ)] gateway exited code=$code" >> "$LOG"

	if [ -f "$STOP_FILE" ] || grep -q '"status"[[:space:]]*:[[:space:]]*"logged_out"' "$STATUS_FILE" 2>/dev/null; then
		break
	fi

	sleep 2
done

rm -f "$SUPERVISOR_PID"
exit 0
