#!/bin/sh

CONFIG_DIR="${SA_CONFIG_DIR:-/etc/config}"
UCI_BIN="${UCI_BIN:-uci}"
IWINFO_BIN="${IWINFO_BIN:-iwinfo}"
IW_BIN="${IW_BIN:-iw}"
WIFI_BIN="${WIFI_BIN:-wifi}"
WAN_CORE_BIN="${WAN_CORE_BIN:-/usr/sbin/wan-core}"

CONFIG_FILE="$CONFIG_DIR/ca_setup"
WIRELESS_FILE="$CONFIG_DIR/wireless"

uci_q() {
	"$UCI_BIN" -q "$@"
}

uci_cmd() {
	"$UCI_BIN" "$@"
}

cfg_get() {
	local package="$1"
	local section="$2"
	local option="$3"
	local default="$4"
	local value

	value="$(uci_q get "$package.$section.$option" 2>/dev/null || true)"
	if [ -n "$value" ]; then
		printf '%s\n' "$value"
	else
		printf '%s\n' "$default"
	fi
}

cfg_set() {
	uci_cmd set "$1.$2.$3=$4"
}

target_profile() {
	local qsdk

	qsdk="$(cfg_get ca_setup getmap qsdk 12.2 | tr '[:upper:] .-' '[:lower:]___')"
	case "$qsdk" in
		12_5|qsdk12_5|qsdk_12_5|qsdk125|qsdk_125) echo "qsdk12_5" ;;
		14*|qsdk14|qsdk14_0|qsdk_14|qsdk_14_0|qsdk140|qsdk_140) echo "qsdk14" ;;
		25*|openwrt25|openwrt_25|owrt25) echo "openwrt25" ;;
		*) echo "qsdk12_2" ;;
	esac
}

json_escape() {
	awk '{
		gsub(/\\/, "\\\\")
		gsub(/"/, "\\\"")
		gsub(/\t/, "\\t")
		if (NR > 1) printf "\\n"
		printf "%s", $0
	}'
}

json_string() {
	printf '"%s"' "$(printf '%s' "$1" | json_escape)"
}

json_bool() {
	case "$1" in
		1|true|yes|on) printf 'true' ;;
		*) printf 'false' ;;
	esac
}

json_value() {
	case "$1" in
		n/a|'') printf 'null' ;;
		*[!0-9.-]*) json_string "$1" ;;
		*) printf '%s' "$1" ;;
	esac
}

json_action_cmd() {
	local module="$1"
	local action="$2"
	shift 2
	local output rc

	output="$("$@" 2>&1)"
	rc=$?
	printf '{"ok":'
	json_bool "$([ "$rc" = "0" ] && echo 1 || echo 0)"
	printf ',"module":'; json_string "$module"
	printf ',"action":'; json_string "$action"
	printf ',"rc":%s' "$rc"
	printf ',"output":'; json_string "$output"
	printf '}'
	printf '\n'
	return "$rc"
}

wisp_contract_json_fields() {
	local schema="$1"
	local family="$2"
	local route="$3"
	local read_only="$4"

	printf '"schema":'; json_string "$schema"
	printf ',"schema_version":1'
	printf ',"contract_family":'; json_string "$family"
	printf ',"owner":"internet-assistant"'
	printf ',"delegated_assistant_route":'; json_string "$route"
	printf ',"qsdks_ready":["12.2","12.5"]'
	printf ',"read_only":'; json_bool "$read_only"
	printf ',"remote_management":{"transport_only":["BBF/icwmp","TR-069-compatible","Remote Agent"],"prepared_api_only":true,"arbitrary_commands_allowed":false,"same_rules_as_local_ui":true}'
}

required_files_ok() {
	if [ ! -f "$CONFIG_FILE" ]; then
		echo "error: required config file missing: $CONFIG_FILE"
		return 1
	fi
	if [ ! -f "$WIRELESS_FILE" ]; then
		echo "error: required wireless config missing: $WIRELESS_FILE"
		return 1
	fi
	return 0
}

list_radios() {
	uci_q show wireless 2>/dev/null |
		awk -F= '/^wireless\.[^.]+=wifi-device$/ { sub(/^wireless\./, "", $1); print $1 }'
}

radio_primary_ifname() {
	local radio="$1"
	local iface device ifname

	for iface in $(uci_q show wireless 2>/dev/null | awk -F= '/^wireless\.[^.]+=wifi-iface$/ { sub(/^wireless\./, "", $1); print $1 }'); do
		device="$(cfg_get wireless "$iface" device "")"
		[ "$device" = "$radio" ] || continue
		ifname="$(cfg_get wireless "$iface" ifname "$iface")"
		[ -n "$ifname" ] && {
			echo "$ifname"
			return 0
		}
	done
	echo "$radio"
}

scan_target_for_radio() {
	local radio="$1"
	local ifname

	if command -v "$IWINFO_BIN" >/dev/null 2>&1; then
		echo "$radio"
		return 0
	fi
	ifname="$(radio_primary_ifname "$radio")"
	echo "$ifname"
}

scan_one_radio() {
	local radio="$1"
	local target

	target="$(scan_target_for_radio "$radio")"
	if command -v "$IWINFO_BIN" >/dev/null 2>&1; then
		"$IWINFO_BIN" "$target" scan 2>/dev/null |
			awk -v radio="$radio" '
				/^Cell / {
					if (seen) print_record()
					seen=1; ssid=""; bssid=""; channel=""; signal=""; encryption=""
				}
				/Address:/ { bssid=$5 }
				/ESSID:/ {
					line=$0
					sub(/^.*ESSID: /, "", line)
					gsub(/^"|"$/, "", line)
					ssid=line
				}
				/Channel:/ { channel=$2 }
				/Signal:/ { signal=$2 }
				/Encryption:/ {
					line=$0
					sub(/^.*Encryption: /, "", line)
					encryption=line
				}
				function print_record() {
					if (ssid != "") {
						printf "%s|%s|%s|%s|%s|%s\n", radio, ssid, bssid, channel, signal, encryption
					}
				}
				END { if (seen) print_record() }
			'
		return 0
	fi

	command -v "$IW_BIN" >/dev/null 2>&1 || return 0
	"$IW_BIN" dev "$target" scan 2>/dev/null |
		awk -v radio="$radio" '
			/^BSS / {
				if (seen) print_record()
				seen=1; ssid=""; bssid=$2; sub(/\(.*/, "", bssid); channel=""; signal=""; encryption="unknown"
			}
			/^[ \t]*SSID:/ {
				sub(/^[ \t]*SSID:[ \t]*/, "")
				ssid=$0
			}
			/^[ \t]*freq:/ { freq=$2; channel=freq }
			/^[ \t]*signal:/ { signal=$2 }
			/^[ \t]*RSN:/ { encryption="WPA2/WPA3" }
			/^[ \t]*WPA:/ { encryption="WPA" }
			function print_record() {
				if (ssid != "") {
					printf "%s|%s|%s|%s|%s|%s\n", radio, ssid, bssid, channel, signal, encryption
				}
			}
			END { if (seen) print_record() }
		'
}

scan_records() {
	local selected="$1"
	local radio

	required_files_ok >/dev/null || return 1
	for radio in $(list_radios); do
		[ "$selected" = "all" ] || [ "$selected" = "auto" ] || [ "$selected" = "$radio" ] || continue
		scan_one_radio "$radio"
	done
}

wisp_ifname() {
	local ifname

	ifname="$(cfg_get wireless wisp_sta ifname "")"
	if [ -n "$ifname" ]; then
		echo "$ifname"
	else
		echo "wisp_sta"
	fi
}

wisp_connected() {
	local ifname="$1"

	command -v "$IW_BIN" >/dev/null 2>&1 || {
		echo 0
		return 0
	}
	"$IW_BIN" dev "$ifname" link 2>/dev/null | grep -q '^Connected to ' && echo 1 || echo 0
}

wisp_link_ssid() {
	local ifname="$1"

	command -v "$IW_BIN" >/dev/null 2>&1 || return 0
	"$IW_BIN" dev "$ifname" link 2>/dev/null |
		awk '/^[ \t]*SSID:/ {
			sub(/^[ \t]*SSID:[ \t]*/, "")
			print
			exit
		}'
}

wisp_link_signal() {
	local ifname="$1"

	command -v "$IW_BIN" >/dev/null 2>&1 || return 0
	"$IW_BIN" dev "$ifname" link 2>/dev/null | awk '/^[ \t]*signal:/ { print $2; exit }'
}

wisp_link_freq() {
	local ifname="$1"

	command -v "$IW_BIN" >/dev/null 2>&1 || return 0
	"$IW_BIN" dev "$ifname" link 2>/dev/null | awk '/^[ \t]*freq:/ { print $2; exit }'
}

wisp_section_exists() {
	uci_q get wireless.wisp_sta >/dev/null 2>&1 && echo 1 || echo 0
}

scan_cmd() {
	local selected radio ssid bssid channel signal encryption

	selected="${1:-$(cfg_get ca_setup wisp radio auto)}"
	[ "$selected" = "auto" ] && selected="all"
	echo "WISP scan"
	scan_records "$selected" | while IFS='|' read -r radio ssid bssid channel signal encryption; do
		echo "$ssid"
		echo "  Radio: $radio"
		echo "  BSSID: ${bssid:-n/a}"
		echo "  Channel: ${channel:-n/a}"
		echo "  Signal: ${signal:-n/a} dBm"
		echo "  Security: ${encryption:-unknown}"
	done
}

scan_json_cmd() {
	local selected first radio ssid bssid channel signal encryption

	selected="${1:-$(cfg_get ca_setup wisp radio auto)}"
	[ "$selected" = "auto" ] && selected="all"
	printf '{'
	wisp_contract_json_fields "wisp-scan-v1" "internet-wisp-scan" "internet-assistant-wisp scan --json" 1
	printf ',"active_scan":true'
	printf ',"aps":['
	first=1
	scan_records "$selected" | while IFS='|' read -r radio ssid bssid channel signal encryption; do
		[ "$first" = "1" ] || printf ','
		first=0
		printf '{'
		printf '"radio":'; json_string "$radio"
		printf ',"ssid":'; json_string "$ssid"
		printf ',"bssid":'; json_string "$bssid"
		printf ',"channel":'; json_string "$channel"
		printf ',"signal_dbm":'; json_string "$signal"
		printf ',"security":'; json_string "$encryption"
		printf '}'
	done
	printf ']}\n'
}

status_cmd() {
	local ifname connected live_ssid signal freq

	ifname="$(wisp_ifname)"
	connected="$(wisp_connected "$ifname")"
	live_ssid="$(wisp_link_ssid "$ifname")"
	signal="$(wisp_link_signal "$ifname")"
	freq="$(wisp_link_freq "$ifname")"

	echo "WISP status"
	echo "Enabled: $(cfg_get ca_setup wisp enabled 1)"
	echo "Radio: $(cfg_get ca_setup wisp radio auto)"
	echo "SSID: $(cfg_get ca_setup wisp ssid "")"
	echo "BSSID: $(cfg_get ca_setup wisp bssid "")"
	echo "Encryption: $(cfg_get ca_setup wisp encryption psk2)"
	echo "WAN protocol: $(cfg_get ca_setup wisp wan_proto dhcp)"
	echo "Applied section: $(wisp_section_exists)"
	echo "Interface: $ifname"
	echo "Connected: $connected"
	echo "Live SSID: ${live_ssid:-n/a}"
	echo "Signal: ${signal:-n/a} dBm"
	echo "Frequency: ${freq:-n/a} MHz"
	echo "Last apply: $(cfg_get ca_setup wisp last_apply never)"
}

status_json_cmd() {
	local ifname connected live_ssid signal freq

	ifname="$(wisp_ifname)"
	connected="$(wisp_connected "$ifname")"
	live_ssid="$(wisp_link_ssid "$ifname")"
	signal="$(wisp_link_signal "$ifname")"
	freq="$(wisp_link_freq "$ifname")"

	printf '{'
	wisp_contract_json_fields "wisp-status-v1" "internet-wisp-status" "internet-assistant-wisp status --json" 1
	printf ',"enabled":'; json_bool "$(cfg_get ca_setup wisp enabled 1)"
	printf ',"radio":'; json_string "$(cfg_get ca_setup wisp radio auto)"
	printf ',"ssid":'; json_string "$(cfg_get ca_setup wisp ssid "")"
	printf ',"bssid":'; json_string "$(cfg_get ca_setup wisp bssid "")"
	printf ',"encryption":'; json_string "$(cfg_get ca_setup wisp encryption psk2)"
	printf ',"wan_proto":'; json_string "$(cfg_get ca_setup wisp wan_proto dhcp)"
	printf ',"applied":'; json_bool "$(wisp_section_exists)"
	printf ',"ifname":'; json_string "$ifname"
	printf ',"connected":'; json_bool "$connected"
	printf ',"live_ssid":'; json_string "$live_ssid"
	printf ',"signal_dbm":'; json_value "$signal"
	printf ',"frequency_mhz":'; json_value "$freq"
	printf ',"last_apply":'; json_string "$(cfg_get ca_setup wisp last_apply never)"
	printf '}\n'
}

validate_cmd() {
	local enabled radio ssid encryption key wan_proto errors

	required_files_ok || return 1
	enabled="$(cfg_get ca_setup wisp enabled 1)"
	radio="$(cfg_get ca_setup wisp radio auto)"
	ssid="$(cfg_get ca_setup wisp ssid "")"
	encryption="$(cfg_get ca_setup wisp encryption psk2)"
	key="$(cfg_get ca_setup wisp key "")"
	wan_proto="$(cfg_get ca_setup wisp wan_proto dhcp)"
	errors=0

	if [ "$enabled" != "1" ]; then
		echo "warning: WISP helper is disabled"
	fi
	if [ "$radio" != "auto" ] && ! list_radios | grep -qx "$radio"; then
		echo "error: selected radio does not exist: $radio"
		errors=$((errors + 1))
	fi
	if [ -z "$ssid" ]; then
		echo "warning: WISP SSID is not configured"
	fi
	case "$encryption" in
		none|psk|psk2|psk-mixed|sae|sae-mixed) ;;
		*)
			echo "error: unsupported encryption: $encryption"
			errors=$((errors + 1))
			;;
	esac
	if [ "$encryption" != "none" ] && [ -n "$ssid" ] && [ -z "$key" ]; then
		echo "error: key is required for encrypted WISP"
		errors=$((errors + 1))
	fi
	case "$wan_proto" in
		dhcp|static) ;;
		*)
			echo "error: unsupported WAN protocol: $wan_proto"
			errors=$((errors + 1))
			;;
	esac
	[ "$errors" -eq 0 ] || return 1
	echo "validation ok"
}

wisp_finding() {
	local first="$1"
	local severity="$2"
	local title="$3"
	local detail="$4"
	local action="$5"

	[ "$first" = "1" ] || printf ','
	printf '{'
	printf '"severity":'; json_string "$severity"
	printf ',"title":'; json_string "$title"
	printf ',"detail":'; json_string "$detail"
	printf ',"action":'; json_string "$action"
	printf '}'
}

health_json_cmd() {
	local enabled applied ifname connected ssid live_ssid signal state summary first validation rc

	enabled="$(cfg_get ca_setup wisp enabled 1)"
	applied="$(wisp_section_exists)"
	ifname="$(wisp_ifname)"
	connected="$(wisp_connected "$ifname")"
	ssid="$(cfg_get ca_setup wisp ssid "")"
	live_ssid="$(wisp_link_ssid "$ifname")"
	signal="$(wisp_link_signal "$ifname")"
	state="idle"
	summary="WISP is not applied"

	validation="$(validate_cmd 2>&1)"
	rc=$?
	if [ "$enabled" != "1" ]; then
		state="idle"
		summary="WISP helper is disabled"
	elif [ "$rc" != "0" ]; then
		state="warning"
		summary="WISP configuration needs attention"
	elif [ "$applied" = "1" ] && [ "$connected" = "1" ]; then
		state="ok"
		summary="WISP uplink is connected"
	elif [ "$applied" = "1" ]; then
		state="warning"
		summary="WISP is applied but not connected"
	elif [ -n "$ssid" ]; then
		state="idle"
		summary="WISP profile is staged but not applied"
	fi

	printf '{'
	wisp_contract_json_fields "wisp-health-v1" "internet-wisp-health" "internet-assistant-wisp health --json" 1
	printf ',"state":'; json_string "$state"
	printf ',"summary":'; json_string "$summary"
	printf ',"findings":['
	first=1
	if [ "$rc" != "0" ]; then
		wisp_finding "$first" "warning" "WISP validation failed" "$validation" "Fix the staged WISP profile before applying WAN-over-Wi-Fi."
		first=0
	fi
	if [ "$applied" = "1" ] && [ "$connected" != "1" ]; then
		wisp_finding "$first" "warning" "WISP uplink is disconnected" "The wireless WAN section exists but $ifname is not associated." "Scan for the upstream AP and verify SSID, BSSID, security, and key."
		first=0
	fi
	if [ "$applied" != "1" ] && [ -n "$ssid" ]; then
		wisp_finding "$first" "info" "WISP profile staged" "SSID $ssid is configured but has not been applied to wireless.wisp_sta." "Apply WISP settings when the local management path is ready."
		first=0
	fi
	if [ "$applied" != "1" ] && [ -z "$ssid" ]; then
		wisp_finding "$first" "info" "WISP not configured" "No upstream Wi-Fi SSID is staged." "Use WISP scan when Wi-Fi should be the WAN connection."
		first=0
	fi
	[ "$first" = "1" ] && wisp_finding "$first" "info" "No WISP findings" "WAN-over-Wi-Fi is connected and reporting normally." "Keep monitoring signal before relying on WISP as primary WAN."
	printf ']'
	printf ',"metrics":{"applied":'; json_bool "$applied"
	printf ',"connected":'; json_bool "$connected"
	printf ',"ifname":'; json_string "$ifname"
	printf ',"ssid":'; json_string "$ssid"
	printf ',"live_ssid":'; json_string "$live_ssid"
	printf ',"signal_dbm":'; json_value "$signal"
	printf '}}'
	printf '\n'
}

preview_cmd() {
	local radio ssid bssid encryption wan_proto

	radio="$(cfg_get ca_setup wisp radio auto)"
	ssid="$(cfg_get ca_setup wisp ssid "")"
	bssid="$(cfg_get ca_setup wisp bssid "")"
	encryption="$(cfg_get ca_setup wisp encryption psk2)"
	wan_proto="$(cfg_get ca_setup wisp wan_proto dhcp)"

	echo "WISP preview"
	echo "This keeps LAN as the local routed network and uses Wi-Fi as WAN."
	echo "Network:"
	echo "  network.wan.proto=$wan_proto"
	echo "  network.wan6.proto=dhcpv6"
	echo "Wireless:"
	echo "  wireless.wisp_sta=wifi-iface"
	echo "  wireless.wisp_sta.mode=sta"
	echo "  wireless.wisp_sta.device=$radio"
	echo "  wireless.wisp_sta.network=wan"
	echo "  wireless.wisp_sta.ssid=${ssid:-not set}"
	echo "  wireless.wisp_sta.bssid=${bssid:-any}"
	echo "  wireless.wisp_sta.encryption=$encryption"
	echo "Firewall:"
	echo "  existing wan zone includes wan and wan6"
}

apply_plan_json_cmd() {
	local radio selected_radio ssid bssid encryption wan_proto key_set enabled applied connected ifname live_ssid signal validation rc state summary safe first

	required_files_ok >/dev/null || return 1
	radio="$(cfg_get ca_setup wisp radio auto)"
	selected_radio="$radio"
	ssid="$(cfg_get ca_setup wisp ssid "")"
	bssid="$(cfg_get ca_setup wisp bssid "")"
	encryption="$(cfg_get ca_setup wisp encryption psk2)"
	wan_proto="$(cfg_get ca_setup wisp wan_proto dhcp)"
	key_set=0
	[ -n "$(cfg_get ca_setup wisp key "")" ] && key_set=1
	enabled="$(cfg_get ca_setup wisp enabled 1)"
	applied="$(wisp_section_exists)"
	ifname="$(wisp_ifname)"
	connected="$(wisp_connected "$ifname")"
	live_ssid="$(wisp_link_ssid "$ifname")"
	signal="$(wisp_link_signal "$ifname")"
	validation="$(validate_cmd 2>&1)"
	rc=$?
	safe=0

	if [ "$radio" = "auto" ]; then
		selected_radio="$(list_radios | awk 'NR == 1 { print; exit }')"
	fi

	if [ "$enabled" != "1" ]; then
		state="disabled"
		summary="WISP helper is disabled."
	elif [ "$rc" != "0" ]; then
		state="invalid"
		summary="WISP profile validation must pass before apply."
	elif [ -z "$ssid" ]; then
		state="idle"
		summary="No upstream Wi-Fi SSID is staged."
	else
		state="ready"
		summary="WISP settings are ready to apply. Keep a local management path before applying."
		safe=1
	fi

	printf '{'
	wisp_contract_json_fields "wisp-apply-plan-v1" "internet-wisp-apply-plan" "internet-assistant-wisp apply-plan --json" 1
	printf ',"state":'; json_string "$state"
	printf ',"summary":'; json_string "$summary"
	printf ',"apply_supported":true'
	printf ',"apply_route":"internet-assistant-wisp apply"'
	printf ',"safe_to_apply":'; json_bool "$safe"
	printf ',"service_reload":true'
	printf ',"target":{"radio":'; json_string "$radio"
	printf ',"selected_radio":'; json_string "$selected_radio"
	printf ',"ssid":'; json_string "$ssid"
	printf ',"bssid":'; json_string "$bssid"
	printf ',"encryption":'; json_string "$encryption"
	printf ',"key_configured":'; json_bool "$key_set"
	printf ',"wan_proto":'; json_string "$wan_proto"
	printf '}'
	printf ',"runtime":{"applied":'; json_bool "$applied"
	printf ',"connected":'; json_bool "$connected"
	printf ',"ifname":'; json_string "$ifname"
	printf ',"live_ssid":'; json_string "$live_ssid"
	printf ',"signal_dbm":'; json_value "$signal"
	printf '}'
	printf ',"policy":{"enabled":'; json_bool "$enabled"
	printf ',"confirmation":"apply_action"'
	printf '}'
	printf ',"validation":{"rc":%s' "$rc"
	printf ',"output":'; json_string "$validation"
	printf '}'
	printf ',"writes":['
	json_string "WISP WAN plan"
	printf ','
	json_string "network.wan"
	printf ','
	json_string "network.wan6"
	printf ','
	json_string "wireless.wisp_sta"
	printf ','
	json_string "firewall wan zone network list"
	printf ','
	json_string "ca_setup.wisp.last_apply"
	printf ']'
	printf ',"reloads":['
	json_string "wifi reload"
	printf ','
	json_string "network reload"
	printf ','
	json_string "firewall reload"
	printf ']'
	printf ',"backup":{"enabled":true,"path_prefix":'
	json_string "/etc/internet-assistant/backups/wisp-<timestamp>"
	printf '}'
	printf ',"blockers":['
	first=1
	if [ "$enabled" != "1" ]; then
		json_string "ca_setup.wisp.enabled is not enabled."
		first=0
	fi
	if [ "$rc" != "0" ]; then
		[ "$first" = "1" ] || printf ','
		json_string "WISP validation did not pass."
		first=0
	fi
	if [ -z "$ssid" ]; then
		[ "$first" = "1" ] || printf ','
		json_string "ca_setup.wisp.ssid is not configured."
		first=0
	fi
	if [ "$encryption" != "none" ] && [ "$key_set" != "1" ]; then
		[ "$first" = "1" ] || printf ','
		json_string "Encrypted WISP requires a configured key."
		first=0
	fi
	if [ "$radio" = "auto" ] && [ -z "$selected_radio" ]; then
		[ "$first" = "1" ] || printf ','
		json_string "No wireless radio was found for automatic selection."
	fi
	printf ']'
	printf ',"notes":['
	json_string "WISP turns Wi-Fi into WAN while keeping LAN as the local routed network."
	printf ','
	json_string "Keep a local management path before applying, because WAN-over-Wi-Fi reloads wireless and network services."
	printf ']}'
	printf '\n'
}

backup_configs() {
	local dir="/etc/internet-assistant/backups/wisp-$(date +%Y%m%d-%H%M%S)"

	mkdir -p "$dir"
	cp /etc/config/network "$dir/network" 2>/dev/null || true
	cp /etc/config/wireless "$dir/wireless" 2>/dev/null || true
	cp /etc/config/firewall "$dir/firewall" 2>/dev/null || true
	cp /etc/config/ca_setup "$dir/ca_setup" 2>/dev/null || true
	echo "$dir"
}

wan_firewall_zone() {
	local section name

	for section in $(uci_q show firewall 2>/dev/null | awk -F= '/^firewall\.[^.]+=zone$/ { sub(/^firewall\./, "", $1); print $1 }'); do
		name="$(cfg_get firewall "$section" name "")"
		[ "$name" = "wan" ] && {
			echo "$section"
			return 0
		}
	done
	echo ""
}

apply_cmd() {
	local radio ssid bssid encryption key wan_proto target backup output rc

	required_files_ok || return 1
	[ -x "$WAN_CORE_BIN" ] || {
		echo "error: required Internet settings engine is missing."
		return 1
	}

	radio="$(cfg_get ca_setup wisp radio auto)"
	ssid="$(cfg_get ca_setup wisp ssid "")"
	bssid="$(cfg_get ca_setup wisp bssid "")"
	encryption="$(cfg_get ca_setup wisp encryption psk2)"
	key="$(cfg_get ca_setup wisp key "")"
	wan_proto="$(cfg_get ca_setup wisp wan_proto dhcp)"
	target="$(target_profile)"

	[ -n "$ssid" ] || {
		echo "error: WISP SSID is required."
		return 1
	}
	if [ "$encryption" != "none" ] && [ -z "$key" ]; then
		echo "error: WISP key is required unless encryption is none."
		return 1
	fi
	if [ "$radio" = "auto" ]; then
		radio="$(list_radios | awk 'NR == 1 { print; exit }')"
	fi
	[ -n "$radio" ] || {
		echo "error: no wireless radio found."
		return 1
	}

	backup="$(backup_configs)"
	output="$("$WAN_CORE_BIN" apply wisp_wan "$target" \
		"radio=$radio" \
		"ssid=$ssid" \
		"bssid=$bssid" \
		"encryption=$encryption" \
		"key=$key" \
		"wan_proto=$wan_proto" 2>&1)"
	rc=$?
	if [ "$rc" != "0" ]; then
		printf '%s\n' "$output"
		return "$rc"
	fi
	printf '%s\n' "$output"
	printf 'Backup: %s\n' "$backup" >&2
}

usage() {
	cat <<'EOF'
usage: internet-assistant-wisp <command>

Commands:
  status [--json]
  scan [--json] [radio|all]
  validate [--json]
  health [--json]
  apply-plan [--json]
  preview
  apply
EOF
}

main() {
	local cmd="${1:-status}"
	local output_json=0
	shift || true
	if [ "${1:-}" = "--json" ]; then
		output_json=1
		shift || true
	fi

	case "$cmd" in
		status)
			if [ "$output_json" = "1" ]; then status_json_cmd "$@"; else status_cmd "$@"; fi
			;;
		scan)
			if [ "$output_json" = "1" ]; then scan_json_cmd "$@"; else scan_cmd "$@"; fi
			;;
		validate)
			if [ "$output_json" = "1" ]; then json_action_cmd internet-assistant-wisp validate validate_cmd; else validate_cmd "$@"; fi
			;;
		health)
			health_json_cmd "$@"
			;;
		apply-plan)
			apply_plan_json_cmd "$@"
			;;
		preview) preview_cmd "$@" ;;
		apply)
			if [ "$output_json" = "1" ]; then
				json_action_cmd internet-assistant-wisp apply apply_cmd "$@"
			else
				apply_cmd "$@"
			fi
			;;
		-h|--help|help) usage ;;
		*)
			echo "error: unknown command: $cmd" >&2
			usage >&2
			return 1
			;;
	esac
}

main "$@"
