#!/bin/sh

# LuCI owns interactive admission. This runner owns finalization after the
# child exits so human-readable log text never decides setup success.

set -u
umask 077

progress_file="/tmp/auto_ipoe_progress.json"
pending_file="/tmp/ipoe_pending"
ui_pending_file="/tmp/ipoe_ui_pending"
reason_file="/tmp/ipoe_apply.reason"
log_file="/tmp/ipoe_log.txt"

operation="${1:-}"
runner_valid=1
case "$operation" in
	auto_ipoe|disable_mapv6|static_ip) ;;
	*) runner_valid=0 ;;
esac
if [ "$#" -gt 0 ]; then
	shift
else
	runner_valid=0
fi
[ "$#" -gt 0 ] || runner_valid=0

busy_retries="${AUTO_IPOE_UI_BUSY_RETRIES:-0}"
case "$busy_retries" in
	''|*[!0-9]*) busy_retries=0 ;;
esac
[ "$busy_retries" -le 300 ] || busy_retries=300

pre_disable="${AUTO_IPOE_UI_PRE_DISABLE:-0}"
[ "$pre_disable" = "1" ] || pre_disable=0

cleanup_file="${AUTO_IPOE_UI_CLEANUP_FILE:-}"
if [ -n "$cleanup_file" ]; then
	cleanup_suffix="${cleanup_file#/tmp/auto-ipoe-biglobe-credentials-}"
	case "$cleanup_file:$cleanup_suffix" in
		/tmp/auto-ipoe-biglobe-credentials-*:*[!0-9-]*|*:)
			cleanup_file=""
			;;
		/tmp/auto-ipoe-biglobe-credentials-*:*) ;;
		*) cleanup_file="" ;;
	esac
fi

read_failure_reason() {
	reason=""
	if [ -r "$reason_file" ]; then
		IFS= read -r reason < "$reason_file" || true
	fi
	case "$reason" in
		''|*[!A-Za-z0-9_]*) reason="ProcessFailed" ;;
	esac
	printf '%s' "$reason"
}

publish_result() {
	rc="$1"
	prior_completed=0
	connectivity_verified=false
	if [ -r "$progress_file" ]; then
		grep -Eq '"phase"[[:space:]]*:[[:space:]]*"completed"' "$progress_file" \
			&& prior_completed=1
		grep -Eq '"connectivityVerified"[[:space:]]*:[[:space:]]*true' "$progress_file" \
			&& connectivity_verified=true
	fi

	phase="failed"
	reason="ProcessFailed"
	if [ "$rc" -eq 75 ]; then
		phase="busy"
		reason="Busy"
	elif [ "$rc" -eq 0 ] && [ "$operation" = "disable_mapv6" ]; then
		phase="completed"
		reason="Completed"
	elif [ "$rc" -eq 0 ] && [ "$prior_completed" -eq 1 ] \
			&& [ "$connectivity_verified" = "true" ]; then
		phase="completed"
		reason="Completed"
	elif [ "$rc" -eq 0 ]; then
		reason="CompletionUnconfirmed"
	else
		reason="$(read_failure_reason)"
	fi

	temporary_file="${progress_file}.tmp.$$"
	printf '{"phase":"%s","operation":"%s","exitCode":%s,"reason":"%s","connectivityVerified":%s}\n' \
		"$phase" "$operation" "$rc" "$reason" "$connectivity_verified" > "$temporary_file"
	if ! mv -f "$temporary_file" "$progress_file"; then
		rm -f "$temporary_file"
	fi

}

finish() {
	rc="$?"
	trap - EXIT HUP INT TERM
	publish_result "$rc"
	rm -f "$pending_file" "$ui_pending_file"
	if [ -n "$cleanup_file" ]; then
		rm -f "$cleanup_file"
	fi
	exit "$rc"
}

trap 'exit 129' HUP
trap 'exit 130' INT
trap 'exit 143' TERM
trap finish EXIT

[ "$runner_valid" -eq 1 ] || exit 64

# Replace the short-lived LuCI controller owner with this runner. A later
# request can then recover markers left by a hard-killed runner without
# mistaking an active operation for stale state.
ui_owner_tmp="${ui_pending_file}.runner.$$"
printf '%s\n' "$$" > "$ui_owner_tmp"
mv -f "$ui_owner_tmp" "$ui_pending_file"

if [ "$pre_disable" -eq 1 ]; then
	/usr/bin/lua /usr/lib/lua/mapv6.lua -disable >/dev/null 2>>"$log_file"
	disable_rc="$?"
	[ "$disable_rc" -eq 0 ] || exit "$disable_rc"
	rm -f "$progress_file" "$log_file"
	: > "$pending_file"
fi

attempt=0
while :; do
	"$@" >/dev/null 2>>"$log_file"
	rc="$?"
	if [ "$rc" -ne 75 ] || [ "$attempt" -ge "$busy_retries" ]; then
		break
	fi
	attempt=$((attempt + 1))
	sleep 2
done

exit "$rc"
