#!/bin/sh

# Script: bbf_config_reload.sh
# Description:
#   This script reloads WiFi Configs based on input args.
#   Input args should be one of the below or both with space separate
#     - "wireless"
#     - "mapcontroller"
#
# Usage:
#   sh bbf_config_reload.sh wireless mapcontroller
#
# Actions:
#   - If both wireless and mapcontroller → Reload mapcontroller (SIGHUP)
#   - If only wireless → Commit wireless config via ubus
#   - If only mapcontroller → Reload mapcontroller (SIGHUP)
#   - Otherwise → Do nothing

log() {
	echo "${@}"|logger -t bbf.config.wifi.reload -p info
}

input="$@"

# Validate input
if [ -z "$input" ]; then
	log "Error: No input provided"
	exit 1
fi

# Normalize inputs (default to 0 if not set)
wireless=0
mapcontroller=0

for arg in ${input}; do
	if [ "${arg}" == "wireless" ]; then
		wireless=1
	fi

	if [ "${arg}" == "mapcontroller" ]; then
		mapcontroller=1
	fi
done


################################################################################
# wait_for_wifi_reload
#
# Description:
#   Currently, there is no direct way to determine when WiFi reload
#   operations have fully completed. The ubus API does not provide any
#   event or flag indicating that WiFi services have finished reloading.
#
#   To work around this, we use a timing-based heuristic:
#     - We repeatedly run `ubus call wifi status` every 1 second.
#     - Each call is timed (using `date +%s` before and after).
#     - Normally, this command returns almost instantly (<1s).
#     - However, during a WiFi reload, the call may take longer
#       (several seconds) while the subsystem is busy.
#     - Once we detect that `ubus call wifi status` takes longer than
#       2 seconds to return, we assume the reload has been applied
#       and completed successfully.
#
#   Additional wait constraints:
#     - Minimum wait: 5 seconds (to ensure reload started).
#     - Maximum wait: 15 seconds (to prevent indefinite blocking).
#     - If the threshold is not met within 15s, we log a timeout warning.
################################################################################
wait_for_wifi_reload() {
	MAX_ITER=15
	MIN_ITER=5
	THRESH=2  # seconds

	# Check if wifi ubus object exists
	ubus -t 2 wait_for wifi >/dev/null 2>&1
	if [ "$?" -ne 0 ]; then
		log "wifi ubus object not available, skipping wait logic"
		return 0
	fi

	#log "Waiting for WiFi reload (min ${MIN_ITER}s, max ${MAX_ITER}s)..."

	iter=0
	while [ "${iter}" -lt "${MAX_ITER}" ]; do
		iter=$((iter + 1))
		start=$(date +%s)
		ubus call wifi status >/dev/null 2>&1
		#rc=$?
		end=$(date +%s)
		elapsed=$((end - start))

		#log "wait_for_wifi_reload: iter=${iter}, rc=${rc}, elapsed=${elapsed}s"

		# If ubus took >2s and we've waited at least MIN_ITER → assume reload done
		if [ "${elapsed}" -gt "${THRESH}" ] && [ "${iter}" -ge "${MIN_ITER}" ]; then
			log "Detected long ubus response (${elapsed}s) after ${iter}s → assuming WiFi reload complete"
			return 0
		fi

		# Sleep 1s between checks
		if [ "${iter}" -lt "${MAX_ITER}" ]; then
			sleep 1
		fi
	done

	log "Timeout after ${MAX_ITER}s — WiFi reload not confirmed"
	return 1
}

###############################################################################
# mark_ap_instances_applied
#
# Description:
#   Finalizes newly created WiFi AccessPoint instances in the dmmap WiFi
#   configuration.
#
#   An AccessPoint instance is considered a *new instance* when the option
#   __is_new__ exists and its value is "1".
#
#   New instance handling logic:
#
#     • The AccessPoint's controller-side section name is obtained from
#       the __section_name__ option (e.g., "mapcontroller.xxx" or "wireless.xxx").
#
#     • For new instances where __section_name__ begins with "mapcontroller.":
#           - Remove __is_new__
#           - No additional actions required
#
#     • For new instances where __section_name__ begins with "wireless.":
#           - Set mapcontroller=0 (indicates mapcontroller reload is not required)
#           - Remove __is_new__
#
#     • For all other prefixes:
#           - Remove __is_new__ only
#
#   After all new instances are processed, the dmmap WiFi configuration is committed.
###############################################################################
mark_ap_instances_applied() {
	for sec in $(uci -q -c /etc/bbfdm/dmmap show WiFi | grep "=AccessPoint" | cut -d. -f2 | cut -d= -f1); do
		is_new=$(uci -q -c /etc/bbfdm/dmmap get WiFi.${sec}.__is_new__)

		if [ "${is_new}" = "1" ]; then
			config_sec_name=$(uci -q -c /etc/bbfdm/dmmap get WiFi.${sec}.__section_name__)
			case "${config_sec_name}" in
				mapcontroller.*)
					# New mapcontroller AP instance — remove creation flag only
					uci -q -c /etc/bbfdm/dmmap delete WiFi.${sec}.__is_new__
					;;

				wireless.*)
					# New wireless AP instance — skip mapcontroller reload
					mapcontroller=0
					uci -q -c /etc/bbfdm/dmmap delete WiFi.${sec}.__is_new__
					;;

				*)
					# Other AP instance types — remove creation flag only
					uci -q -c /etc/bbfdm/dmmap delete WiFi.${sec}.__is_new__
					;;
			esac
		fi
	done

	uci -q -c /etc/bbfdm/dmmap commit WiFi
}

# Define function to reload mapcontroller
reload_mapcontroller() {
	pid=$(pidof mapcontroller)
	if [ -n "$pid" ]; then
		log "Reloading mapcontroller (PID: $pid)..."
		kill -SIGHUP "$pid"
		wait_for_wifi_reload
	else
		log "Warning: mapcontroller process not found"
	fi
}

# Define function to commit wireless config
commit_wireless_config() {
	log "Committing wireless config..."
	ubus call uci commit '{"config":"wireless"}'
	wait_for_wifi_reload
}

# Finalize newly created AP AccessPoint instances
mark_ap_instances_applied

# Apply logic based on flags
if [ "$mapcontroller" -eq 1 ]; then
	reload_mapcontroller
elif [ "$wireless" -eq 1 ]; then
	commit_wireless_config
else
	log "No action needed."
	exit 1
fi

exit 0
