#!/bin/sh
# SPDX-License-Identifier: Apache-2.0
# Network Modes Dashboard RPCD backend
# Copyright (C) 2024 CyberMind.fr - Gandalf

. /lib/functions.sh
. /usr/share/libubox/jshn.sh

get_pkg_version() {
	local ctrl="/usr/lib/opkg/info/luci-app-network-modes.control"
	if [ -f "$ctrl" ]; then
		awk -F': ' '/^Version/ { print $2; exit }' "$ctrl"
	else
		echo "unknown"
	fi
}

PKG_VERSION="$(get_pkg_version)"

CONFIG_FILE="/etc/config/network-modes"
BACKUP_DIR="/etc/network-modes-backup"
PCAP_DIR="/var/log/pcap"

is_module_enabled() {
	local enabled
	enabled=$(uci -q get secubox.network_modes.enabled)
	[ -z "$enabled" ] && return 0
	[ "$enabled" = "1" ] && return 0
	return 1
}

# Get current status
get_status() {
	json_init
	
	# Current mode
	local current_mode=$(uci -q get network-modes.config.current_mode || echo "router")
	local last_change=$(uci -q get network-modes.config.last_change || echo "Never")
	
	json_add_string "version" "$PKG_VERSION"
	json_add_string "current_mode" "$current_mode"
	json_add_string "last_change" "$last_change"
	
	# Get mode details
	local mode_name=$(uci -q get network-modes.$current_mode.name || echo "$current_mode")
	local mode_desc=$(uci -q get network-modes.$current_mode.description || echo "")
	json_add_string "mode_name" "$mode_name"
	json_add_string "mode_description" "$mode_desc"
	
	# System info
	json_add_string "hostname" "$(uci -q get system.@system[0].hostname || hostname)"
	json_add_int "uptime" "$(cat /proc/uptime | cut -d. -f1)"
	
	# Network interfaces status
	json_add_array "interfaces"
	for iface in $(ip -o link show | awk -F': ' '{print $2}' | grep -v "^lo$"); do
		local state="down"
		ip link show $iface 2>/dev/null | grep -q "UP" && state="up"
		local ip=$(ip -4 addr show $iface 2>/dev/null | grep -oP 'inet \K[\d.]+' | head -1)
		local mac=$(ip link show $iface 2>/dev/null | grep -oP 'link/ether \K[a-f0-9:]+')
		
		json_add_object
		json_add_string "name" "$iface"
		json_add_string "state" "$state"
		json_add_string "ip" "${ip:-N/A}"
		json_add_string "mac" "${mac:-N/A}"
		json_close_object
	done
	json_close_array
	
	# WiFi status
	local wifi_enabled=0
	[ -d /sys/class/net/wlan0 ] && wifi_enabled=1
	json_add_boolean "wifi_available" "$wifi_enabled"
	
	# WireGuard status
	local wg_enabled=0
	command -v wg >/dev/null 2>&1 && wg_enabled=1
	json_add_boolean "wireguard_available" "$wg_enabled"
	
	# Services status
	json_add_object "services"
	json_add_boolean "firewall" "$(pgrep -x fw4 >/dev/null && echo 1 || echo 0)"
	json_add_boolean "dnsmasq" "$(pgrep -x dnsmasq >/dev/null && echo 1 || echo 0)"
	json_add_boolean "netifyd" "$(pgrep -x netifyd >/dev/null && echo 1 || echo 0)"
	json_add_boolean "nginx" "$(pgrep -x nginx >/dev/null && echo 1 || echo 0)"
	json_add_boolean "squid" "$(pgrep -x squid >/dev/null && echo 1 || echo 0)"
	json_close_object
	
	json_dump
}

# Get all modes configuration
get_modes() {
	json_init
	json_add_array "modes"
	
	local current_mode=$(uci -q get network-modes.config.current_mode || echo "router")
	
	# Sniffer mode
	json_add_object
	json_add_string "id" "sniffer"
	json_add_string "name" "$(uci -q get network-modes.sniffer.name || echo 'Sniffer / Passthrough')"
	json_add_string "description" "$(uci -q get network-modes.sniffer.description)"
	json_add_string "icon" "🔍"
	json_add_boolean "active" "$([ "$current_mode" = "sniffer" ] && echo 1 || echo 0)"
	json_add_string "bridge_interface" "$(uci -q get network-modes.sniffer.bridge_interface)"
	json_add_boolean "netifyd_enabled" "$(uci -q get network-modes.sniffer.netifyd_enabled || echo 0)"
	json_add_boolean "promiscuous" "$(uci -q get network-modes.sniffer.promiscuous || echo 0)"
	json_close_object
	
	# Access Point mode
	json_add_object
	json_add_string "id" "accesspoint"
	json_add_string "name" "$(uci -q get network-modes.accesspoint.name || echo 'Access Point')"
	json_add_string "description" "$(uci -q get network-modes.accesspoint.description)"
	json_add_string "icon" "📶"
	json_add_boolean "active" "$([ "$current_mode" = "accesspoint" ] && echo 1 || echo 0)"
	json_add_string "wifi_channel" "$(uci -q get network-modes.accesspoint.wifi_channel)"
	json_add_string "wifi_htmode" "$(uci -q get network-modes.accesspoint.wifi_htmode)"
	json_add_int "wifi_txpower" "$(uci -q get network-modes.accesspoint.wifi_txpower || echo 20)"
	json_add_boolean "roaming_enabled" "$(uci -q get network-modes.accesspoint.roaming_enabled || echo 0)"
	json_add_boolean "band_steering" "$(uci -q get network-modes.accesspoint.band_steering || echo 0)"
	json_close_object
	
	# Relay mode
	json_add_object
	json_add_string "id" "relay"
	json_add_string "name" "$(uci -q get network-modes.relay.name || echo 'Relay / Extender')"
	json_add_string "description" "$(uci -q get network-modes.relay.description)"
	json_add_string "icon" "🔄"
	json_add_boolean "active" "$([ "$current_mode" = "relay" ] && echo 1 || echo 0)"
	json_add_boolean "wireguard_enabled" "$(uci -q get network-modes.relay.wireguard_enabled || echo 0)"
	json_add_string "wireguard_interface" "$(uci -q get network-modes.relay.wireguard_interface)"
	json_add_boolean "mtu_optimization" "$(uci -q get network-modes.relay.mtu_optimization || echo 0)"
	json_add_boolean "mss_clamping" "$(uci -q get network-modes.relay.mss_clamping || echo 0)"
	json_close_object
	
	# Router mode
	json_add_object
	json_add_string "id" "router"
	json_add_string "name" "$(uci -q get network-modes.router.name || echo 'Router')"
	json_add_string "description" "$(uci -q get network-modes.router.description)"
	json_add_string "icon" "🌐"
	json_add_boolean "active" "$([ "$current_mode" = "router" ] && echo 1 || echo 0)"
	json_add_string "wan_protocol" "$(uci -q get network-modes.router.wan_protocol)"
	json_add_boolean "nat_enabled" "$(uci -q get network-modes.router.nat_enabled || echo 1)"
	json_add_boolean "firewall_enabled" "$(uci -q get network-modes.router.firewall_enabled || echo 1)"
	json_add_boolean "proxy_enabled" "$(uci -q get network-modes.router.proxy_enabled || echo 0)"
	json_add_string "proxy_type" "$(uci -q get network-modes.router.proxy_type)"
	json_add_boolean "https_frontend" "$(uci -q get network-modes.router.https_frontend || echo 0)"
	json_add_string "frontend_type" "$(uci -q get network-modes.router.frontend_type)"
	json_close_object

	# Travel mode
	json_add_object
	json_add_string "id" "travel"
	json_add_string "name" "$(uci -q get network-modes.travel.name || echo 'Travel Router')"
	json_add_string "description" "$(uci -q get network-modes.travel.description || echo 'Portable router with WiFi uplink and personal hotspot')"
	json_add_string "icon" "✈️"
	json_add_boolean "active" "$([ "$current_mode" = "travel" ] && echo 1 || echo 0)"
	json_add_string "client_interface" "$(uci -q get network-modes.travel.client_interface || echo 'wlan1')"
	json_add_string "hotspot_interface" "$(uci -q get network-modes.travel.hotspot_interface || echo 'wlan0')"
	json_add_boolean "mac_clone_enabled" "$([ -n "$(uci -q get network-modes.travel.clone_mac)" ] && echo 1 || echo 0)"
	json_add_string "hotspot_ssid" "$(uci -q get network-modes.travel.hotspot_ssid || echo 'SecuBox-Travel')"
	json_close_object
	
	json_close_array
	json_dump
}

# Get sniffer mode configuration
get_sniffer_config() {
	json_init
	
	json_add_string "mode" "sniffer"
	json_add_string "name" "Sniffer / Passthrough Mode"
	json_add_string "description" "Transparent Ethernet bridge without IP for passive network analysis"
	
	# Current settings
	json_add_string "bridge_interface" "$(uci -q get network-modes.sniffer.bridge_interface || echo 'br-lan')"
	json_add_string "capture_interface" "$(uci -q get network-modes.sniffer.capture_interface || echo 'eth0')"
	json_add_boolean "netifyd_enabled" "$(uci -q get network-modes.sniffer.netifyd_enabled || echo 1)"
	json_add_boolean "promiscuous" "$(uci -q get network-modes.sniffer.promiscuous || echo 1)"
	
	# Available interfaces for bridging
	json_add_array "available_interfaces"
	for iface in $(ls /sys/class/net/ | grep -v "^lo$"); do
		json_add_string "" "$iface"
	done
	json_close_array
	
	# Netifyd status
	local netifyd_running=0
	pgrep -x netifyd >/dev/null && netifyd_running=1
	json_add_boolean "netifyd_running" "$netifyd_running"
	
	# Sample config preview
	json_add_string "config_preview" "# /etc/config/network bridge config
config interface 'lan'
    option proto 'none'
    option type 'bridge'
    option ifname 'eth0 eth1'
    option delegate '0'"
	
	json_dump
}

# Get access point mode configuration
get_ap_config() {
	json_init
	
	json_add_string "mode" "accesspoint"
	json_add_string "name" "Access Point Mode"
	json_add_string "description" "WiFi Access Point with advanced optimizations"
	
	# Current settings
	json_add_string "upstream_interface" "$(uci -q get network-modes.accesspoint.upstream_interface || echo 'eth0')"
	json_add_boolean "dhcp_client" "$(uci -q get network-modes.accesspoint.dhcp_client || echo 1)"
	json_add_string "wifi_channel" "$(uci -q get network-modes.accesspoint.wifi_channel || echo 'auto')"
	json_add_string "wifi_htmode" "$(uci -q get network-modes.accesspoint.wifi_htmode || echo 'VHT80')"
	json_add_int "wifi_txpower" "$(uci -q get network-modes.accesspoint.wifi_txpower || echo 20)"
	
	# WiFi tweaks
	json_add_object "wifi_tweaks"
	json_add_boolean "roaming_80211r" "$(uci -q get network-modes.accesspoint.roaming_enabled || echo 0)"
	json_add_boolean "rrm_80211k" "$(uci -q get network-modes.accesspoint.rrm_enabled || echo 0)"
	json_add_boolean "wnm_80211v" "$(uci -q get network-modes.accesspoint.wnm_enabled || echo 0)"
	json_add_boolean "band_steering" "$(uci -q get network-modes.accesspoint.band_steering || echo 0)"
	json_add_boolean "airtime_fairness" "$(uci -q get network-modes.accesspoint.airtime_fairness || echo 0)"
	json_add_boolean "beamforming" "$(uci -q get network-modes.accesspoint.beamforming || echo 1)"
	json_close_object
	
	# Available channels
	json_add_array "available_channels_2g"
	for ch in 1 6 11; do
		json_add_int "" "$ch"
	done
	json_close_array
	
	json_add_array "available_channels_5g"
	for ch in 36 40 44 48 149 153 157 161; do
		json_add_int "" "$ch"
	done
	json_close_array
	
	# HT modes
	json_add_array "available_htmodes"
	json_add_string "" "HT20"
	json_add_string "" "HT40"
	json_add_string "" "VHT40"
	json_add_string "" "VHT80"
	json_add_string "" "VHT160"
	json_add_string "" "HE40"
	json_add_string "" "HE80"
	json_add_string "" "HE160"
	json_close_array
	
	# WiFi info
	local wifi_phy=""
	local wifi_driver=""
	if [ -d /sys/class/ieee80211/phy0 ]; then
		wifi_phy="phy0"
		wifi_driver=$(cat /sys/class/ieee80211/phy0/device/uevent 2>/dev/null | grep DRIVER | cut -d= -f2)
	fi
	json_add_string "wifi_phy" "$wifi_phy"
	json_add_string "wifi_driver" "$wifi_driver"
	
	json_dump
}

# Get relay mode configuration  
get_relay_config() {
	json_init
	
	json_add_string "mode" "relay"
	json_add_string "name" "Relay / Extender Mode"
	json_add_string "description" "Network relay with LAN optimization and WireGuard tunneling"
	
	# Current settings
	json_add_string "relay_interface" "$(uci -q get network-modes.relay.relay_interface || echo 'wlan0')"
	json_add_string "lan_interface" "$(uci -q get network-modes.relay.lan_interface || echo 'eth0')"
	
	# WireGuard settings
	json_add_object "wireguard"
	json_add_boolean "enabled" "$(uci -q get network-modes.relay.wireguard_enabled || echo 0)"
	json_add_string "interface" "$(uci -q get network-modes.relay.wireguard_interface || echo 'wg0')"
	json_add_int "mtu" "$(uci -q get network-modes.relay.wireguard_mtu || echo 1420)"
	json_add_boolean "persistent_keepalive" "$(uci -q get network-modes.relay.persistent_keepalive || echo 1)"
	json_close_object
	
	# Optimization settings
	json_add_object "optimizations"
	json_add_boolean "mtu_optimization" "$(uci -q get network-modes.relay.mtu_optimization || echo 1)"
	json_add_boolean "mss_clamping" "$(uci -q get network-modes.relay.mss_clamping || echo 1)"
	json_add_boolean "tcp_optimization" "$(uci -q get network-modes.relay.tcp_optimization || echo 1)"
	json_add_int "conntrack_max" "$(uci -q get network-modes.relay.conntrack_max || echo 16384)"
	json_close_object
	
	# Relayd status
	local relayd_installed=0
	opkg list-installed 2>/dev/null | grep -q "^relayd" && relayd_installed=1
	json_add_boolean "relayd_available" "$relayd_installed"
	
	# WireGuard interfaces
	json_add_array "wg_interfaces"
	if command -v wg >/dev/null 2>&1; then
		for wgiface in $(wg show interfaces 2>/dev/null); do
			json_add_string "" "$wgiface"
		done
	fi
	json_close_array
	
	json_dump
}

# Get router mode configuration
get_router_config() {
	json_init
	
	json_add_string "mode" "router"
	json_add_string "name" "Router Mode"
	json_add_string "description" "Full router with WAN, proxy, and HTTPS frontends"
	
	# WAN settings
	json_add_object "wan"
	json_add_string "interface" "$(uci -q get network-modes.router.wan_interface || echo 'eth1')"
	json_add_string "protocol" "$(uci -q get network-modes.router.wan_protocol || echo 'dhcp')"
	json_add_boolean "nat_enabled" "$(uci -q get network-modes.router.nat_enabled || echo 1)"
	json_close_object
	
	# LAN settings
	json_add_object "lan"
	json_add_string "interface" "$(uci -q get network-modes.router.lan_interface || echo 'br-lan')"
	json_add_string "ip_address" "$(uci -q get network.lan.ipaddr || echo '192.168.1.1')"
	json_add_string "netmask" "$(uci -q get network.lan.netmask || echo '255.255.255.0')"
	json_close_object
	
	# Firewall
	json_add_object "firewall"
	json_add_boolean "enabled" "$(uci -q get network-modes.router.firewall_enabled || echo 1)"
	json_add_boolean "syn_flood" "$(uci -q get firewall.@defaults[0].syn_flood || echo 1)"
	json_add_string "input" "$(uci -q get firewall.@zone[0].input || echo 'ACCEPT')"
	json_add_string "output" "$(uci -q get firewall.@zone[0].output || echo 'ACCEPT')"
	json_add_string "forward" "$(uci -q get firewall.@zone[0].forward || echo 'REJECT')"
	json_close_object
	
	# Proxy settings
	json_add_object "proxy"
	json_add_boolean "enabled" "$(uci -q get network-modes.router.proxy_enabled || echo 0)"
	json_add_string "type" "$(uci -q get network-modes.router.proxy_type || echo 'squid')"
	json_add_int "port" "$(uci -q get network-modes.router.proxy_port || echo 3128)"
	json_add_boolean "transparent" "$(uci -q get network-modes.router.proxy_transparent || echo 0)"
	json_add_boolean "dns_over_https" "$(uci -q get network-modes.router.dns_over_https || echo 0)"
	json_close_object
	
	# HTTPS Frontend settings
	json_add_object "https_frontend"
	json_add_boolean "enabled" "$(uci -q get network-modes.router.https_frontend || echo 0)"
	json_add_string "type" "$(uci -q get network-modes.router.frontend_type || echo 'nginx')"
	json_add_int "http_port" "$(uci -q get network-modes.router.frontend_http_port || echo 80)"
	json_add_int "https_port" "$(uci -q get network-modes.router.frontend_https_port || echo 443)"
	json_add_boolean "letsencrypt" "$(uci -q get network-modes.router.letsencrypt || echo 0)"
	json_close_object
	
	# Virtual hosts
	json_add_array "virtual_hosts"
	local idx=0
	while true; do
		local domain=$(uci -q get network-modes.@vhost[$idx].domain)
		[ -z "$domain" ] && break
		
		json_add_object
		json_add_string "domain" "$domain"
		json_add_string "backend" "$(uci -q get network-modes.@vhost[$idx].backend)"
		json_add_int "port" "$(uci -q get network-modes.@vhost[$idx].port || echo 80)"
		json_add_boolean "ssl" "$(uci -q get network-modes.@vhost[$idx].ssl || echo 0)"
		json_close_object
		
		idx=$((idx + 1))
	done
	json_close_array
	
	# Available protocols
	json_add_array "available_wan_protocols"
	json_add_string "" "dhcp"
	json_add_string "" "static"
	json_add_string "" "pppoe"
	json_add_string "" "pptp"
	json_add_string "" "l2tp"
	json_close_array
	
	json_dump
}

get_dmz_config() {
	json_init

	json_add_string "mode" "dmz"
	json_add_string "name" "Router + DMZ"
	json_add_string "description" "LAN avec NAT + segment DMZ isolé"

	local wan_iface=$(uci -q get network-modes.dmz.wan_interface || echo "eth1")
	local wan_proto=$(uci -q get network-modes.dmz.wan_protocol || echo "dhcp")
	local lan_iface=$(uci -q get network-modes.dmz.lan_interface || echo "br-lan")
	local lan_ip=$(uci -q get network-modes.dmz.lan_ip || echo "192.168.1.1")
	local lan_netmask=$(uci -q get network-modes.dmz.lan_netmask || echo "255.255.255.0")
	local dmz_iface=$(uci -q get network-modes.dmz.dmz_interface || echo "eth2")
	local dmz_ip=$(uci -q get network-modes.dmz.dmz_ip || echo "192.168.50.1")
	local dmz_netmask=$(uci -q get network-modes.dmz.dmz_netmask || echo "255.255.255.0")
	local dmz_start=$(uci -q get network-modes.dmz.dmz_dhcp_start || echo "50")
	local dmz_limit=$(uci -q get network-modes.dmz.dmz_dhcp_limit || echo "80")
	local dmz_isolated=$(uci -q get network-modes.dmz.dmz_isolated || echo "1")

	json_add_object "wan"
	json_add_string "interface" "$wan_iface"
	json_add_string "protocol" "$wan_proto"
	json_add_array "protocols"
	for proto in dhcp static pppoe; do
		json_add_string "" "$proto"
	done
	json_close_array
	json_close_object

	json_add_object "lan"
	json_add_string "interface" "$lan_iface"
	json_add_string "ip_address" "$lan_ip"
	json_add_string "netmask" "$lan_netmask"
	json_close_object

	json_add_object "dmz"
	json_add_string "interface" "$dmz_iface"
	json_add_string "ip_address" "$dmz_ip"
	json_add_string "netmask" "$dmz_netmask"
	json_add_int "dhcp_start" "$dmz_start"
	json_add_int "dhcp_limit" "$dmz_limit"
	json_add_boolean "isolated" "$([ "$dmz_isolated" = "1" ] && echo 1 || echo 0)"
	json_close_object

	json_add_array "available_interfaces"
	for iface in $(ls /sys/class/net/ | grep -v "^lo$"); do
		json_add_string "" "$iface"
	done
	json_close_array

	json_dump
}

# Get travel router configuration
get_travel_config() {
	json_init

	local client_iface=$(uci -q get network-modes.travel.client_interface || echo "wlan1")
	local hotspot_iface=$(uci -q get network-modes.travel.hotspot_interface || echo "wlan0")
	local client_radio=$(uci -q get network-modes.travel.client_radio || echo "radio1")
	local hotspot_radio=$(uci -q get network-modes.travel.hotspot_radio || echo "radio0")
	local clone_mac=$(uci -q get network-modes.travel.clone_mac || echo "")

	json_add_string "mode" "travel"
	json_add_string "name" "$(uci -q get network-modes.travel.name || echo 'Travel Router')"
	json_add_string "description" "$(uci -q get network-modes.travel.description || echo 'Portable WiFi router for hotels and coworking spaces')"

	json_add_object "client"
	json_add_string "interface" "$client_iface"
	json_add_string "radio" "$client_radio"
	json_add_string "ssid" "$(uci -q get network-modes.travel.ssid || echo '')"
	json_add_string "encryption" "$(uci -q get network-modes.travel.encryption || echo 'sae-mixed')"
	json_add_string "password" "$(uci -q get network-modes.travel.password || echo '')"
	json_add_string "clone_mac" "$clone_mac"
	json_add_boolean "mac_clone_enabled" "$([ -n "$clone_mac" ] && echo 1 || echo 0)"
	json_close_object

	json_add_object "hotspot"
	json_add_string "interface" "$hotspot_iface"
	json_add_string "radio" "$hotspot_radio"
	json_add_string "ssid" "$(uci -q get network-modes.travel.hotspot_ssid || echo 'SecuBox-Travel')"
	json_add_string "password" "$(uci -q get network-modes.travel.hotspot_password || echo 'TravelSafe123!')"
	json_add_string "band" "$(uci -q get network-modes.travel.hotspot_band || echo 'dual')"
	json_close_object

	json_add_object "lan"
	json_add_string "subnet" "$(uci -q get network-modes.travel.lan_subnet || echo '10.77.0.1')"
	json_add_string "netmask" "$(uci -q get network-modes.travel.lan_netmask || echo '255.255.255.0')"
	json_close_object

	json_add_array "available_interfaces"
	for iface in $(ls /sys/class/net/ 2>/dev/null | grep -E '^wl|^wlan' || true); do
		json_add_string "" "$iface"
	done
	json_close_array

	json_add_array "available_radios"
	for radio in $(uci show wireless 2>/dev/null | grep "=wifi-device" | cut -d'.' -f2 | cut -d'=' -f1); do
		json_add_string "" "$radio"
	done
	json_close_array

	json_dump
}

# Scan nearby WiFi networks for travel mode
travel_scan_networks() {
	json_init
	json_add_array "networks"

	local iface=$(uci -q get network-modes.travel.client_interface || echo "wlan1")
	local scan_output
	scan_output="$(iwinfo "$iface" scan 2>/dev/null || true)"

	if [ -z "$scan_output" ]; then
		json_close_array
		json_dump
		return
	fi

	local bssid=""
	local ssid=""
	local channel=""
	local signal=""
	local encryption=""
	local quality=""

	while IFS= read -r line; do
		case "$line" in
			Cell*)
				if [ -n "$bssid" ]; then
					json_add_object
					json_add_string "ssid" "${ssid:-Unknown}"
					json_add_string "bssid" "$bssid"
					json_add_string "channel" "${channel:-?}"
					json_add_string "signal" "${signal:-N/A}"
					json_add_string "quality" "${quality:-N/A}"
					json_add_string "encryption" "${encryption:-Unknown}"
					json_close_object
				fi
				bssid=$(printf '%s\n' "$line" | awk '{print $5}')
				ssid=""
				channel=""
				signal=""
				encryption=""
				quality=""
				;;
			*"ESSID:"*)
				ssid=$(printf '%s\n' "$line" | sed -n 's/.*ESSID: "\(.*\)".*/\1/p')
				;;
			*"Channel:"*)
				channel=$(printf '%s\n' "$line" | awk -F'Channel:' '{print $2}' | awk '{print $1}')
				;;
			*"Signal:"*)
				signal=$(printf '%s\n' "$line" | awk -F'Signal:' '{print $2}' | awk '{print $1" "$2}')
				if echo "$line" | grep -q 'Quality'; then
					quality=$(printf '%s\n' "$line" | sed -n 's/.*Quality: \([0-9\/]*\).*/\1/p')
				fi
				;;
			*"Encryption:"*)
				encryption=$(printf '%s\n' "$line" | sed -n 's/.*Encryption: //p')
				;;
		esac
	done <<EOF
$scan_output
EOF

	if [ -n "$bssid" ]; then
		json_add_object
		json_add_string "ssid" "${ssid:-Unknown}"
		json_add_string "bssid" "$bssid"
		json_add_string "channel" "${channel:-?}"
		json_add_string "signal" "${signal:-N/A}"
		json_add_string "quality" "${quality:-N/A}"
		json_add_string "encryption" "${encryption:-Unknown}"
		json_close_object
	fi

	json_close_array
	json_dump
}

# Apply mode change (with actual network reconfiguration and rollback timer)
apply_mode() {
	if ! is_module_enabled; then
		json_init
		json_add_boolean "success" 0
		json_add_string "error" "module_disabled"
		json_add_string "message" "Network Modes module is disabled in SecuBox. Enable it before applying changes."
		json_dump
		return
	fi
	json_init

	local pending_mode=$(uci -q get network-modes.config.pending_mode || echo "")

	if [ -z "$pending_mode" ]; then
		json_add_boolean "success" 0
		json_add_string "error" "Aucun mode en attente. Utilisez set_mode d'abord."
		json_dump
		return
	fi

	local current_mode=$(uci -q get network-modes.config.current_mode || echo "router")

	# Backup current config
	mkdir -p "$BACKUP_DIR"
	local timestamp="$(date +%Y%m%d_%H%M%S)"
	local backup_file="$BACKUP_DIR/backup_${timestamp}.tar.gz"
	tar -czf "$backup_file" /etc/config/network /etc/config/wireless /etc/config/firewall /etc/config/dhcp 2>/dev/null
	uci set network-modes.config.last_backup="$backup_file"
	uci set network-modes.config.last_backup_time="$(date '+%Y-%m-%d %H:%M:%S')"

	# Apply network configuration based on mode
	case "$pending_mode" in
		router)
		# Router mode: NAT, DHCP server, firewall
		# WAN interface
		uci delete network.wan 2>/dev/null
		uci set network.wan=interface
		uci set network.wan.proto='dhcp'
		uci set network.wan.device='eth1'

		# LAN interface
		uci set network.lan=interface
		uci set network.lan.proto='static'
		uci set network.lan.device='eth0'
		uci set network.lan.ipaddr='192.168.1.1'
		uci set network.lan.netmask='255.255.255.0'

		# DHCP server
		uci set dhcp.lan=dhcp
		uci set dhcp.lan.interface='lan'
		uci set dhcp.lan.start='100'
		uci set dhcp.lan.limit='150'
		uci set dhcp.lan.leasetime='12h'

		# Firewall zones
		uci set firewall.@zone[0]=zone
		uci set firewall.@zone[0].name='lan'
		uci set firewall.@zone[0].input='ACCEPT'
		uci set firewall.@zone[0].output='ACCEPT'
		uci set firewall.@zone[0].forward='ACCEPT'

		uci set firewall.@zone[1]=zone
		uci set firewall.@zone[1].name='wan'
		uci set firewall.@zone[1].input='REJECT'
		uci set firewall.@zone[1].output='ACCEPT'
		uci set firewall.@zone[1].forward='REJECT'
		uci set firewall.@zone[1].masq='1'
		uci set firewall.@zone[1].mtu_fix='1'

		generate_squid_config
		generate_tinyproxy_config
		generate_privoxy_config
		configure_doh_proxy
		apply_transparent_proxy_rules
		deploy_nginx_vhosts
		;;
	dmz)
		local dmz_wan=$(uci -q get network-modes.dmz.wan_interface || echo "eth1")
		local dmz_wan_proto=$(uci -q get network-modes.dmz.wan_protocol || echo "dhcp")
		local dmz_lan_iface=$(uci -q get network-modes.dmz.lan_interface || echo "br-lan")
		local dmz_lan_ip=$(uci -q get network-modes.dmz.lan_ip || echo "192.168.1.1")
		local dmz_lan_netmask=$(uci -q get network-modes.dmz.lan_netmask || echo "255.255.255.0")
		local dmz_iface=$(uci -q get network-modes.dmz.dmz_interface || echo "eth2")
		local dmz_ip=$(uci -q get network-modes.dmz.dmz_ip || echo "192.168.50.1")
		local dmz_netmask=$(uci -q get network-modes.dmz.dmz_netmask || echo "255.255.255.0")
		local dmz_start=$(uci -q get network-modes.dmz.dmz_dhcp_start || echo "50")
		local dmz_limit=$(uci -q get network-modes.dmz.dmz_dhcp_limit || echo "80")
		local dmz_isolated_flag=$(uci -q get network-modes.dmz.dmz_isolated || echo "1")

		uci delete network.wan 2>/dev/null
		uci set network.wan=interface
		uci set network.wan.device="$dmz_wan"
		uci set network.wan.proto="$dmz_wan_proto"

		uci set network.lan=interface
		uci set network.lan.proto='static'
		uci set network.lan.device="$dmz_lan_iface"
		uci set network.lan.ipaddr="$dmz_lan_ip"
		uci set network.lan.netmask="$dmz_lan_netmask"

		uci delete network.dmz 2>/dev/null
		uci set network.dmz=interface
		uci set network.dmz.proto='static'
		uci set network.dmz.device="$dmz_iface"
		uci set network.dmz.ipaddr="$dmz_ip"
		uci set network.dmz.netmask="$dmz_netmask"

		uci set dhcp.lan=dhcp
		uci set dhcp.lan.interface='lan'
		uci set dhcp.lan.start='100'
		uci set dhcp.lan.limit='150'
		uci set dhcp.lan.leasetime='12h'

		uci delete dhcp.dmz 2>/dev/null
		uci set dhcp.dmz=dhcp
		uci set dhcp.dmz.interface='dmz'
		uci set dhcp.dmz.start="$dmz_start"
		uci set dhcp.dmz.limit="$dmz_limit"
		uci set dhcp.dmz.leasetime='12h'

		uci -q delete firewall.lan
		uci set firewall.lan=zone
		uci set firewall.lan.name='lan'
		uci set firewall.lan.network='lan'
		uci set firewall.lan.input='ACCEPT'
		uci set firewall.lan.output='ACCEPT'
		uci set firewall.lan.forward='ACCEPT'

		uci -q delete firewall.wan
		uci set firewall.wan=zone
		uci set firewall.wan.name='wan'
		uci set firewall.wan.network='wan'
		uci set firewall.wan.input='REJECT'
		uci set firewall.wan.output='ACCEPT'
		uci set firewall.wan.forward='REJECT'
		uci set firewall.wan.masq='1'
		uci set firewall.wan.mtu_fix='1'

		uci -q delete firewall.dmz
		uci set firewall.dmz=zone
		uci set firewall.dmz.name='dmz'
		uci set firewall.dmz.network='dmz'
		uci set firewall.dmz.input='REJECT'
		uci set firewall.dmz.output='ACCEPT'
		uci set firewall.dmz.forward='REJECT'

		uci -q delete firewall.dmz_wan
		uci set firewall.dmz_wan=forwarding
		uci set firewall.dmz_wan.src='dmz'
		uci set firewall.dmz_wan.dest='wan'

		uci -q delete firewall.dmz_lan 2>/dev/null
		if [ "$dmz_isolated_flag" != "1" ]; then
			uci set firewall.dmz_lan=forwarding
			uci set firewall.dmz_lan.src='dmz'
			uci set firewall.dmz_lan.dest='lan'
		fi
		;;
	travel)
		local client_iface=$(uci -q get network-modes.travel.client_interface || echo "wlan1")
		local client_radio=$(uci -q get network-modes.travel.client_radio || echo "radio1")
		local hotspot_radio=$(uci -q get network-modes.travel.hotspot_radio || echo "radio0")
		local travel_ssid=$(uci -q get network-modes.travel.ssid || echo "")
		local travel_password=$(uci -q get network-modes.travel.password || echo "")
		local travel_encryption=$(uci -q get network-modes.travel.encryption || echo "sae-mixed")
		local hotspot_ssid=$(uci -q get network-modes.travel.hotspot_ssid || echo "SecuBox-Travel")
		local hotspot_password=$(uci -q get network-modes.travel.hotspot_password || echo "TravelSafe123!")
		local clone_mac=$(uci -q get network-modes.travel.clone_mac || echo "")
		local lan_ip=$(uci -q get network-modes.travel.lan_subnet || echo "10.77.0.1")
		local lan_netmask=$(uci -q get network-modes.travel.lan_netmask || echo "255.255.255.0")

		uci delete network.wan 2>/dev/null
		uci set network.wan=interface
		uci set network.wan.proto='dhcp'
		uci set network.wan.device="$client_iface"

		uci set network.lan=interface
		uci set network.lan.proto='static'
		uci set network.lan.device='br-lan'
		uci set network.lan.ipaddr="$lan_ip"
		uci set network.lan.netmask="$lan_netmask"

		uci set dhcp.lan=dhcp
		uci set dhcp.lan.interface='lan'
		uci set dhcp.lan.start='60'
		uci set dhcp.lan.limit='80'
		uci set dhcp.lan.leasetime='6h'

		uci set firewall.@zone[0]=zone
		uci set firewall.@zone[0].name='lan'
		uci set firewall.@zone[0].input='ACCEPT'
		uci set firewall.@zone[0].output='ACCEPT'
		uci set firewall.@zone[0].forward='ACCEPT'

		uci set firewall.@zone[1]=zone
		uci set firewall.@zone[1].name='wan'
		uci set firewall.@zone[1].network='wan'
		uci set firewall.@zone[1].input='REJECT'
		uci set firewall.@zone[1].output='ACCEPT'
		uci set firewall.@zone[1].forward='REJECT'
		uci set firewall.@zone[1].masq='1'
		uci set firewall.@zone[1].mtu_fix='1'

		uci delete wireless.travel_sta 2>/dev/null
		uci set wireless.travel_sta=wifi-iface
		uci set wireless.travel_sta.device="$client_radio"
		uci set wireless.travel_sta.mode='sta'
		uci set wireless.travel_sta.network='wan'
		[ -n "$travel_ssid" ] && uci set wireless.travel_sta.ssid="$travel_ssid" || uci delete wireless.travel_sta.ssid 2>/dev/null
		uci set wireless.travel_sta.encryption="$travel_encryption"
		if [ -n "$travel_password" ]; then
			uci set wireless.travel_sta.key="$travel_password"
		else
			uci delete wireless.travel_sta.key 2>/dev/null
		fi
		if [ -n "$clone_mac" ]; then
			uci set wireless.travel_sta.macaddr="$clone_mac"
		else
			uci delete wireless.travel_sta.macaddr 2>/dev/null
		fi

		uci delete wireless.travel_ap 2>/dev/null
		uci set wireless.travel_ap=wifi-iface
		uci set wireless.travel_ap.device="$hotspot_radio"
		uci set wireless.travel_ap.mode='ap'
		uci set wireless.travel_ap.network='lan'
		uci set wireless.travel_ap.ssid="$hotspot_ssid"
		uci set wireless.travel_ap.encryption='sae-mixed'
		uci set wireless.travel_ap.key="$hotspot_password"
		uci set wireless.travel_ap.ieee80211w='1'
		uci set wireless.travel_ap.hidden='0'
		;;

	accesspoint)
			# Access Point mode: Bridge, no NAT, DHCP client
			# Delete WAN
			uci delete network.wan 2>/dev/null

			# Bridge LAN
			uci set network.lan=interface
			uci set network.lan.proto='dhcp'
			uci set network.lan.type='bridge'
			uci set network.lan.ifname='eth0 eth1'

			# Disable DHCP server
			uci set dhcp.lan.ignore='1'

			# Disable firewall
			uci set firewall.@zone[0].input='ACCEPT'
			uci set firewall.@zone[0].forward='ACCEPT'
			uci delete firewall.@zone[1] 2>/dev/null
			apply_accesspoint_features
			;;

	relay)
		# Repeater mode: STA + AP relay
			# Client interface (sta)
			uci set network.wwan=interface
			uci set network.wwan.proto='dhcp'

			# AP interface
			uci set network.lan=interface
			uci set network.lan.proto='static'
			uci set network.lan.ipaddr='192.168.2.1'
			uci set network.lan.netmask='255.255.255.0'

			# Relay with relayd
			uci set network.stabridge=interface
			uci set network.stabridge.proto='relay'
			uci set network.stabridge.network='lan wwan'

		apply_wireguard_config
		apply_mtu_clamping
		enable_tcp_bbr
		;;

	sniffer)
		local ports=$(uci -q get network-modes.sniffer.bridge_ports || echo "eth0 eth1")
		local bridge_iface=$(uci -q get network-modes.sniffer.bridge_interface || echo "br-lan")
		local promisc=$(uci -q get network-modes.sniffer.promiscuous || echo 1)

		uci delete network.wan 2>/dev/null
		uci set network.lan=interface
		uci set network.lan.proto='none'
		uci set network.lan.type='bridge'
		uci set network.lan.ifname="$ports"
		uci set network.lan.delegate='0'
		uci set network.lan.device="$bridge_iface"

		uci set dhcp.lan=dhcp
		uci set dhcp.lan.interface='lan'
		uci set dhcp.lan.ignore='1'

		uci set firewall.@zone[0].input='ACCEPT'
		uci set firewall.@zone[0].output='ACCEPT'
		uci set firewall.@zone[0].forward='ACCEPT'
		uci delete firewall.@zone[1] 2>/dev/null

		if [ "$promisc" = "1" ]; then
			for port in $ports; do
				ip link set "$port" promisc on 2>/dev/null || true
			done
		fi
		;;

	bridge)
			# Pure L2 bridge: all interfaces bridged, DHCP client
			uci delete network.wan 2>/dev/null

			# Bridge all interfaces
			uci set network.lan=interface
			uci set network.lan.proto='dhcp'
			uci set network.lan.type='bridge'
			uci set network.lan.bridge_empty='1'

			# Disable DHCP server
			uci set dhcp.lan.ignore='1'

			# Disable firewall
			uci delete firewall.@zone[1] 2>/dev/null
			;;
	esac

	if [ "$pending_mode" = "sniffer" ]; then
		start_packet_capture
	else
		stop_packet_capture
	fi

	# Commit all changes
	uci commit network
	uci commit dhcp
	uci commit firewall

	# Update current mode
	uci set network-modes.config.current_mode="$pending_mode"
	uci set network-modes.config.last_change="$(date '+%Y-%m-%d %H:%M:%S')"
	uci set network-modes.config.rollback_timer="120"
	uci commit network-modes

	# Start rollback timer (2 minutes) in background
	(
		for i in $(seq 120 -1 0); do
			echo "$i" > /tmp/network-mode-rollback.remaining
			sleep 1
		done

		# Timer expired, rollback
		logger -t network-modes "Rollback timer expired, reverting to $current_mode"

		cd /
		tar -xzf "$backup_file" 2>/dev/null
		/etc/init.d/network reload 2>&1
		/etc/init.d/firewall reload 2>&1
		/etc/init.d/dnsmasq reload 2>&1

		uci set network-modes.config.current_mode="$current_mode"
		uci delete network-modes.config.pending_mode 2>/dev/null
		uci set network-modes.config.last_change="$(date '+%Y-%m-%d %H:%M:%S') (auto-rollback)"
		uci commit network-modes

		rm -f /tmp/network-mode-rollback.pid
		rm -f /tmp/network-mode-rollback.remaining
	) &

	echo $! > /tmp/network-mode-rollback.pid

	# Apply network changes NOW (async to not block RPC)
	(
		sleep 2
		/etc/init.d/network reload 2>&1
		/etc/init.d/firewall reload 2>&1
		/etc/init.d/dnsmasq reload 2>&1
	) &

	json_add_boolean "success" 1
	json_add_string "mode" "$pending_mode"
	json_add_string "previous_mode" "$current_mode"
	json_add_string "message" "Mode $pending_mode appliqué. Confirmez dans les 2 minutes ou rollback automatique."
	json_add_string "backup" "$backup_file"
	json_add_int "rollback_seconds" 120

	json_dump
}

# Update mode settings
update_settings() {
	read input
	json_load "$input"
	json_get_var mode mode

	json_init
	
	case "$mode" in
		sniffer)
			json_get_var bridge_interface bridge_interface
			json_get_var capture_interface capture_interface
			json_get_var netifyd_enabled netifyd_enabled
			json_get_var promiscuous promiscuous
			
			[ -n "$bridge_interface" ] && uci set network-modes.sniffer.bridge_interface="$bridge_interface"
			[ -n "$capture_interface" ] && uci set network-modes.sniffer.capture_interface="$capture_interface"
			[ -n "$netifyd_enabled" ] && uci set network-modes.sniffer.netifyd_enabled="$netifyd_enabled"
			[ -n "$promiscuous" ] && uci set network-modes.sniffer.promiscuous="$promiscuous"
			;;
		accesspoint)
			json_get_var wifi_channel wifi_channel
			json_get_var wifi_htmode wifi_htmode
			json_get_var wifi_txpower wifi_txpower
			json_get_var roaming_enabled roaming_enabled
			json_get_var band_steering band_steering
			json_get_var rrm_enabled rrm_enabled
			json_get_var wnm_enabled wnm_enabled
			json_get_var airtime_fairness airtime_fairness
			json_get_var beamforming beamforming
			
			[ -n "$wifi_channel" ] && uci set network-modes.accesspoint.wifi_channel="$wifi_channel"
			[ -n "$wifi_htmode" ] && uci set network-modes.accesspoint.wifi_htmode="$wifi_htmode"
			[ -n "$wifi_txpower" ] && uci set network-modes.accesspoint.wifi_txpower="$wifi_txpower"
			[ -n "$roaming_enabled" ] && uci set network-modes.accesspoint.roaming_enabled="$roaming_enabled"
			[ -n "$band_steering" ] && uci set network-modes.accesspoint.band_steering="$band_steering"
			[ -n "$rrm_enabled" ] && uci set network-modes.accesspoint.rrm_enabled="$rrm_enabled"
			[ -n "$wnm_enabled" ] && uci set network-modes.accesspoint.wnm_enabled="$wnm_enabled"
			[ -n "$airtime_fairness" ] && uci set network-modes.accesspoint.airtime_fairness="$airtime_fairness"
			[ -n "$beamforming" ] && uci set network-modes.accesspoint.beamforming="$beamforming"
			;;
		relay)
			json_get_var wireguard_enabled wireguard_enabled
			json_get_var wireguard_interface wireguard_interface
			json_get_var wireguard_mtu wireguard_mtu
			json_get_var mtu_optimization mtu_optimization
			json_get_var mss_clamping mss_clamping
			json_get_var relay_interface relay_interface
			json_get_var lan_interface lan_interface
			json_get_var tcp_optimization tcp_optimization
			json_get_var conntrack_max conntrack_max
			
			[ -n "$wireguard_enabled" ] && uci set network-modes.relay.wireguard_enabled="$wireguard_enabled"
			[ -n "$wireguard_interface" ] && uci set network-modes.relay.wireguard_interface="$wireguard_interface"
			[ -n "$wireguard_mtu" ] && uci set network-modes.relay.wireguard_mtu="$wireguard_mtu"
			[ -n "$relay_interface" ] && uci set network-modes.relay.relay_interface="$relay_interface"
			[ -n "$lan_interface" ] && uci set network-modes.relay.lan_interface="$lan_interface"
			[ -n "$mtu_optimization" ] && uci set network-modes.relay.mtu_optimization="$mtu_optimization"
			[ -n "$mss_clamping" ] && uci set network-modes.relay.mss_clamping="$mss_clamping"
			[ -n "$tcp_optimization" ] && uci set network-modes.relay.tcp_optimization="$tcp_optimization"
			[ -n "$conntrack_max" ] && uci set network-modes.relay.conntrack_max="$conntrack_max"
			;;
		router)
			json_get_var wan_interface wan_interface
			json_get_var wan_protocol wan_protocol
			json_get_var nat_enabled nat_enabled
			json_get_var firewall_enabled firewall_enabled
			json_get_var proxy_enabled proxy_enabled
			json_get_var proxy_type proxy_type
			json_get_var proxy_port proxy_port
			json_get_var https_frontend https_frontend
			json_get_var frontend_type frontend_type
			json_get_var transparent_proxy transparent_proxy
			json_get_var dns_over_https dns_over_https
			json_get_var letsencrypt letsencrypt
			
			[ -n "$wan_interface" ] && uci set network-modes.router.wan_interface="$wan_interface"
			[ -n "$wan_protocol" ] && uci set network-modes.router.wan_protocol="$wan_protocol"
			[ -n "$nat_enabled" ] && uci set network-modes.router.nat_enabled="$nat_enabled"
			[ -n "$firewall_enabled" ] && uci set network-modes.router.firewall_enabled="$firewall_enabled"
			[ -n "$proxy_enabled" ] && uci set network-modes.router.proxy_enabled="$proxy_enabled"
			[ -n "$proxy_type" ] && uci set network-modes.router.proxy_type="$proxy_type"
			[ -n "$proxy_port" ] && uci set network-modes.router.proxy_port="$proxy_port"
			[ -n "$https_frontend" ] && uci set network-modes.router.https_frontend="$https_frontend"
			[ -n "$frontend_type" ] && uci set network-modes.router.frontend_type="$frontend_type"
			[ -n "$transparent_proxy" ] && uci set network-modes.router.proxy_transparent="$transparent_proxy"
			[ -n "$dns_over_https" ] && uci set network-modes.router.dns_over_https="$dns_over_https"
			[ -n "$letsencrypt" ] && uci set network-modes.router.letsencrypt="$letsencrypt"
			;;
		dmz)
			json_get_var wan_interface wan_interface
			json_get_var wan_protocol wan_protocol
			json_get_var lan_interface lan_interface
			json_get_var lan_ip lan_ip
			json_get_var lan_netmask lan_netmask
			json_get_var dmz_interface dmz_interface
			json_get_var dmz_ip dmz_ip
			json_get_var dmz_netmask dmz_netmask
			json_get_var dmz_dhcp_start dmz_dhcp_start
			json_get_var dmz_dhcp_limit dmz_dhcp_limit
			json_get_var dmz_isolated dmz_isolated
			
			[ -n "$wan_interface" ] && uci set network-modes.dmz.wan_interface="$wan_interface"
			[ -n "$wan_protocol" ] && uci set network-modes.dmz.wan_protocol="$wan_protocol"
			[ -n "$lan_interface" ] && uci set network-modes.dmz.lan_interface="$lan_interface"
			[ -n "$lan_ip" ] && uci set network-modes.dmz.lan_ip="$lan_ip"
			[ -n "$lan_netmask" ] && uci set network-modes.dmz.lan_netmask="$lan_netmask"
			[ -n "$dmz_interface" ] && uci set network-modes.dmz.dmz_interface="$dmz_interface"
			[ -n "$dmz_ip" ] && uci set network-modes.dmz.dmz_ip="$dmz_ip"
			[ -n "$dmz_netmask" ] && uci set network-modes.dmz.dmz_netmask="$dmz_netmask"
			[ -n "$dmz_dhcp_start" ] && uci set network-modes.dmz.dmz_dhcp_start="$dmz_dhcp_start"
			[ -n "$dmz_dhcp_limit" ] && uci set network-modes.dmz.dmz_dhcp_limit="$dmz_dhcp_limit"
			[ -n "$dmz_isolated" ] && uci set network-modes.dmz.dmz_isolated="$dmz_isolated"
			;;
		travel)
			json_get_var client_interface client_interface
			json_get_var client_radio client_radio
			json_get_var hotspot_radio hotspot_radio
			json_get_var ssid ssid
			json_get_var password password
			json_get_var encryption encryption
			json_get_var hotspot_ssid hotspot_ssid
			json_get_var hotspot_password hotspot_password
			json_get_var clone_mac clone_mac
			json_get_var lan_subnet lan_subnet
			json_get_var lan_netmask lan_netmask

			[ -n "$client_interface" ] && uci set network-modes.travel.client_interface="$client_interface"
			[ -n "$client_radio" ] && uci set network-modes.travel.client_radio="$client_radio"
			[ -n "$hotspot_radio" ] && uci set network-modes.travel.hotspot_radio="$hotspot_radio"
			[ -n "$ssid" ] && uci set network-modes.travel.ssid="$ssid"
			[ -n "$password" ] && uci set network-modes.travel.password="$password"
			[ -n "$encryption" ] && uci set network-modes.travel.encryption="$encryption"
			[ -n "$hotspot_ssid" ] && uci set network-modes.travel.hotspot_ssid="$hotspot_ssid"
			[ -n "$hotspot_password" ] && uci set network-modes.travel.hotspot_password="$hotspot_password"
			[ -n "$clone_mac" ] && uci set network-modes.travel.clone_mac="$clone_mac"
			[ -n "$lan_subnet" ] && uci set network-modes.travel.lan_subnet="$lan_subnet"
			[ -n "$lan_netmask" ] && uci set network-modes.travel.lan_netmask="$lan_netmask"
			;;
		doublenat)
			json_get_var wan_interface wan_interface
			json_get_var wan_protocol wan_protocol
			json_get_var lan_interface lan_interface
			json_get_var lan_ip lan_ip
			json_get_var lan_netmask lan_netmask
			json_get_var guest_network guest_network
			json_get_var isolate_guest isolate_guest
			json_get_var upnp_enabled upnp_enabled
			json_get_var dmz_host dmz_host

			[ -n "$wan_interface" ] && uci set network-modes.doublenat.wan_interface="$wan_interface"
			[ -n "$wan_protocol" ] && uci set network-modes.doublenat.wan_protocol="$wan_protocol"
			[ -n "$lan_interface" ] && uci set network-modes.doublenat.lan_interface="$lan_interface"
			[ -n "$lan_ip" ] && uci set network-modes.doublenat.lan_ip="$lan_ip"
			[ -n "$lan_netmask" ] && uci set network-modes.doublenat.lan_netmask="$lan_netmask"
			[ -n "$guest_network" ] && uci set network-modes.doublenat.guest_network="$guest_network"
			[ -n "$isolate_guest" ] && uci set network-modes.doublenat.isolate_guest="$isolate_guest"
			[ -n "$upnp_enabled" ] && uci set network-modes.doublenat.upnp_enabled="$upnp_enabled"
			[ -n "$dmz_host" ] && uci set network-modes.doublenat.dmz_host="$dmz_host"
			;;
		multiwan)
			json_get_var wan_primary wan_primary
			json_get_var wan_secondary wan_secondary
			json_get_var policy policy
			json_get_var tracking_host tracking_host
			json_get_var tracking_interval tracking_interval
			json_get_var failover_hold failover_hold
			json_get_var load_balance load_balance
			json_get_var use_mwan3 use_mwan3

			[ -n "$wan_primary" ] && uci set network-modes.multiwan.wan_primary="$wan_primary"
			[ -n "$wan_secondary" ] && uci set network-modes.multiwan.wan_secondary="$wan_secondary"
			[ -n "$policy" ] && uci set network-modes.multiwan.policy="$policy"
			[ -n "$tracking_host" ] && uci set network-modes.multiwan.tracking_host="$tracking_host"
			[ -n "$tracking_interval" ] && uci set network-modes.multiwan.tracking_interval="$tracking_interval"
			[ -n "$failover_hold" ] && uci set network-modes.multiwan.failover_hold="$failover_hold"
			[ -n "$load_balance" ] && uci set network-modes.multiwan.load_balance="$load_balance"
			[ -n "$use_mwan3" ] && uci set network-modes.multiwan.use_mwan3="$use_mwan3"
			;;
		vpnrelay)
			json_get_var vpn_type vpn_type
			json_get_var vpn_provider vpn_provider
			json_get_var wg_interface wg_interface
			json_get_var openvpn_profile openvpn_profile
			json_get_var upstream_interface upstream_interface
			json_get_var policy_routing policy_routing
			json_get_var dns_override dns_override
			json_get_var kill_switch kill_switch
			json_get_var lan_bypass lan_bypass

			[ -n "$vpn_type" ] && uci set network-modes.vpnrelay.vpn_type="$vpn_type"
			[ -n "$vpn_provider" ] && uci set network-modes.vpnrelay.vpn_provider="$vpn_provider"
			[ -n "$wg_interface" ] && uci set network-modes.vpnrelay.wg_interface="$wg_interface"
			[ -n "$openvpn_profile" ] && uci set network-modes.vpnrelay.openvpn_profile="$openvpn_profile"
			[ -n "$upstream_interface" ] && uci set network-modes.vpnrelay.upstream_interface="$upstream_interface"
			[ -n "$policy_routing" ] && uci set network-modes.vpnrelay.policy_routing="$policy_routing"
			[ -n "$dns_override" ] && uci set network-modes.vpnrelay.dns_override="$dns_override"
			[ -n "$kill_switch" ] && uci set network-modes.vpnrelay.kill_switch="$kill_switch"
			[ -n "$lan_bypass" ] && uci set network-modes.vpnrelay.lan_bypass="$lan_bypass"
			;;
		bridge)
			if ! uci -q get network-modes.bridge >/dev/null 2>&1; then
				uci set network-modes.bridge=mode
				uci set network-modes.bridge.name='Bridge'
				uci set network-modes.bridge.description='Layer 2 bridge template'
			fi
			json_get_var bridge_interface bridge_interface
			json_get_var bridge_ports bridge_ports
			json_get_var dhcp_client dhcp_client
			json_get_var firewall_mode firewall_mode

			[ -n "$bridge_interface" ] && uci set network-modes.bridge.bridge_interface="$bridge_interface"
			[ -n "$bridge_ports" ] && uci set network-modes.bridge.bridge_ports="$bridge_ports"
			[ -n "$dhcp_client" ] && uci set network-modes.bridge.dhcp_client="$dhcp_client"
			[ -n "$firewall_mode" ] && uci set network-modes.bridge.firewall_mode="$firewall_mode"
			;;
		*)
			json_add_boolean "success" 0
			json_add_string "error" "Invalid mode"
			json_dump
			return
			;;
	esac
	
	uci commit network-modes
	local current_mode=$(uci -q get network-modes.config.current_mode || echo "")
	local module_active=1
	if ! is_module_enabled; then
		module_active=0
	fi
	if [ "$module_active" = "1" ] && [ "$mode" = "accesspoint" ] && [ "$current_mode" = "accesspoint" ]; then
		apply_accesspoint_features
	fi
	if [ "$module_active" = "1" ] && [ "$mode" = "sniffer" ] && [ "$current_mode" = "sniffer" ]; then
		start_packet_capture
	elif [ "$mode" = "sniffer" ]; then
		stop_packet_capture
	fi
	
	json_add_boolean "success" 1
	if [ "$module_active" != "1" ]; then
		json_add_string "message" "Module disabled in SecuBox. Preferences saved for $mode template."
	elif [ "$mode" = "$current_mode" ]; then
		json_add_string "message" "Settings updated for $mode mode"
	else
		json_add_string "message" "Settings saved for $mode template (current mode: $current_mode)"
	fi
	json_dump
}

# Squid proxy configuration
generate_squid_config() {
	local proxy_type=$(uci -q get network-modes.router.proxy_type || echo "none")
	local enabled=$(uci -q get network-modes.router.proxy_enabled || echo 0)
	[ "$proxy_type" = "squid" ] || return 0
	[ "$enabled" = "1" ] || return 0

	if ! command -v squid >/dev/null 2>&1; then
		logger -t network-modes "squid binary not found"
		return 1
	fi

	local proxy_port=$(uci -q get network-modes.router.proxy_port || echo 3128)
	local cache_size=$(uci -q get network-modes.router.proxy_cache_size || echo 256)
	mkdir -p /etc/squid /var/spool/squid /var/log/squid

	cat > /etc/squid/squid.conf <<EOF
# SecuBox Network Modes - Squid Configuration
# Generated: $(date)

http_port $proxy_port transparent
cache_dir ufs /var/spool/squid $cache_size 16 256
cache_mem 64 MB
maximum_object_size 4096 KB
minimum_object_size 0 KB

acl localnet src 192.168.0.0/16
acl localnet src 10.0.0.0/8
acl localnet src fc00::/7
acl SSL_ports port 443
acl Safe_ports port 80
acl Safe_ports port 443
acl CONNECT method CONNECT

http_access deny !Safe_ports
http_access deny CONNECT !SSL_ports
http_access allow localhost manager
http_access deny manager
http_access allow localnet
http_access allow localhost
http_access deny all

access_log /var/log/squid/access.log squid
cache_log /var/log/squid/cache.log
dns_nameservers 1.1.1.1 8.8.8.8
forwarded_for on
via on
EOF

	squid -z >/dev/null 2>&1 || true
	/etc/init.d/squid restart >/dev/null 2>&1 || true
}

generate_tinyproxy_config() {
	local proxy_type=$(uci -q get network-modes.router.proxy_type || echo "none")
	local enabled=$(uci -q get network-modes.router.proxy_enabled || echo 0)
	[ "$proxy_type" = "tinyproxy" ] || return 0
	[ "$enabled" = "1" ] || return 0

	if ! command -v tinyproxy >/dev/null 2>&1; then
		logger -t network-modes "tinyproxy binary not found"
		return 1
	fi

	local proxy_port=$(uci -q get network-modes.router.proxy_port || echo 8888)
	mkdir -p /etc/tinyproxy

	cat > /etc/tinyproxy/tinyproxy.conf <<EOF
User nobody
Group nogroup
Port $proxy_port
Listen 0.0.0.0
Timeout 600
DefaultErrorFile "/usr/share/tinyproxy/default.html"
Logfile "/var/log/tinyproxy/tinyproxy.log"
StatFile "/usr/share/tinyproxy/stats.html"
MaxClients 100
MinSpareServers 5
MaxSpareServers 20
StartServers 10
Allow 192.168.0.0/16
Allow 10.0.0.0/8
Allow 172.16.0.0/12
ViaProxyName "SecuBox"
EOF

	/etc/init.d/tinyproxy restart >/dev/null 2>&1 || true
}

generate_privoxy_config() {
	local proxy_type=$(uci -q get network-modes.router.proxy_type || echo "none")
	local enabled=$(uci -q get network-modes.router.proxy_enabled || echo 0)
	[ "$proxy_type" = "privoxy" ] || return 0
	[ "$enabled" = "1" ] || return 0

	if ! command -v privoxy >/dev/null 2>&1; then
		logger -t network-modes "privoxy binary not found"
		return 1
	fi

	local proxy_port=$(uci -q get network-modes.router.proxy_port || echo 8118)
	mkdir -p /etc/privoxy

	cat > /etc/privoxy/config <<EOF
listen-address  0.0.0.0:$proxy_port
toggle  1
enable-remote-toggle 0
enable-remote-http-toggle 0
accept-intercepted-requests 1
forward-socks5 / 127.0.0.1:9050 .
logfile /var/log/privoxy/logfile
EOF

	/etc/init.d/privoxy restart >/dev/null 2>&1 || true
}

apply_transparent_proxy_rules() {
	local proxy_enabled=$(uci -q get network-modes.router.proxy_enabled || echo 0)
	local proxy_port=$(uci -q get network-modes.router.proxy_port || echo 3128)
	local transparent=$(uci -q get network-modes.router.proxy_transparent || echo 0)

	uci -q delete firewall.proxy_redirect

	if [ "$proxy_enabled" = "1" ] && [ "$transparent" = "1" ]; then
		uci set firewall.proxy_redirect=redirect
		uci set firewall.proxy_redirect.name='Transparent Web Proxy'
		uci set firewall.proxy_redirect.src='lan'
		uci set firewall.proxy_redirect.proto='tcp'
		uci set firewall.proxy_redirect.src_dport='80'
		uci set firewall.proxy_redirect.dest_port="$proxy_port"
		uci set firewall.proxy_redirect.target='DNAT'
	fi
	uci commit firewall
	/etc/init.d/firewall reload >/dev/null 2>&1 || true
}

configure_doh_proxy() {
	local doh_enabled=$(uci -q get network-modes.router.dns_over_https || echo 0)
	[ "$doh_enabled" = "1" ] || return 0

	if ! command -v https_dns_proxy >/dev/null 2>&1; then
		logger -t network-modes "https_dns_proxy not installed"
		return 1
	fi

	local provider=$(uci -q get network-modes.router.doh_provider || echo "cloudflare")
	local doh_url
	case "$provider" in
		cloudflare) doh_url="https://1.1.1.1/dns-query" ;;
		google) doh_url="https://dns.google/dns-query" ;;
		quad9) doh_url="https://dns.quad9.net/dns-query" ;;
		*) doh_url="https://1.1.1.1/dns-query" ;;
	esac

	uci set https-dns-proxy.@https-dns-proxy[0]=https-dns-proxy
	uci set https-dns-proxy.@https-dns-proxy[0].resolver_url="$doh_url"
	uci set https-dns-proxy.@https-dns-proxy[0].listen_addr='127.0.0.1'
	uci set https-dns-proxy.@https-dns-proxy[0].listen_port='5053'
	uci commit https-dns-proxy

	uci set dhcp.@dnsmasq[0].noresolv='1'
	uci -q delete dhcp.@dnsmasq[0].server
	uci add_list dhcp.@dnsmasq[0].server="127.0.0.1#5053"
	uci commit dhcp

	/etc/init.d/https-dns-proxy restart >/dev/null 2>&1 || true
	/etc/init.d/dnsmasq restart >/dev/null 2>&1 || true
}

apply_accesspoint_features() {
	local iface="wireless.@wifi-iface[0]"
	uci -q show "$iface" >/dev/null 2>&1 || return 0
	local changed=0

	local ft_enabled=$(uci -q get network-modes.accesspoint.roaming_enabled || echo 0)
	if [ "$ft_enabled" = "1" ]; then
		local ssid=$(uci -q get $iface.ssid || echo "SecuBox")
		local mobility_domain=$(echo -n "$ssid" | md5sum 2>/dev/null | cut -c1-4)
		[ -z "$mobility_domain" ] && mobility_domain="a1b2"
		uci set $iface.ieee80211r='1'
		uci set $iface.mobility_domain="$mobility_domain"
		uci set $iface.ft_over_ds='1'
		uci set $iface.ft_psk_generate_local='1'
		uci set $iface.reassociation_deadline='1000'
		changed=1
	else
		uci set $iface.ieee80211r='0'
		uci -q delete $iface.mobility_domain
	fi

	local rrm_enabled=$(uci -q get network-modes.accesspoint.rrm_enabled || echo 0)
	if [ "$rrm_enabled" = "1" ]; then
		uci set $iface.ieee80211k='1'
		uci set $iface.rrm_neighbor_report='1'
		uci set $iface.rrm_beacon_report='1'
		changed=1
	else
		uci set $iface.ieee80211k='0'
		uci -q delete $iface.rrm_neighbor_report
		uci -q delete $iface.rrm_beacon_report
	fi

	local v_enabled=$(uci -q get network-modes.accesspoint.wnm_enabled || echo 0)
	if [ "$v_enabled" = "1" ]; then
		uci set $iface.ieee80211v='1'
		uci set $iface.bss_transition='1'
		uci set $iface.wnm_sleep_mode='1'
		changed=1
	else
		uci set $iface.ieee80211v='0'
		uci -q delete $iface.bss_transition
		uci -q delete $iface.wnm_sleep_mode
	fi

	local band=$(uci -q get network-modes.accesspoint.band_steering || echo 0)
	if [ "$band" = "1" ]; then
		local radio_2g=$(uci show wireless 2>/dev/null | grep "band='2g'" | head -n1)
		local radio_5g=$(uci show wireless 2>/dev/null | grep "band='5g'" | head -n1)
		if [ -n "$radio_2g" ] && [ -n "$radio_5g" ]; then
			uci set $iface.bss_load_update_period='60'
			uci set $iface.chan_util_avg_period='600'
			uci set $iface.disassoc_low_ack='1'
			changed=1
		else
			logger -t network-modes "band steering requested but dual-band radios missing"
		fi
	else
		uci -q delete $iface.bss_load_update_period
		uci -q delete $iface.chan_util_avg_period
		uci -q delete $iface.disassoc_low_ack
	fi

	if [ "$changed" = "1" ]; then
		uci commit wireless
		wifi reload >/dev/null 2>&1 || true
	fi
}

start_packet_capture() {
	local capture_enabled=$(uci -q get network-modes.sniffer.pcap_capture || echo 0)
	if [ "$capture_enabled" != "1" ]; then
		stop_packet_capture
		return 0
	fi

	if ! command -v tcpdump >/dev/null 2>&1; then
		logger -t network-modes "tcpdump not installed"
		return 1
	fi

	local capture_interface=$(uci -q get network-modes.sniffer.capture_interface || echo "br-lan")
	local capture_filter=$(uci -q get network-modes.sniffer.capture_filter || echo "")
	local max_size=$(uci -q get network-modes.sniffer.pcap_max_size || echo "100")
	local rotate_count=$(uci -q get network-modes.sniffer.pcap_rotate || echo "10")

	mkdir -p "$PCAP_DIR"
	stop_packet_capture

	if [ -n "$capture_filter" ]; then
		tcpdump -i "$capture_interface" -w "$PCAP_DIR/capture.pcap" -C "$max_size" -W "$rotate_count" -s 0 $capture_filter >/dev/null 2>&1 &
	else
		tcpdump -i "$capture_interface" -w "$PCAP_DIR/capture.pcap" -C "$max_size" -W "$rotate_count" -s 0 >/dev/null 2>&1 &
	fi
	local pid=$!
	echo "$pid" > /var/run/tcpdump-sniffer.pid
}

stop_packet_capture() {
	if [ -f /var/run/tcpdump-sniffer.pid ]; then
		local pid=$(cat /var/run/tcpdump-sniffer.pid 2>/dev/null)
		[ -n "$pid" ] && kill "$pid" 2>/dev/null || true
		rm -f /var/run/tcpdump-sniffer.pid
	fi
	killall tcpdump >/dev/null 2>&1 || true
}

validate_pcap_filter() {
	read input
	json_load "$input"
	json_get_var filter filter

	if [ -z "$filter" ]; then
		json_init
		json_add_boolean "valid" 1
		json_add_string "filter" "all"
		json_dump
		return
	fi

	if command -v tcpdump >/dev/null 2>&1 && tcpdump -i any -d "$filter" >/dev/null 2>&1; then
		json_init
		json_add_boolean "valid" 1
		json_add_string "filter" "$filter"
		json_dump
	else
		json_init
		json_add_boolean "valid" 0
		json_add_string "error" "Invalid BPF syntax"
		json_dump
	fi
}

cleanup_old_pcaps() {
	local max_age=$(uci -q get network-modes.sniffer.pcap_retention_days || echo "7")
	mkdir -p "$PCAP_DIR"
	local deleted=0
	find "$PCAP_DIR" -name "*.pcap*" -mtime +$max_age -type f 2>/dev/null | while read -r file; do
		rm -f "$file"
		deleted=$((deleted + 1))
	done

	local total_size=$(du -sm "$PCAP_DIR" 2>/dev/null | cut -f1 || echo "0")

	json_init
	json_add_boolean "success" 1
	json_add_int "deleted" "$deleted"
	json_add_int "total_size_mb" "$total_size"
	json_dump
}

deploy_nginx_vhosts() {
	local frontend_enabled=$(uci -q get network-modes.router.https_frontend || echo 0)
	local frontend_type=$(uci -q get network-modes.router.frontend_type || echo nginx)
	[ "$frontend_enabled" = "1" ] || return 0
	[ "$frontend_type" = "nginx" ] || return 0

	if ! command -v nginx >/dev/null 2>&1; then
		logger -t network-modes "nginx not installed"
		return 1
	fi

	rm -f /etc/nginx/conf.d/vhost-*.conf 2>/dev/null || true
	mkdir -p /etc/nginx/conf.d /etc/acme

	local idx=0
	local deployed=0
	while true; do
		local domain=$(uci -q get network-modes.@vhost[$idx].domain)
		[ -n "$domain" ] || break
		local backend=$(uci -q get network-modes.@vhost[$idx].backend || echo "127.0.0.1")
		local port=$(uci -q get network-modes.@vhost[$idx].port || echo 80)
		local ssl=$(uci -q get network-modes.@vhost[$idx].ssl || echo 0)

		cat > "/etc/nginx/conf.d/vhost-$idx.conf" <<EOF
server {
	listen 80;
	server_name $domain;
EOF

	if [ "$ssl" = "1" ]; then
		cat >> "/etc/nginx/conf.d/vhost-$idx.conf" <<EOF
	return 301 https://\$server_name\$request_uri;
}

server {
	listen 443 ssl http2;
	server_name $domain;

	ssl_certificate /etc/acme/$domain/fullchain.cer;
	ssl_certificate_key /etc/acme/$domain/$domain.key;
	ssl_protocols TLSv1.2 TLSv1.3;
	ssl_ciphers HIGH:!aNULL:!MD5;

	location / {
		proxy_pass http://$backend:$port;
		proxy_set_header Host \$host;
		proxy_set_header X-Real-IP \$remote_addr;
		proxy_set_header X-Forwarded-For \$proxy_add_x_forwarded_for;
		proxy_set_header X-Forwarded-Proto \$scheme;
	}
}
EOF
	else
		cat >> "/etc/nginx/conf.d/vhost-$idx.conf" <<EOF
	location / {
		proxy_pass http://$backend:$port;
		proxy_set_header Host \$host;
		proxy_set_header X-Real-IP \$remote_addr;
		proxy_set_header X-Forwarded-For \$proxy_add_x_forwarded_for;
		proxy_set_header X-Forwarded-Proto \$scheme;
	}
}
EOF
	fi

		deployed=$((deployed + 1))
		idx=$((idx + 1))
	done

	/etc/init.d/nginx reload >/dev/null 2>&1 || true
	logger -t network-modes "Deployed $deployed nginx vhosts"
}

issue_letsencrypt_cert() {
	local domain="$1"
	[ -n "$domain" ] || return 1

	local acme_email=$(uci -q get network-modes.router.acme_email)
	[ -n "$acme_email" ] || acme_email="admin@$domain"

	if ! command -v /usr/lib/acme/acme.sh >/dev/null 2>&1; then
		opkg update >/dev/null 2>&1 || true
		opkg install acme acme-dnsapi >/dev/null 2>&1 || true
	fi

	/usr/lib/acme/acme.sh --issue -d "$domain" --webroot /www --accountemail "$acme_email" --force >/tmp/acme-issue.log 2>&1
	if [ $? -eq 0 ]; then
		mkdir -p /etc/acme/$domain
		/usr/lib/acme/acme.sh --install-cert \
			-d "$domain" \
			--cert-file /etc/acme/$domain/cert.cer \
			--key-file /etc/acme/$domain/$domain.key \
			--fullchain-file /etc/acme/$domain/fullchain.cer \
			--reloadcmd "/etc/init.d/nginx reload" >/dev/null 2>&1
		return 0
	else
		logger -t network-modes "ACME issue failed for $domain"
		return 1
	fi
}

validate_ssl_cert() {
	local domain="$1"
	local cert_file="/etc/acme/$domain/fullchain.cer"
	[ -f "$cert_file" ] || return 1
	command -v openssl >/dev/null 2>&1 || return 1

	local expiry_date=$(openssl x509 -enddate -noout -in "$cert_file" | cut -d= -f2)
	local expiry_epoch=$(date -d "$expiry_date" +%s 2>/dev/null || echo 0)
	local now_epoch=$(date +%s)
	[ "$expiry_epoch" -gt 0 ] || return 1
	local days_left=$(( (expiry_epoch - now_epoch) / 86400 ))
	logger -t network-modes "Cert $domain valid $days_left days"
	[ "$days_left" -gt 0 ]
}

# Generate WireGuard key pair and store in UCI
generate_wireguard_keys() {
	json_init

	if ! command -v wg >/dev/null 2>&1; then
		json_add_boolean "success" 0
		json_add_string "error" "wireguard-tools not installed"
		json_dump
		return
	fi

	local privkey="$(wg genkey 2>/dev/null)"
	if [ -z "$privkey" ]; then
		json_add_boolean "success" 0
		json_add_string "error" "failed to generate private key"
		json_dump
		return
	fi

	local pubkey
	pubkey="$(printf '%s' "$privkey" | wg pubkey 2>/dev/null)"

	if [ -z "$pubkey" ]; then
		json_add_boolean "success" 0
		json_add_string "error" "failed to derive public key"
		json_dump
		return
	fi

	uci set network-modes.relay.wg_private_key="$privkey"
	uci set network-modes.relay.wg_public_key="$pubkey"
	uci commit network-modes

	json_add_boolean "success" 1
	json_add_string "private_key" "$privkey"
	json_add_string "public_key" "$pubkey"
	json_dump
}

# Deploy WireGuard interface/peer config to /etc/config/network
apply_wireguard_config() {
	local wg_enabled=$(uci -q get network-modes.relay.wireguard_enabled || echo "0")
	[ "$wg_enabled" = "1" ] || return 0

	local privkey=$(uci -q get network-modes.relay.wg_private_key)
	local peer_pubkey=$(uci -q get network-modes.relay.wg_peer_pubkey)
	local peer_endpoint=$(uci -q get network-modes.relay.wg_peer_endpoint)
	local wg_port=$(uci -q get network-modes.relay.wg_port || echo "51820")
	local wg_ip=$(uci -q get network-modes.relay.wg_ip || echo "10.200.200.2/24")

	[ -n "$privkey" ] || return 1
	[ -n "$peer_pubkey" ] || return 1
	[ -n "$peer_endpoint" ] || return 1

	uci -q delete network.wg0
	uci -q delete network.wg0_peer

	uci set network.wg0=interface
	uci set network.wg0.proto='wireguard'
	uci set network.wg0.private_key="$privkey"
	uci set network.wg0.listen_port="$wg_port"
	uci add_list network.wg0.addresses="$wg_ip"

	uci set network.wg0_peer=wireguard_wg0
	uci set network.wg0_peer.public_key="$peer_pubkey"
	uci set network.wg0_peer.endpoint_host="$(echo "$peer_endpoint" | cut -d: -f1)"
	uci set network.wg0_peer.endpoint_port="$(echo "$peer_endpoint" | cut -d: -f2-)"
	uci set network.wg0_peer.persistent_keepalive='25'
	uci add_list network.wg0_peer.allowed_ips='0.0.0.0/0'

	uci commit network
	/etc/init.d/network reload >/dev/null 2>&1
}

# Configure firewall MSS clamping based on configured MTU
apply_mtu_clamping() {
	local mtu_optimization=$(uci -q get network-modes.relay.mtu_optimization || echo "0")
	[ "$mtu_optimization" = "1" ] || return 0

	local wg_mtu=$(uci -q get network-modes.relay.wg_mtu || echo "1420")
	local mss_value=$((wg_mtu - 40))
	if [ "$mss_value" -lt 500 ]; then
		mss_value=500
	fi

	uci -q delete firewall.mss_clamping
	uci set firewall.mss_clamping=rule
	uci set firewall.mss_clamping.name='WireGuard MSS Clamping'
	uci set firewall.mss_clamping.src='lan'
	uci set firewall.mss_clamping.dest='wan'
	uci set firewall.mss_clamping.proto='tcp'
	uci set firewall.mss_clamping.tcp_flags='SYN'
	uci set firewall.mss_clamping.target='TCPMSS'
	uci set firewall.mss_clamping.set_mss="$mss_value"
	uci commit firewall
	/etc/init.d/firewall reload >/dev/null 2>&1
}

# Enable TCP BBR congestion control if requested
enable_tcp_bbr() {
	local tcp_optimize=$(uci -q get network-modes.relay.tcp_optimization || echo "0")
	[ "$tcp_optimize" = "1" ] || return 0

	if ! modprobe tcp_bbr 2>/dev/null; then
		logger -t network-modes "tcp_bbr module unavailable"
		return 1
	fi

	cat > /etc/sysctl.d/90-tcp-bbr.conf <<EOF
net.core.default_qdisc=fq
net.ipv4.tcp_congestion_control=bbr
EOF

	sysctl -p /etc/sysctl.d/90-tcp-bbr.conf >/dev/null 2>&1
}

# Add virtual host
add_vhost() {
	read input
	json_load "$input"
	json_get_var domain domain
	json_get_var backend backend
	json_get_var port port
	json_get_var ssl ssl
	
	json_init
	
	if [ -z "$domain" ] || [ -z "$backend" ]; then
		json_add_boolean "success" 0
		json_add_string "error" "Domain and backend are required"
		json_dump
		return
	fi
	
	uci add network-modes vhost
	uci set network-modes.@vhost[-1].domain="$domain"
	uci set network-modes.@vhost[-1].backend="$backend"
	uci set network-modes.@vhost[-1].port="${port:-80}"
	uci set network-modes.@vhost[-1].ssl="${ssl:-0}"
	uci commit network-modes
	
	json_add_boolean "success" 1
	json_add_string "message" "Virtual host $domain added"
	json_dump
}

# Generate config for current mode
generate_config() {
	read input
	json_load "$input"
	json_get_var mode mode
	
	json_init
	
	local config=""
	
	case "$mode" in
		sniffer)
			local bridge=$(uci -q get network-modes.sniffer.bridge_interface || echo "br-lan")
			config="# Sniffer Mode Configuration
# /etc/config/network

config interface 'loopback'
    option proto 'static'
    option ipaddr '127.0.0.1'
    option netmask '255.0.0.0'
    option device 'lo'

config device
    option name '$bridge'
    option type 'bridge'
    list ports 'eth0'
    list ports 'eth1'

config interface 'lan'
    option device '$bridge'
    option proto 'none'

# Disable DHCP
# /etc/config/dhcp
config dhcp 'lan'
    option ignore '1'

# Enable promiscuous mode
# Run: ip link set eth0 promisc on
# Run: ip link set eth1 promisc on"
			;;
		accesspoint)
			local channel=$(uci -q get network-modes.accesspoint.wifi_channel || echo "auto")
			local htmode=$(uci -q get network-modes.accesspoint.wifi_htmode || echo "VHT80")
			local txpower=$(uci -q get network-modes.accesspoint.wifi_txpower || echo "20")
			config="# Access Point Mode Configuration
# /etc/config/network

config interface 'lan'
    option proto 'dhcp'
    option device 'eth0'

# /etc/config/wireless

config wifi-device 'radio0'
    option type 'mac80211'
    option channel '$channel'
    option htmode '$htmode'
    option txpower '$txpower'
    option country 'FR'

config wifi-iface 'default_radio0'
    option device 'radio0'
    option network 'lan'
    option mode 'ap'
    option ssid 'OpenWrt-AP'
    option encryption 'sae-mixed'
    option key 'your_password'
    option ieee80211r '1'
    option ft_over_ds '1'
    option ieee80211k '1'
    option ieee80211v '1'
    option bss_transition '1'"
			;;
		relay)
			local wg_iface=$(uci -q get network-modes.relay.wireguard_interface || echo "wg0")
			config="# Relay Mode Configuration
# /etc/config/network

config interface 'lan'
    option proto 'static'
    option ipaddr '192.168.1.1'
    option netmask '255.255.255.0'
    option device 'br-lan'

config interface 'wwan'
    option proto 'dhcp'
    option device 'wlan0'

config interface '$wg_iface'
    option proto 'wireguard'
    option listen_port '51820'
    list addresses '10.0.0.1/24'

# /etc/config/firewall - MSS clamping
config rule
    option name 'MSS-Clamping'
    option src '*'
    option dest '*'
    option proto 'tcp'
    option extra '-m tcp --tcp-flags SYN,RST SYN -j TCPMSS --clamp-mss-to-pmtu'"
			;;
		router)
			local wan_proto=$(uci -q get network-modes.router.wan_protocol || echo "dhcp")
			config="# Router Mode Configuration
# /etc/config/network

config interface 'wan'
    option proto '$wan_proto'
    option device 'eth1'

config interface 'lan'
    option proto 'static'
    option device 'br-lan'
    option ipaddr '192.168.1.1'
    option netmask '255.255.255.0'

# /etc/config/firewall

config defaults
    option syn_flood '1'
    option input 'ACCEPT'
    option output 'ACCEPT'
    option forward 'REJECT'

config zone
    option name 'wan'
    option input 'REJECT'
    option output 'ACCEPT'
    option forward 'REJECT'
    option masq '1'
    option mtu_fix '1'
    list network 'wan'

config zone
    option name 'lan'
    option input 'ACCEPT'
    option output 'ACCEPT'
    option forward 'ACCEPT'
    list network 'lan'

config forwarding
    option src 'lan'
    option dest 'wan'"
			;;
		travel)
			local travel_ssid=$(uci -q get network-modes.travel.ssid || echo "HotelWiFi")
			local hotspot_ssid=$(uci -q get network-modes.travel.hotspot_ssid || echo "SecuBox-Travel")
			local lan_ip=$(uci -q get network-modes.travel.lan_subnet || echo "10.77.0.1")
			config="# Travel Router Mode
# /etc/config/network

config interface 'wan'
    option proto 'dhcp'
    option device 'wlan-sta'

config interface 'lan'
    option proto 'static'
    option ipaddr '$lan_ip'
    option netmask '255.255.255.0'
    option device 'br-lan'

# /etc/config/wireless

config wifi-iface 'travel_sta'
    option device 'radio1'
    option mode 'sta'
    option network 'wan'
    option ssid '$travel_ssid'
    option encryption 'sae-mixed'
    option key 'hotel-password'

config wifi-iface 'travel_ap'
    option device 'radio0'
    option mode 'ap'
    option network 'lan'
    option ssid '$hotspot_ssid'
    option encryption 'sae-mixed'
    option key 'TravelSafe123!'

# /etc/config/firewall
	config zone
    option name 'wan'
    option input 'REJECT'
    option output 'ACCEPT'
    option forward 'REJECT'
    option masq '1'"
			;;
		doublenat)
			local lan_ip=$(uci -q get network-modes.doublenat.lan_ip || echo "10.10.0.1")
			local lan_netmask=$(uci -q get network-modes.doublenat.lan_netmask || echo "255.255.255.0")
			local guest=$(uci -q get network-modes.doublenat.guest_network || echo "br-guest")
			config="# Double NAT mode
# /etc/config/network

config interface 'wan'
    option proto 'dhcp'
    option device 'eth1'

config interface 'lan'
    option proto 'static'
    option ipaddr '$lan_ip'
    option netmask '$lan_netmask'
    option device 'br-lan'

config interface '$guest'
    option proto 'static'
    option ipaddr '172.16.0.1'
    option netmask '255.255.255.0'

# /etc/config/firewall
config zone
    option name 'lan'
    option input 'ACCEPT'
    option output 'ACCEPT'
    option forward 'REJECT'
    list network 'lan'

config zone
    option name 'guest'
    option input 'REJECT'
    option output 'ACCEPT'
    option forward 'REJECT'
    list network '$guest'

config forwarding
    option src 'lan'
    option dest 'wan'"
			;;
		multiwan)
			local primary=$(uci -q get network-modes.multiwan.wan_primary || echo "eth1")
			local secondary=$(uci -q get network-modes.multiwan.wan_secondary || echo "wwan0")
			local host=$(uci -q get network-modes.multiwan.tracking_host || echo "8.8.8.8")
			config="# Multi-WAN (mwan3) snippet
# /etc/config/mwan3

config interface '$primary'
    option enabled '1'
    option reliability '1'
    option initial_state 'online'
    option track_method 'ping'
    list track_ip '$host'

config interface '$secondary'
    option enabled '1'
    option reliability '1'
    option initial_state 'online'
    option timeout '5'
    option track_method 'ping'
    list track_ip '$host'

config member 'member_primary'
    option interface '$primary'
    option metric '1'
    option weight '3'

config member 'member_secondary'
    option interface '$secondary'
    option metric '2'
    option weight '1'

config policy 'balanced'
    list use_member 'member_primary'
    list use_member 'member_secondary'

config policy 'failover'
    list use_member 'member_primary'
    list use_member 'member_secondary'
    option last_resort 'unreachable'"
			;;
		vpnrelay)
			local vpn_type=$(uci -q get network-modes.vpnrelay.vpn_type || echo "wireguard")
			local wg_iface=$(uci -q get network-modes.vpnrelay.wg_interface || echo "wg0")
			config="# VPN Relay example
# /etc/config/network

config interface '$wg_iface'
    option proto 'wireguard'
    option private_key '<private>'
    list addresses '10.8.0.2/32'

config wireguard_$wg_iface
    option public_key '<server_pub>'
    option endpoint_host 'vpn.example.com'
    option endpoint_port '51820'
    option persistent_keepalive '25'
    list allowed_ips '0.0.0.0/0'

# /etc/config/firewall
config zone
    option name 'vpn'
    option input 'ACCEPT'
    option output 'ACCEPT'
    option forward 'REJECT'
    option masq '1'
    list network '$wg_iface'

config forwarding
    option src 'lan'
    option dest 'vpn'

config rule
    option name 'Kill-Switch'
    option src 'lan'
    option dest 'wan'
    option proto 'all'
    option target 'REJECT'
    option enabled '1'

# Force DNS over VPN
uci set dhcp.@dnsmasq[0].server='10.8.0.1'
uci commit dhcp && /etc/init.d/dnsmasq restart"
			;;
	esac
	
	json_add_string "config" "$config"
	json_add_string "mode" "$mode"
	json_dump
}

# Get current mode details
get_current_mode() {
	json_init

	local current_mode=$(uci -q get network-modes.config.current_mode || echo "router")
	local last_change=$(uci -q get network-modes.config.last_change || echo "Never")
	local pending_mode=$(uci -q get network-modes.config.pending_mode || echo "")
	local rollback_timer=$(uci -q get network-modes.config.rollback_timer || echo "0")

	json_add_string "current_mode" "$current_mode"
	json_add_string "mode_name" "$(uci -q get network-modes.$current_mode.name || echo "$current_mode")"
	json_add_string "description" "$(uci -q get network-modes.$current_mode.description || echo "")"
	json_add_string "last_change" "$last_change"
	json_add_string "pending_mode" "$pending_mode"
	if [ -n "$pending_mode" ]; then
		json_add_string "pending_mode_name" "$(uci -q get network-modes.$pending_mode.name || echo "$pending_mode")"
	fi
	json_add_int "rollback_timer" "$rollback_timer"
	json_add_string "last_backup" "$(uci -q get network-modes.config.last_backup || echo '')"
	json_add_string "last_backup_time" "$(uci -q get network-modes.config.last_backup_time || echo '')"

	# Check if rollback is active
	if [ -f "/tmp/network-mode-rollback.pid" ]; then
		json_add_boolean "rollback_active" 1
		local remaining=$(cat /tmp/network-mode-rollback.remaining 2>/dev/null || echo "0")
		json_add_int "rollback_remaining" "$remaining"
	else
		json_add_boolean "rollback_active" 0
		json_add_int "rollback_remaining" 0
	fi

	json_dump
}

# Get available modes
get_available_modes() {
	json_init
	json_add_array "modes"

	local current_mode=$(uci -q get network-modes.config.current_mode || echo "router")

	add_mode() {
		local id="$1"; shift
		local name="$1"; shift
		local icon="$1"; shift
		local desc="$1"; shift
		json_add_object
		json_add_string "id" "$id"
		json_add_string "name" "$name"
		json_add_string "description" "$desc"
		json_add_string "icon" "$icon"
		json_add_boolean "current" "$([ "$current_mode" = "$id" ] && echo 1 || echo 0)"
		json_add_array "features"
		for feature in "$@"; do
			json_add_string "" "$feature"
		done
		json_close_array
		json_close_object
	}

	add_mode "router" "Router" "🌐" "Mode routeur complet avec NAT, DHCP et firewall" \
		"NAT activé" "Serveur DHCP" "Firewall (zones WAN/LAN)" "Proxy optionnel"

	add_mode "dmz" "Router + DMZ" "🛡️" "Mode routeur avec réseau DMZ isolé et firewall segmenté" \
		"Réseau DMZ séparé" "DHCP optionnel pour DMZ" "Isolation LAN/DMZ" "Forwarding WAN contrôlé"

	add_mode "doublenat" "Double NAT" "🔁" "Derrière box opérateur avec réseau isolé" \
		"WAN DHCP client" "Deuxième LAN privé" "Isolation invitée" "UPnP désactivé"

	add_mode "multiwan" "Multi-WAN" "⚡" "Agrégation et bascule multi-liens WAN" \
		"Double WAN" "Suivi de santé" "Équilibrage de charge" "Failover automatique"

	add_mode "accesspoint" "Access Point" "📶" "Point d'accès WiFi en mode bridge" \
		"Bridge WAN+LAN" "Pas de DHCP" "Pas de firewall" "Optimisations WiFi"

	add_mode "relay" "Repeater" "🔄" "Client WiFi + Répéteur AP" \
		"Client WiFi (sta0)" "AP répéteur (ap0)" "WireGuard optionnel" "Optimisations MTU/MSS"

	add_mode "vpnrelay" "VPN Relay" "🛡️" "Tunnels WireGuard/OpenVPN avec policy routing" \
		"Policy routing" "Kill-switch" "DNS sécurisé" "Split tunnel"

	add_mode "travel" "Travel Router" "✈️" "Hotspot personnel depuis WiFi/ethernet hôtel" \
		"Client WiFi + scan" "Clone MAC WAN" "Hotspot WPA3" "NAT + DHCP isolé"

	add_mode "bridge" "Bridge" "🔗" "Bridge Layer 2 pur, DHCP client" \
		"Bridge transparent L2" "Toutes interfaces bridgées" "DHCP client" "Pas de firewall"

	json_close_array
	json_dump
}

# Set mode (prepare for switch)
set_mode() {
	read input
	json_load "$input"
	json_get_var target_mode mode

	json_init

	# Validate mode
	case "$target_mode" in
		router|dmz|multiwan|doublenat|accesspoint|relay|vpnrelay|bridge|sniffer|travel)
			;;
		*)
			json_add_boolean "success" 0
			json_add_string "error" "Mode invalide: $target_mode"
			json_dump
			return
			;;
	esac

	local current_mode=$(uci -q get network-modes.config.current_mode || echo "router")

	if [ "$current_mode" = "$target_mode" ]; then
		json_add_boolean "success" 0
		json_add_string "error" "Déjà en mode $target_mode"
		json_dump
		return
	fi

	# Store pending mode
	uci set network-modes.config.pending_mode="$target_mode"
	uci set network-modes.config.pending_since="$(date '+%Y-%m-%d %H:%M:%S')"
	uci commit network-modes

	json_add_boolean "success" 1
	json_add_string "current_mode" "$current_mode"
	json_add_string "target_mode" "$target_mode"
	json_add_string "message" "Mode $target_mode préparé. Utilisez preview_changes puis apply_mode."

	json_dump
}

# Preview changes before applying
preview_changes() {
	json_init

	local current_mode=$(uci -q get network-modes.config.current_mode || echo "router")
	local pending_mode=$(uci -q get network-modes.config.pending_mode || echo "")

	if [ -z "$pending_mode" ]; then
		json_add_boolean "success" 0
		json_add_string "error" "Aucun changement de mode en attente"
		json_dump
		return
	fi

	json_add_boolean "success" 1
	json_add_string "current_mode" "$current_mode"
	json_add_string "target_mode" "$pending_mode"

	# Changes array
	json_add_array "changes"

	local dmz_ip_preview
	dmz_ip_preview=$(uci -q get network-modes.dmz.dmz_ip || echo "192.168.50.1")

	case "$pending_mode" in
		router)
			json_add_object
			json_add_string "file" "/etc/config/network"
			json_add_string "change" "WAN: proto dhcp, NAT enabled"
			json_close_object
			json_add_object
			json_add_string "file" "/etc/config/network"
			json_add_string "change" "LAN: static IP, DHCP server enabled"
			json_close_object
			json_add_object
			json_add_string "file" "/etc/config/firewall"
			json_add_string "change" "Zones: WAN, LAN, forwarding rules"
			json_close_object
			;;
		dmz)
			json_add_object
			json_add_string "file" "/etc/config/network"
			json_add_string "change" "WAN interface + LAN bridge reconfiguré"
			json_close_object
			json_add_object
			json_add_string "file" "/etc/config/network"
			json_add_string "change" "Nouveau segment DMZ (${dmz_ip_preview}/24)"
			json_close_object
			json_add_object
			json_add_string "file" "/etc/config/dhcp"
			json_add_string "change" "Serveur DHCP dédié pour DMZ"
			json_close_object
			json_add_object
			json_add_string "file" "/etc/config/firewall"
			json_add_string "change" "Zone DMZ isolée (forwarding uniquement vers WAN)"
			json_close_object
			;;
		accesspoint)
			json_add_object
			json_add_string "file" "/etc/config/network"
			json_add_string "change" "Bridge: br-lan (WAN+LAN)"
			json_close_object
			json_add_object
			json_add_string "file" "/etc/config/network"
			json_add_string "change" "DHCP: client mode"
			json_close_object
			json_add_object
			json_add_string "file" "/etc/config/firewall"
			json_add_string "change" "Firewall: disabled"
			json_close_object
			;;
		relay)
			json_add_object
			json_add_string "file" "/etc/config/wireless"
			json_add_string "change" "WiFi STA: client mode on wlan0"
			json_close_object
			json_add_object
			json_add_string "file" "/etc/config/wireless"
			json_add_string "change" "WiFi AP: repeater mode on wlan1"
			json_close_object
			json_add_object
			json_add_string "file" "/etc/config/network"
			json_add_string "change" "Relay: relayd between sta0 and ap0"
			json_close_object
			;;
		bridge)
			json_add_object
			json_add_string "file" "/etc/config/network"
			json_add_string "change" "Bridge: all interfaces to br-lan"
			json_close_object
			json_add_object
			json_add_string "file" "/etc/config/network"
			json_add_string "change" "DHCP: client only"
			json_close_object
			json_add_object
			json_add_string "file" "/etc/config/firewall"
			json_add_string "change" "Firewall: disabled"
			json_close_object
			;;
	esac

	json_close_array

	# Warnings
	json_add_array "warnings"
	json_add_string "" "La connexion réseau sera interrompue pendant la reconfiguration"
	json_add_string "" "Vous devrez peut-être reconnecter via la nouvelle IP"
	json_add_string "" "Un rollback automatique de 2 minutes sera activé"
	json_add_string "" "Vous devez confirmer le changement avant expiration"
	json_close_array

	json_dump
}

# Multi-WAN configuration
get_multiwan_config() {
	json_init

	json_add_string "mode" "multiwan"
	json_add_string "name" "$(uci -q get network-modes.multiwan.name || echo 'Multi-WAN Controller')"
	json_add_string "description" "$(uci -q get network-modes.multiwan.description || echo 'Dual-WAN bonding with health tracking')"

	json_add_object "policy"
	json_add_string "profile" "$(uci -q get network-modes.multiwan.policy || echo 'balanced')"
	json_add_boolean "load_balance" "$(uci -q get network-modes.multiwan.load_balance || echo 1)"
	json_add_string "tracking_host" "$(uci -q get network-modes.multiwan.tracking_host || echo '8.8.8.8')"
	json_add_int "tracking_interval" "$(uci -q get network-modes.multiwan.tracking_interval || echo 30)"
	json_add_int "failover_hold" "$(uci -q get network-modes.multiwan.failover_hold || echo 45)"
	json_close_object

	json_add_object "links"
	json_add_string "primary" "$(uci -q get network-modes.multiwan.wan_primary || echo 'eth1')"
	json_add_string "secondary" "$(uci -q get network-modes.multiwan.wan_secondary || echo 'wwan0')"
	json_add_boolean "mwan3_enabled" "$(uci -q get network-modes.multiwan.use_mwan3 || echo 0)"
	json_close_object

	json_add_array "wan_candidates"
	for iface in $(ls /sys/class/net 2>/dev/null); do
		[ "$iface" = "lo" ] && continue
		case "$iface" in
			br-*|ifb*|gre*|ip6*|mon*) continue ;;
		esac
		local operstate="$(cat /sys/class/net/$iface/operstate 2>/dev/null)"
		local mac="$(cat /sys/class/net/$iface/address 2>/dev/null)"
		json_add_object
		json_add_string "name" "$iface"
		json_add_boolean "up" "$([ "$operstate" = "up" ] && echo 1 || echo 0)"
		json_add_string "mac" "$mac"
		json_close_object
	done
	json_close_array

	json_dump
}

# VPN relay configuration
get_vpnrelay_config() {
	json_init

	json_add_string "mode" "vpnrelay"
	json_add_string "name" "$(uci -q get network-modes.vpnrelay.name || echo 'VPN Relay')"
	json_add_string "description" "$(uci -q get network-modes.vpnrelay.description || echo 'Route LAN traffic through VPN tunnels with policy routing')"

	json_add_object "vpn"
	json_add_string "type" "$(uci -q get network-modes.vpnrelay.vpn_type || echo 'wireguard')"
	json_add_string "provider" "$(uci -q get network-modes.vpnrelay.vpn_provider || echo 'Mullvad')"
	json_add_string "wg_interface" "$(uci -q get network-modes.vpnrelay.wg_interface || echo 'wg0')"
	json_add_string "openvpn_profile" "$(uci -q get network-modes.vpnrelay.openvpn_profile || echo '')"
	json_add_string "upstream_interface" "$(uci -q get network-modes.vpnrelay.upstream_interface || echo 'wan')"
	json_close_object

	json_add_object "policy"
	json_add_boolean "policy_routing" "$(uci -q get network-modes.vpnrelay.policy_routing || echo 1)"
	json_add_boolean "dns_override" "$(uci -q get network-modes.vpnrelay.dns_override || echo 1)"
	json_add_boolean "kill_switch" "$(uci -q get network-modes.vpnrelay.kill_switch || echo 1)"
	json_add_boolean "lan_bypass" "$(uci -q get network-modes.vpnrelay.lan_bypass || echo 0)"
	json_close_object

	json_add_array "wireguard_interfaces"
	if command -v wg >/dev/null 2>&1; then
		for iface in $(wg show interfaces 2>/dev/null); do
			json_add_string "" "$iface"
		done
	fi
	json_close_array

	json_add_array "openvpn_profiles"
	for profile in /etc/openvpn/*.ovpn /etc/openvpn/*.conf; do
		[ -f "$profile" ] || continue
		json_add_string "" "$(basename "$profile")"
	done
	json_close_array

	json_add_array "available_interfaces"
	for iface in $(ls /sys/class/net 2>/dev/null); do
		[ "$iface" = "lo" ] && continue
		json_add_string "" "$iface"
	done
	json_close_array

	json_dump
}

# Double NAT configuration
get_doublenat_config() {
	json_init

	local wan_iface=$(uci -q get network-modes.doublenat.wan_interface || echo "eth1")
	local wan_proto=$(uci -q get network-modes.doublenat.wan_protocol || echo "dhcp")
	local lan_iface=$(uci -q get network-modes.doublenat.lan_interface || echo "br-lan")
	local lan_ip=$(uci -q get network-modes.doublenat.lan_ip || echo "10.10.0.1")
	local lan_netmask=$(uci -q get network-modes.doublenat.lan_netmask || echo "255.255.255.0")

	json_add_string "mode" "doublenat"
	json_add_string "name" "$(uci -q get network-modes.doublenat.name || echo 'Double NAT')"
	json_add_string "description" "$(uci -q get network-modes.doublenat.description || echo 'Operate behind an ISP router with isolated LAN and guest network')"

	json_add_object "wan"
	json_add_string "interface" "$wan_iface"
	json_add_string "protocol" "$wan_proto"
	json_close_object

	json_add_object "lan"
	json_add_string "interface" "$lan_iface"
	json_add_string "ipaddr" "$lan_ip"
	json_add_string "netmask" "$lan_netmask"
	json_close_object

	json_add_boolean "upnp_enabled" "$(uci -q get network-modes.doublenat.upnp_enabled || echo 0)"
	json_add_string "guest_network" "$(uci -q get network-modes.doublenat.guest_network || echo 'br-guest')"
	json_add_boolean "isolate_guest" "$(uci -q get network-modes.doublenat.isolate_guest || echo 1)"
	json_add_string "dmz_host" "$(uci -q get network-modes.doublenat.dmz_host || echo '')"

	json_dump
}

# Confirm mode change (cancel rollback timer)
confirm_mode() {
	json_init

	local current_mode=$(uci -q get network-modes.config.current_mode || echo "router")

	# Stop rollback timer
	if [ -f "/tmp/network-mode-rollback.pid" ]; then
		local pid=$(cat /tmp/network-mode-rollback.pid)
		kill $pid 2>/dev/null
		rm -f /tmp/network-mode-rollback.pid
		rm -f /tmp/network-mode-rollback.remaining

		# Clear pending mode
		uci delete network-modes.config.pending_mode 2>/dev/null
		uci delete network-modes.config.pending_since 2>/dev/null
		uci set network-modes.config.rollback_timer="0"
		uci commit network-modes

		json_add_boolean "success" 1
		json_add_string "message" "Mode $current_mode confirmé, rollback annulé"
		json_add_string "mode" "$current_mode"
	else
		json_add_boolean "success" 0
		json_add_string "error" "Aucun rollback actif"
	fi

	json_dump
}

# Rollback to previous mode
rollback() {
	json_init

	# Stop any active rollback timer
	if [ -f "/tmp/network-mode-rollback.pid" ]; then
		local pid=$(cat /tmp/network-mode-rollback.pid)
		kill $pid 2>/dev/null
		rm -f /tmp/network-mode-rollback.pid
		rm -f /tmp/network-mode-rollback.remaining
	fi

	# Get backup file
	local latest_backup=$(ls -t "$BACKUP_DIR"/backup_*.tar.gz 2>/dev/null | head -1)

	if [ -z "$latest_backup" ]; then
		json_add_boolean "success" 0
		json_add_string "error" "Aucune sauvegarde disponible"
		json_dump
		return
	fi

	# Restore backup
	cd /
	tar -xzf "$latest_backup" 2>/dev/null

	# Reload network services
	/etc/init.d/network reload 2>&1
	/etc/init.d/firewall reload 2>&1
	/etc/init.d/dnsmasq reload 2>&1

	# Update UCI
	local previous_mode=$(uci -q get network-modes.config.current_mode || echo "router")
	uci delete network-modes.config.pending_mode 2>/dev/null
	uci set network-modes.config.last_change="$(date '+%Y-%m-%d %H:%M:%S') (rollback)"
	uci commit network-modes

	json_add_boolean "success" 1
	json_add_string "message" "Configuration restaurée depuis la sauvegarde"
	json_add_string "mode" "$previous_mode"
	json_add_string "backup_file" "$latest_backup"

	json_dump
}

# Main dispatcher
case "$1" in
	list)
		echo '{"status":{},"modes":{},"get_current_mode":{},"get_available_modes":{},"set_mode":{"mode":"str"},"preview_changes":{},"apply_mode":{},"confirm_mode":{},"rollback":{},"sniffer_config":{},"ap_config":{},"relay_config":{},"router_config":{},"dmz_config":{},"travel_config":{},"doublenat_config":{},"multiwan_config":{},"vpnrelay_config":{},"travel_scan_networks":{},"update_settings":{"mode":"str"},"generate_wireguard_keys":{},"apply_wireguard_config":{},"apply_mtu_clamping":{},"enable_tcp_bbr":{},"add_vhost":{"domain":"str","backend":"str","port":"int","ssl":"bool"},"generate_config":{"mode":"str"},"validate_pcap_filter":{"filter":"str"},"cleanup_old_pcaps":{}}'
		;;
	call)
		case "$2" in
			status)
				get_status
				;;
			modes)
				get_modes
				;;
			get_current_mode)
				get_current_mode
				;;
			get_available_modes)
				get_available_modes
				;;
			set_mode)
				set_mode
				;;
			preview_changes)
				preview_changes
				;;
			apply_mode)
				apply_mode
				;;
			confirm_mode)
				confirm_mode
				;;
			rollback)
				rollback
				;;
			sniffer_config)
				get_sniffer_config
				;;
			ap_config)
				get_ap_config
				;;
			relay_config)
				get_relay_config
				;;
			router_config)
				get_router_config
				;;
			dmz_config)
				get_dmz_config
				;;
			travel_config)
				get_travel_config
				;;
			doublenat_config)
				get_doublenat_config
				;;
			multiwan_config)
				get_multiwan_config
				;;
			vpnrelay_config)
				get_vpnrelay_config
				;;
			travel_scan_networks)
				travel_scan_networks
				;;
			update_settings)
				update_settings
				;;
			generate_wireguard_keys)
				generate_wireguard_keys
				;;
			apply_wireguard_config)
				if apply_wireguard_config; then
					json_init; json_add_boolean "success" 1; json_dump
				else
					json_init; json_add_boolean "success" 0; json_add_string "error" "WireGuard deployment failed"; json_dump
				fi
				;;
			apply_mtu_clamping)
				if apply_mtu_clamping; then
					json_init; json_add_boolean "success" 1; json_dump
				else
					json_init; json_add_boolean "success" 0; json_add_string "error" "Unable to update firewall rule"; json_dump
				fi
				;;
			enable_tcp_bbr)
				if enable_tcp_bbr; then
					json_init; json_add_boolean "success" 1; json_dump
				else
					json_init; json_add_boolean "success" 0; json_add_string "error" "TCP BBR not applied"; json_dump
				fi
				;;
			add_vhost)
				add_vhost
				;;
			generate_config)
				generate_config
				;;
			validate_pcap_filter)
				validate_pcap_filter
				;;
			cleanup_old_pcaps)
				cleanup_old_pcaps
				;;
			*)
				echo '{"error": "Unknown method"}'
				;;
		esac
		;;
esac
		dmz)
			local wan_if=$(uci -q get network-modes.dmz.wan_interface || echo "eth1")
			local wan_proto=$(uci -q get network-modes.dmz.wan_protocol || echo "dhcp")
			local lan_iface=$(uci -q get network-modes.dmz.lan_interface || echo "br-lan")
			local lan_ip=$(uci -q get network-modes.dmz.lan_ip || echo "192.168.1.1")
			local lan_mask=$(uci -q get network-modes.dmz.lan_netmask || echo "255.255.255.0")
			local dmz_iface=$(uci -q get network-modes.dmz.dmz_interface || echo "eth2")
			local dmz_ip=$(uci -q get network-modes.dmz.dmz_ip || echo "192.168.50.1")
			local dmz_mask=$(uci -q get network-modes.dmz.dmz_netmask || echo "255.255.255.0")
			config="# DMZ Mode Configuration
# /etc/config/network

config interface 'wan'
    option device '$wan_if'
    option proto '$wan_proto'

config interface 'lan'
    option device '$lan_iface'
    option proto 'static'
    option ipaddr '$lan_ip'
    option netmask '$lan_mask'

config interface 'dmz'
    option device '$dmz_iface'
    option proto 'static'
    option ipaddr '$dmz_ip'
    option netmask '$dmz_mask'

# /etc/config/firewall
config zone
    option name 'lan'
    option input 'ACCEPT'
    option output 'ACCEPT'
    option forward 'ACCEPT'
    list network 'lan'

config zone
    option name 'dmz'
    option input 'REJECT'
    option output 'ACCEPT'
    option forward 'REJECT'
    list network 'dmz'

config zone
    option name 'wan'
    option input 'REJECT'
    option output 'ACCEPT'
    option forward 'REJECT'
    option masq '1'
    option mtu_fix '1'
    list network 'wan'

config forwarding
    option src 'lan'
    option dest 'wan'

config forwarding
    option src 'dmz'
    option dest 'wan'"
			;;
