#!/bin/sh

PATH=/usr/sbin:/usr/bin:/sbin:/bin
UCI_BIN="${UCI_BIN:-uci}"
WAN_CORE_BIN="${WAN_CORE_BIN:-/usr/sbin/wan-core}"

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

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)"
	[ -n "$value" ] && printf '%s\n' "$value" || printf '%s\n' "$default"
}

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_number_or_string() {
	case "$1" in
		''|*[!0-9]*) json_string "$1" ;;
		*) printf '%s' "$1" ;;
	esac
}

command_exists() {
	command -v "$1" >/dev/null 2>&1
}

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
}

wan_core_json_cmd() {
	local subcmd="$1"
	shift

	if [ ! -x "$WAN_CORE_BIN" ]; then
		printf '{"state":"error","summary":'
		json_string "Required Internet settings engine is missing."
		printf ',"internet_settings_engine_required":true,"posix_fallback":false}\n'
		return 1
	fi
	"$WAN_CORE_BIN" "$subcmd" "$(target_profile)" "$@"
}

first_ipv4_route_dev() {
	ip route show default 2>/dev/null |
		awk '$1 == "default" { for (i=1; i<=NF; i++) if ($i == "dev") { print $(i+1); exit } }'
}

wan6_state() {
	ifstatus wan6 2>/dev/null |
		awk -F: '/"up"/ { gsub(/[ ,]/, "", $2); if ($2 == "true") print "up"; else print "down"; exit }'
}

global_ipv6_prefix() {
	ip -6 addr show scope global 2>/dev/null | awk '/inet6 / { print $2; exit }'
}

connection_mode() {
	local auto proto route_dev wan_setup

	auto="$(cfg_get ca_setup getmap autoipoe 0)"
	wan_setup="$(cfg_get ca_setup ipoe wan_setup dhcp_auto)"
	proto="$(uci_q get network.wan.proto 2>/dev/null || echo unknown)"
	route_dev="$(first_ipv4_route_dev)"
	if [ "$auto" = "1" ]; then
		echo "auto-ipoe enabled"
	elif [ "$wan_setup" = "static_ip" ]; then
		echo "static ip"
	elif [ "$wan_setup" = "dhcp_auto" ]; then
		echo "dhcp auto"
	elif [ "$wan_setup" = "pppoe_ipv4" ] || [ "$wan_setup" = "ipoe_mix" ] || [ "$proto" = "pppoe" ]; then
		echo "pppoe"
	elif [ "$wan_setup" = "wisp_wan" ] || uci_q get wireless.wisp_sta >/dev/null 2>&1; then
		echo "wisp wan"
	elif [ "$wan_setup" = "manual" ] || [ "$wan_setup" = "ipoe_mape" ] || [ "$wan_setup" = "ipoe_dslite" ] || [ "$wan_setup" = "bridge_mode" ]; then
		echo "manual setting"
	elif [ "$proto" = "static" ]; then
		echo "static ip"
	elif [ "$proto" = "map" ] || [ "$proto" = "dslite" ] || [ "$proto" = "ipip6" ] || [ "$route_dev" = "wanmap" ] || [ "$route_dev" = "dslite" ] || [ "$route_dev" = "ipip6" ] || [ "$route_dev" = "ipip" ]; then
		echo "manual tunnel"
	else
		echo "manual setting"
	fi
}

detected_vne() {
	local vne

	vne="$(uci_q get ca_setup.getmap.vne 2>/dev/null || uci_q get ca_setup.getmap.service 2>/dev/null || true)"
	[ -n "$vne" ] && echo "$vne" || echo "unknown"
}

status_json_cmd() {
	local mode proto route_dev wan_dev wan6 ipv6 vne state summary core

	mode="$(connection_mode)"
	proto="$(uci_q get network.wan.proto 2>/dev/null || echo unknown)"
	route_dev="$(first_ipv4_route_dev)"
	wan_dev="$(uci_q get network.wan.ifname 2>/dev/null || uci_q get network.wan.device 2>/dev/null || echo unknown)"
	wan6="$(wan6_state)"
	ipv6="$(global_ipv6_prefix)"
	vne="$(detected_vne)"
	[ -x /usr/sbin/mapv6-core ] && core=1 || core=0
	if [ -n "$route_dev" ] || [ "$wan6" = "up" ] || [ -n "$ipv6" ]; then
		state="ok"
		summary="$mode"
	else
		state="warning"
		summary="$mode; no active route detected"
	fi

	printf '{'
	printf '"state":'; json_string "$state"
	printf ',"summary":'; json_string "$summary"
	printf ',"module":"auto-ipoe"'
	printf ',"connection_mode":'; json_string "$mode"
	printf ',"internet_mode":'; json_string "$(cfg_get ca_setup ipoe wan_setup dhcp_auto)"
	printf ',"autoipoe_enabled":'; json_bool "$(cfg_get ca_setup getmap autoipoe 0)"
	printf ',"detected_vne":'; json_string "$vne"
	printf ',"wan_proto":'; json_string "$proto"
	printf ',"wan_device":'; json_string "$wan_dev"
	printf ',"default_route_device":'; json_string "${route_dev:-unknown}"
	printf ',"wan6_state":'; json_string "${wan6:-unknown}"
	printf ',"ipv6_prefix":'; json_string "${ipv6:-unknown}"
	printf ',"qsdk":'; json_string "$(cfg_get ca_setup getmap qsdk unknown)"
	printf ',"mapv6_core":'; json_bool "$core"
	printf ',"last_log":'; json_string "$(tail -n 1 /etc/ipoe_last.log 2>/dev/null || tail -n 1 /tmp/ipoe_last.log 2>/dev/null || true)"
	printf '}'
	printf '\n'
}

ui_summary_json_cmd() {
	local mode internet_mode proto route_dev wan6 ipv6 vne auto state priority title message action_label
	local badge_state badge_label blocker_count

	mode="$(connection_mode)"
	internet_mode="$(cfg_get ca_setup ipoe wan_setup dhcp_auto)"
	proto="$(uci_q get network.wan.proto 2>/dev/null || echo unknown)"
	route_dev="$(first_ipv4_route_dev)"
	wan6="$(wan6_state)"
	ipv6="$(global_ipv6_prefix)"
	vne="$(detected_vne)"
	auto="$(cfg_get ca_setup getmap autoipoe 0)"

	state="healthy"
	priority="status_first"
	title="Internet is ready"
	message="Current connection settings are available."
	action_label="Check connection"
	badge_state="ok"
	badge_label="Ready"
	blocker_count=0

	if [ -z "$route_dev" ] && [ "$wan6" != "up" ] && [ -z "$ipv6" ]; then
		state="needs_attention"
		priority="fix_first"
		title="Internet needs attention"
		message="No active Internet route was detected."
		action_label="Review connection"
		badge_state="warning"
		badge_label="Needs attention"
		blocker_count=1
	fi

	case "$internet_mode:$proto:$mode" in
		'':*|not\ selected:*|*:unknown:manual\ setting)
			state="setup_needed"
			priority="setup_first"
			title="Set up Internet"
			message="Choose how this router should connect before configuring optional services."
			action_label="Choose Internet setup"
			badge_state="idle"
			badge_label="Setup needed"
			;;
	esac

	printf '{'
	printf '"schema":"internet-ui-summary-v1"'
	printf ',"contract_family":"router-assistant-ui-summary"'
	printf ',"assistant":"internet"'
	printf ',"owner":"internet-assistant"'
	printf ',"read_only":true'
	printf ',"state":'; json_string "$state"
	printf ',"priority":'; json_string "$priority"
	printf ',"title":'; json_string "$title"
	printf ',"message":'; json_string "$message"
	printf ',"badge":{"state":'; json_string "$badge_state"
	printf ',"label":'; json_string "$badge_label"
	printf '}'
	printf ',"summary":{'
	printf '"title":'; json_string "$title"
	printf ',"message":'; json_string "$message"
	printf ',"facts":['
	printf '{"label":"Connection method","value":'; json_string "$mode"; printf '},'
	printf '{"label":"WAN protocol","value":'; json_string "$proto"; printf '},'
	printf '{"label":"Default route","value":'; json_string "${route_dev:-not detected}"; printf '},'
	printf '{"label":"WAN IPv6","value":'; json_string "${wan6:-unknown}"; printf '},'
	printf '{"label":"Detected VNE","value":'; json_string "$vne"; printf '}'
	printf ']'
	printf '}'
	printf ',"primary_actions":['
	printf '{"id":"check_connection","label":'; json_string "$action_label"
	printf ',"action":"health","enabled":true,"mutating":false},'
	printf '{"id":"review_workflow","label":"Review Internet plan","action":"workflow-plan","enabled":true,"mutating":false}'
	printf ']'
	printf ',"safe_checks":['
	printf '{"id":"route","label":"Default route","state":'
	if [ -n "$route_dev" ]; then json_string "ready"; else json_string "missing"; fi
	printf '},'
	printf '{"id":"wan_ipv6","label":"WAN IPv6","state":'
	if [ "$wan6" = "up" ] || [ -n "$ipv6" ]; then json_string "ready"; else json_string "not detected"; fi
	printf '},'
	printf '{"id":"auto_ipoe","label":"Auto-IPoE","state":'
	if [ "$auto" = "1" ]; then json_string "enabled"; else json_string "disabled"; fi
	printf '}'
	printf ']'
	printf ',"editable_settings":[]'
	printf ',"technician_details":{'
	printf '"source":"auto-ipoe ui-summary","status_action":"status","health_action":"health","workflow_action":"workflow-plan"'
	printf ',"blocker_count":'; json_number_or_string "$blocker_count"
	printf ',"internet_mode":'; json_string "$internet_mode"
	printf ',"ipv6_prefix":'; json_string "${ipv6:-unknown}"
	printf '}'
	printf ',"safety":{"wan_changed":false,"service_reload":false,"network_reload":false,"autoipoe_toggled":false}'
	printf '}'
	printf '\n'
}

health_finding() {
	local first="$1" severity="$2" title="$3" detail="$4" 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 first=1 state="ok" summary="Internet connection path is available" route_dev wan6 ipv6 mode

	route_dev="$(first_ipv4_route_dev)"
	wan6="$(wan6_state)"
	ipv6="$(global_ipv6_prefix)"
	mode="$(connection_mode)"

	printf '{'
	if [ -z "$route_dev" ] && [ "$wan6" != "up" ] && [ -z "$ipv6" ]; then
		state="warning"
		summary="No active Internet route was detected"
	fi
	printf '"state":'; json_string "$state"
	printf ',"summary":'; json_string "$summary"
	printf ',"findings":['
	if [ -z "$route_dev" ]; then
		health_finding "$first" warning "No IPv4 default route" "No IPv4 default route is currently visible." "Refresh Auto-IPoE or check WAN connectivity before applying dependent features."
		first=0
	fi
	if [ "$wan6" != "up" ] && [ -z "$ipv6" ]; then
		health_finding "$first" warning "WAN IPv6 not detected" "Auto-IPoE needs WAN IPv6 information for MAP-E, DS-Lite, or IPIP selection." "Check WAN6 status and upstream IPv6 before re-detection."
		first=0
	fi
	if [ "$(cfg_get ca_setup getmap autoipoe 0)" != "1" ]; then
		health_finding "$first" info "Auto-IPoE is not enabled" "Current mode is $mode." "Use Auto-IPoE only when this router should manage IPv4-over-IPv6 automatically."
		first=0
	fi
	if [ "$first" = "1" ]; then
		health_finding "$first" info "No Internet findings" "Auto-IPoE did not report a blocking condition." "Refresh status after changing WAN or IPoE settings."
	fi
	printf ']'
	printf ',"metrics":{"connection_mode":'; json_string "$mode"
	printf ',"default_route_device":'; json_string "${route_dev:-unknown}"
	printf ',"wan6_state":'; json_string "${wan6:-unknown}"
	printf '}}'
	printf '\n'
}

workflow_plan_json_cmd() {
	local route_dev wan6 ipv6 mode blockers=0

	route_dev="$(first_ipv4_route_dev)"
	wan6="$(wan6_state)"
	ipv6="$(global_ipv6_prefix)"
	mode="$(connection_mode)"
	[ -z "$ipv6" ] && [ "$wan6" != "up" ] && blockers=$((blockers + 1))

	printf '{'
	printf '"state":'; json_string "$([ "$blockers" -eq 0 ] && echo ready || echo blocked)"
	printf ',"summary":'; json_string "Auto-IPoE workflow is preview-only until an explicit apply path is selected."
	printf ',"safe_to_apply":false'
	printf ',"connection_mode":'; json_string "$mode"
	printf ',"stages":['
	printf '{"id":"detect_ipv6","state":'; json_string "$([ -n "$ipv6" ] || [ "$wan6" = "up" ] && echo ready || echo blocked)"
	printf ',"summary":"Read WAN IPv6 prefix and route state."},'
	printf '{"id":"select_profile","state":"planned","summary":"Choose Auto-IPoE, static IP, or manual tunnel mode."},'
	printf '{"id":"write_network","state":"gated","summary":"Network writes remain owned by Auto-IPoE LuCI/mapv6 flow."},'
	printf '{"id":"validate_connectivity","state":"planned","summary":"Confirm Internet reachability after changes."}'
	printf ']'
	printf ',"blockers":['
	if [ "$blockers" -gt 0 ]; then
		json_string "WAN IPv6 is not currently visible."
	fi
	printf ']'
	printf ',"observed":{"default_route_device":'; json_string "${route_dev:-unknown}"
	printf ',"wan6_state":'; json_string "${wan6:-unknown}"
	printf ',"ipv6_prefix":'; json_string "${ipv6:-unknown}"
	printf '}}'
	printf '\n'
}

rollback_plan_json_cmd() {
	printf '{'
	printf '"state":"manual"'
	printf ',"summary":'; json_string "Auto-IPoE rollback remains owned by the Auto-IPoE LuCI/mapv6 flow."
	printf ',"safe_to_apply":false'
	printf ',"automatic_rollback":false'
	printf ',"module":"auto-ipoe"'
	printf ',"notes":['
	json_string "Auto-IPoE exposes read-only workflow guidance for controller and UI integrations."
	printf ','
	json_string "Use the Auto-IPoE assistant page or saved system backup for WAN rollback."
	printf ']'
	printf '}'
	printf '\n'
}

usage() {
	cat <<'EOF'
usage: auto-ipoe <command>

Commands:
  ui-summary [--json]
  status [--json]
  health [--json]
  validate [--json]
  preview [--json]
  workflow-plan [--json]
  wan-candidates [--json] [candidates=<id:node:transport:interface:mode:health:priority[:role[:gateway_handoff_supported]];...>]
  rollback-plan [--json]
  rollback [--json]
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
		ui-summary)
			ui_summary_json_cmd "$@"
			;;
		status)
			status_json_cmd "$@"
			;;
		health|validate)
			health_json_cmd "$@"
			;;
		workflow-plan|preview)
			workflow_plan_json_cmd "$@"
			;;
		wan-candidates)
			wan_core_json_cmd wan-candidates "$@"
			;;
		rollback-plan|rollback)
			rollback_plan_json_cmd "$@"
			;;
		-h|--help|help)
			usage
			;;
		*)
			echo "error: unknown command: $cmd" >&2
			usage >&2
			return 1
			;;
	esac
}

main "$@"
