#!/bin/sh

#
# SecuBox Core RPCD Interface
# Provides ubus API for SecuBox operations
#

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

case "$1" in
	list)
		json_init

		# Core status and information
		json_add_object "getStatus"
		json_close_object

		json_add_object "getVersion"
		json_close_object

		json_add_object "reload"
		json_close_object

		# Module management
		json_add_object "getModules"
		json_close_object

		json_add_object "getModuleInfo"
			json_add_string "module" "string"
		json_close_object

		json_add_object "installModule"
			json_add_string "module" "string"
			json_add_boolean "dryrun" "boolean"
		json_close_object

		json_add_object "removeModule"
			json_add_string "module" "string"
		json_close_object

		json_add_object "updateModule"
			json_add_string "module" "string"
		json_close_object

		# Profile management
		json_add_object "listProfiles"
		json_close_object

		json_add_object "getProfile"
			json_add_string "profile" "string"
		json_close_object

		json_add_object "applyProfile"
			json_add_string "profile" "string"
			json_add_boolean "dryrun" "boolean"
		json_close_object

		json_add_object "rollbackProfile"
		json_close_object

		json_add_object "validateProfile"
			json_add_string "profile" "string"
		json_close_object

		# Diagnostics
		json_add_object "runDiagnostics"
			json_add_string "target" "string"
		json_close_object

		json_add_object "getHealth"
		json_close_object

		json_add_object "getLogs"
			json_add_string "service" "string"
			json_add_int "lines" "integer"
		json_close_object

		# Snapshot/Recovery
		json_add_object "createSnapshot"
			json_add_string "name" "string"
		json_close_object

		json_add_object "listSnapshots"
		json_close_object

		json_add_object "restoreSnapshot"
			json_add_string "snapshot" "string"
		json_close_object

		# AppStore (NEW - uses catalog files)
		json_add_object "get_appstore_apps"
		json_close_object

		json_add_object "list_apps"
		json_close_object

		json_add_object "get_appstore_app"
			json_add_string "app_id" "string"
		json_close_object

		json_add_object "install_appstore_app"
			json_add_string "app_id" "string"
		json_close_object

		json_add_object "remove_appstore_app"
			json_add_string "app_id" "string"
		json_close_object

		# Catalog source management
		json_add_object "get_catalog_sources"
		json_close_object

		json_add_object "set_catalog_source"
			json_add_string "source" "string"
		json_close_object

		json_add_object "sync_catalog"
			json_add_string "source" "string"
		json_close_object

		# Version and update management
		json_add_object "check_updates"
		json_close_object

		json_add_object "get_app_versions"
			json_add_string "app_id" "string"
		json_close_object

		json_add_object "get_changelog"
			json_add_string "app_id" "string"
			json_add_string "from_version" "string"
			json_add_string "to_version" "string"
		json_close_object

		# Widget data
		json_add_object "get_widget_data"
			json_add_string "app_id" "string"
		json_close_object

			# Dashboard and monitoring
		json_add_object "get_dashboard_data"
		json_close_object

		json_add_object "get_system_health"
		json_close_object

		json_add_object "get_public_ips"
		json_close_object

		json_add_object "get_alerts"
		json_close_object

		# State management
		json_add_object "get_component_state"
			json_add_string "component_id" "string"
		json_close_object

		json_add_object "set_component_state"
			json_add_string "component_id" "string"
			json_add_string "new_state" "string"
			json_add_string "reason" "string"
		json_close_object

		json_add_object "get_state_history"
			json_add_string "component_id" "string"
			json_add_int "limit" "integer"
		json_close_object

		json_add_object "list_components"
			json_add_string "state_filter" "string"
			json_add_string "type_filter" "string"
		json_close_object

		json_add_object "freeze_component"
			json_add_string "component_id" "string"
			json_add_string "reason" "string"
		json_close_object

		json_add_object "clear_error_state"
			json_add_string "component_id" "string"
		json_close_object

		# Component registry management
		json_add_object "get_component"
			json_add_string "component_id" "string"
		json_close_object

		json_add_object "list_all_components"
			json_add_string "type" "string"
			json_add_string "profile" "string"
		json_close_object

		json_add_object "get_component_tree"
			json_add_string "component_id" "string"
		json_close_object

		json_add_object "update_component_settings"
			json_add_string "component_id" "string"
			json_add_object "settings"
			json_close_object
		json_close_object

		json_add_object "sync_component_registry"
		json_close_object

		# WAN Access management
		json_add_object "get_wan_access"
		json_close_object

		json_add_object "set_wan_access"
			json_add_boolean "enabled" "boolean"
			json_add_boolean "https_enabled" "boolean"
			json_add_int "https_port" "integer"
			json_add_boolean "http_enabled" "boolean"
			json_add_int "http_port" "integer"
			json_add_boolean "ssh_enabled" "boolean"
			json_add_int "ssh_port" "integer"
		json_close_object

		json_add_object "apply_wan_access"
		json_close_object

		# Services discovery
		json_add_object "get_services"
		json_close_object

	json_dump
		;;

	call)
		case "$2" in
			getStatus)
				/usr/sbin/secubox-core status
				;;

			getVersion)
				json_init
				json_add_string "version" "0.8.0"
				json_add_string "core" "secubox-core"
				json_add_string "build_date" "$(date -u +%Y-%m-%d)"
				json_dump
				;;

			reload)
				/usr/sbin/secubox-core reload
				json_init
				json_add_boolean "success" 1
				json_dump
				;;

			getModules)
				/usr/sbin/secubox-appstore list --json
				;;

			getModuleInfo)
				read -r input
				module=$(echo "$input" | jsonfilter -e '@.module')
				/usr/sbin/secubox-appstore info "$module"
				;;

			installModule)
				read -r input
				module=$(echo "$input" | jsonfilter -e '@.module')
				dryrun=$(echo "$input" | jsonfilter -e '@.dryrun')
				/usr/sbin/secubox-appstore install "$module" ${dryrun:+--dryrun}
				;;

			removeModule)
				read -r input
				module=$(echo "$input" | jsonfilter -e '@.module')
				/usr/sbin/secubox-appstore remove "$module"
				;;

			updateModule)
				read -r input
				module=$(echo "$input" | jsonfilter -e '@.module')
				/usr/sbin/secubox-appstore update "$module"
				;;

			listProfiles)
				/usr/sbin/secubox-profile list --json
				;;

			getProfile)
				read -r input
				profile=$(echo "$input" | jsonfilter -e '@.profile')
				/usr/sbin/secubox-profile show "$profile"
				;;

			applyProfile)
				read -r input
				profile=$(echo "$input" | jsonfilter -e '@.profile')
				dryrun=$(echo "$input" | jsonfilter -e '@.dryrun')
				result=$(/usr/sbin/secubox-profile apply "$profile" ${dryrun:+--dryrun} 2>&1)
				if [ $? -eq 0 ]; then
					echo '{"success":true,"message":"Profile applied successfully"}'
				else
					echo "{\"success\":false,\"message\":\"Failed to apply profile\",\"error\":\"$result\"}"
				fi
				;;

			rollbackProfile)
				# Rollback to last snapshot created before profile application
				if [ -f /usr/sbin/secubox-recovery ]; then
					result=$(/usr/sbin/secubox-recovery restore last 2>&1)
					if [ $? -eq 0 ]; then
						echo '{"success":true,"message":"Rolled back to last snapshot"}'
					else
						echo "{\"success\":false,\"message\":\"Rollback failed\",\"error\":\"$result\"}"
					fi
				else
					echo '{"success":false,"message":"Recovery system not available"}'
				fi
				;;

			validateProfile)
				read -r input
				profile=$(echo "$input" | jsonfilter -e '@.profile')
				/usr/sbin/secubox-profile validate "$profile"
				;;

			runDiagnostics)
				read -r input
				target=$(echo "$input" | jsonfilter -e '@.target')
				/usr/sbin/secubox-diagnostics run "${target:-all}"
				;;

			getHealth)
				/usr/sbin/secubox-core health
				;;

			get_dashboard_data)
				# Return dashboard summary data
				json_init

				# Get module stats
				modules_output=$(/usr/sbin/secubox-appstore list --json 2>/dev/null || echo '{"modules":[]}')
				total_modules=$(echo "$modules_output" | jsonfilter -e '@.modules[*]' | wc -l)
				running_modules=$(echo "$modules_output" | jsonfilter -e '@.modules[@.state="running"]' | wc -l 2>/dev/null || echo 0)

				# Get system info
				uptime_seconds=$(cat /proc/uptime | cut -d' ' -f1 | cut -d'.' -f1)
				load_avg=$(cat /proc/loadavg | cut -d' ' -f1-3)

				# Build response
				json_add_object "status"
					json_add_string "version" "0.8.0"
					json_add_int "uptime" "$uptime_seconds"
					json_add_string "load" "$load_avg"
				json_close_object

				json_add_object "counts"
					json_add_int "total" "$total_modules"
					json_add_int "running" "$running_modules"
				json_close_object

				json_dump
				;;

			get_system_health)
				# Return system health metrics
				json_init

				uptime_seconds=$(cut -d' ' -f1 /proc/uptime | cut -d'.' -f1)

				# CPU usage (simple average from /proc/loadavg)
				load1=$(awk '{print $1}' /proc/loadavg)
				cpu_count=$(grep -c ^processor /proc/cpuinfo)
				if [ "$cpu_count" -le 0 ]; then
					cpu_count=1
				fi
				cpu_percent=$(awk -v load="$load1" -v cores="$cpu_count" 'BEGIN {printf "%.0f", (load / cores) * 100}')

				# Memory
				mem_total=$(grep MemTotal /proc/meminfo | awk '{print $2}')
				mem_free=$(grep MemAvailable /proc/meminfo | awk '{print $2}')
				mem_free=${mem_free:-0}
				if [ "$mem_total" -le 0 ]; then
					mem_total=1
				fi
				mem_used=$((mem_total - mem_free))
				mem_percent=$(awk -v used="$mem_used" -v total="$mem_total" 'BEGIN {printf "%.0f", (used / total) * 100}')

				# Disk
				disk_info=$(df / | tail -1)
				disk_total=$(echo "$disk_info" | awk '{print $2}')
				disk_used=$(echo "$disk_info" | awk '{print $3}')
				disk_used=${disk_used:-0}
				if [ -z "$disk_total" ] || [ "$disk_total" -le 0 ]; then
					disk_total=0
					disk_used=0
				fi
				disk_free=$((disk_total - disk_used))
				disk_percent=$(echo "$disk_info" | awk '{print $5}' | tr -d '%')
				[ -n "$disk_percent" ] || disk_percent=0

				# Calculate overall score (100 - average of usage percentages)
				overall_score=$(awk -v c="$cpu_percent" -v m="$mem_percent" -v d="$disk_percent" 'BEGIN {printf "%.0f", 100 - ((c + m + d) / 3)}')

				json_add_int "uptime" "$uptime_seconds"

				if [ "$overall_score" -gt 70 ]; then
					overall_status="healthy"
				else
					overall_status="warning"
				fi

				json_add_object "overall"
					json_add_int "score" "$overall_score"
					json_add_string "status" "$overall_status"
				json_close_object

				json_add_object "cpu"
					json_add_int "usage_percent" "$cpu_percent"
					json_add_string "load" "$(cut -d' ' -f1-3 /proc/loadavg)"
					json_add_int "count" "$cpu_count"
				json_close_object

				json_add_object "memory"
					json_add_int "total_kb" "$mem_total"
					json_add_int "used_kb" "$mem_used"
					json_add_int "free_kb" "$mem_free"
					json_add_int "usage_percent" "$mem_percent"
				json_close_object

				json_add_object "disk"
					json_add_int "total_kb" "$disk_total"
					json_add_int "used_kb" "$disk_used"
					json_add_int "free_kb" "$disk_free"
					json_add_int "usage_percent" "$disk_percent"
				json_close_object

				json_dump
				;;

			get_public_ips)
				# Return public IPv4 and IPv6 addresses
				json_init

				# Get IPv4 (try multiple services with short timeout)
				ipv4=""
				for service in "https://api.ipify.org" "https://ipv4.icanhazip.com" "https://v4.ident.me"; do
					ipv4=$(curl -4 -s --connect-timeout 3 --max-time 5 "$service" 2>/dev/null | tr -d '\n')
					[ -n "$ipv4" ] && break
				done

				# Get IPv6 (try multiple services with short timeout)
				ipv6=""
				for service in "https://api64.ipify.org" "https://ipv6.icanhazip.com" "https://v6.ident.me"; do
					ipv6=$(curl -6 -s --connect-timeout 3 --max-time 5 "$service" 2>/dev/null | tr -d '\n')
					[ -n "$ipv6" ] && break
				done

				# Fallback: get from interface if external check fails
				if [ -z "$ipv4" ]; then
					ipv4=$(ip -4 addr show scope global 2>/dev/null | grep -oP '(?<=inet\s)\d+(\.\d+){3}' | head -1)
				fi
				if [ -z "$ipv6" ]; then
					ipv6=$(ip -6 addr show scope global 2>/dev/null | grep -oP '(?<=inet6\s)[0-9a-f:]+' | head -1)
				fi

				json_add_string "ipv4" "${ipv4:-N/A}"
				json_add_string "ipv6" "${ipv6:-N/A}"
				json_add_boolean "ipv4_available" "$([ -n "$ipv4" ] && [ "$ipv4" != "N/A" ] && echo 1 || echo 0)"
				json_add_boolean "ipv6_available" "$([ -n "$ipv6" ] && [ "$ipv6" != "N/A" ] && echo 1 || echo 0)"

				json_dump
				;;

			get_alerts)
				# Return system alerts
				json_init
				json_add_array "alerts"

				# Check for common issues
				# 1. High memory usage
				mem_total=$(grep MemTotal /proc/meminfo | awk '{print $2}')
				mem_free=$(grep MemAvailable /proc/meminfo | awk '{print $2}')
				mem_percent=$(awk "BEGIN {printf \"%.0f\", (($mem_total - $mem_free) / $mem_total) * 100}")
				if [ "$mem_percent" -gt 90 ]; then
					json_add_object ""
						json_add_string "id" "high_memory"
						json_add_string "level" "warning"
						json_add_string "title" "High Memory Usage"
						json_add_string "message" "Memory usage is at ${mem_percent}%"
						json_add_int "timestamp" "$(date +%s)"
					json_close_object
				fi

				# 2. High disk usage
				disk_percent=$(df / | tail -1 | awk '{print $5}' | tr -d '%')
				if [ "$disk_percent" -gt 85 ]; then
					json_add_object ""
						json_add_string "id" "high_disk"
						json_add_string "level" "warning"
						json_add_string "title" "High Disk Usage"
						json_add_string "message" "Disk usage is at ${disk_percent}%"
						json_add_int "timestamp" "$(date +%s)"
					json_close_object
				fi

				json_close_array
				json_dump
				;;



			getLogs)
				read -r input
				service=$(echo "$input" | jsonfilter -e '@.service')
				lines=$(echo "$input" | jsonfilter -e '@.lines')

				json_init
				json_add_array "logs"
				if [ -n "$service" ]; then
					logread -e "$service" | tail -n "${lines:-100}" | while read -r line; do
						json_add_string "" "$line"
					done
				else
					logread | tail -n "${lines:-100}" | while read -r line; do
						json_add_string "" "$line"
					done
				fi
				json_close_array
				json_dump
				;;

			createSnapshot)
				read -r input
				name=$(echo "$input" | jsonfilter -e '@.name')
				/usr/sbin/secubox-recovery snapshot "${name:-auto-$(date +%Y%m%d-%H%M%S)}"
				;;

			listSnapshots)
				/usr/sbin/secubox-recovery list --json
				;;

			restoreSnapshot)
				read -r input
				snapshot=$(echo "$input" | jsonfilter -e '@.snapshot')
				/usr/sbin/secubox-recovery rollback "$snapshot"
				;;

			get_appstore_apps)
				# Return apps from catalog with installation status
				# Use secubox-appstore which properly detects installed packages
				CATALOG_FILE="/usr/share/secubox/catalog.json"

				if [ -f "$CATALOG_FILE" ]; then
					# Get modules list with installation status from secubox-appstore
					MODULES_JSON=$(/usr/sbin/secubox-appstore list --json 2>/dev/null)

					if [ -n "$MODULES_JSON" ]; then
						# Merge installation status from modules into catalog apps
						jq --argjson modules "$MODULES_JSON" '
							{
								apps: [.plugins[] | . as $app |
									($modules.modules // [] | map(select(.id == $app.id or .name == $app.id)) | first) as $mod |
									$app + {
										installed: (if $mod then ($mod.installed // false) else false end),
										enabled: (if $mod then ($mod.enabled // false) else false end),
										status: (if $mod then ($mod.status // "unknown") else "not_installed" end)
									}
								],
								categories: .categories
							}
						' "$CATALOG_FILE"
					else
						# Fallback: just return catalog without status
						jq '{apps: .plugins, categories: .categories}' "$CATALOG_FILE"
					fi
				else
					echo '{"apps":[],"categories":{}}'
				fi
				;;

			list_apps)
				# Returns apps from catalog and adds apps from manifests with wizards
				CATALOG_FILE="/usr/share/secubox/catalog.json"
				PLUGINS_DIR="/usr/share/secubox/plugins"

				if [ -f "$CATALOG_FILE" ]; then
					# Get base apps from catalog
					APPS_JSON=$(jq '.plugins' "$CATALOG_FILE")
				else
					APPS_JSON='[]'
				fi

				# Scan plugin manifests and add apps with wizards
				for plugin_dir in "$PLUGINS_DIR"/*; do
					[ -d "$plugin_dir" ] || continue
					manifest="$plugin_dir/manifest.json"
					[ -f "$manifest" ] || continue

					# Get app ID from manifest
					app_id=$(jq -r '.id // empty' "$manifest" 2>/dev/null)
					[ -n "$app_id" ] || continue

					# Check if manifest has wizard configuration
					has_wizard=$(jq -e '.wizard.fields | length > 0' "$manifest" >/dev/null 2>&1 && echo "true" || echo "false")

					if [ "$has_wizard" = "true" ]; then
						# Check if app already exists in catalog
						app_exists=$(echo "$APPS_JSON" | jq --arg id "$app_id" 'map(select(.id == $id)) | length')

						if [ "$app_exists" -gt 0 ]; then
							# Update existing catalog app with has_wizard flag
							APPS_JSON=$(echo "$APPS_JSON" | jq --arg id "$app_id" \
								'map(if .id == $id then . + {has_wizard: true} else . end)')
						else
							# Add new app from manifest
							app_data=$(jq '{
								id: .id,
								name: .name,
								description: .description,
								version: .version,
								icon: "📦",
								has_wizard: true,
								state: "available"
							}' "$manifest")
							APPS_JSON=$(echo "$APPS_JSON" | jq --argjson app "$app_data" '. + [$app]')
						fi
					fi
				done

				# Return modified apps list
				if [ -f "$CATALOG_FILE" ]; then
					jq -n --argjson apps "$APPS_JSON" --argjson cats "$(jq '.categories // {}' "$CATALOG_FILE")" \
						'{apps: $apps, categories: $cats}'
				else
					jq -n --argjson apps "$APPS_JSON" '{apps: $apps, categories: {}}'
				fi
				;;

			get_appstore_app)
				# Get single app details from catalog
				read -r input
				app_id=$(echo "$input" | jsonfilter -e '@.app_id')

				CATALOG_DIR="/usr/share/secubox/plugins/catalog"
				CATALOG_FILE="$CATALOG_DIR/${app_id}.json"

				if [ -f "$CATALOG_FILE" ]; then
					# Add installed status
					json_init
					cat "$CATALOG_FILE" | jsonfilter -e '@'

					# Check if installed
					pkg=$(jsonfilter -i "$CATALOG_FILE" -e '@.packages.required[0]')
					if [ -n "$pkg" ] && opkg list-installed | grep -q "^$pkg "; then
						echo ',"installed":true'
					else
						echo ',"installed":false'
					fi
				else
					json_init
					json_add_boolean "error" true
					json_add_string "message" "App not found: $app_id"
					json_dump
				fi
				;;

			install_appstore_app)
				# Install app using secubox-appstore CLI
				read -r input
				app_id=$(echo "$input" | jsonfilter -e '@.app_id')

				# Use secubox-appstore for installation
				if /usr/sbin/secubox-appstore install "$app_id" >/dev/null 2>&1; then
					json_init
					json_add_boolean "success" 1
					json_add_string "message" "App installed successfully"
					json_dump
				else
					json_init
					json_add_boolean "success" 0
					json_add_string "error" "Installation failed"
					json_add_string "details" "Check system logs for more information"
					json_dump
				fi
				;;

			remove_appstore_app)
				# Remove app using secubox-appstore CLI
				read -r input
				app_id=$(echo "$input" | jsonfilter -e '@.app_id')

				# Use secubox-appstore for removal
				if /usr/sbin/secubox-appstore remove "$app_id" >/dev/null 2>&1; then
					json_init
					json_add_boolean "success" 1
					json_add_string "message" "App removed successfully"
					json_dump
				else
					json_init
					json_add_boolean "success" 0
					json_add_string "error" "Removal failed"
					json_add_string "details" "Check system logs for more information"
					json_dump
				fi
				;;

			get_catalog_sources)
				# Return configured catalog sources from UCI (OPTIMIZED)
				CONFIG_NAME="secubox-appstore"
				METADATA_FILE="/var/lib/secubox/catalog-metadata.json"

					_add_default_source() {
						local name="$1"
						local type="$2"
						local url="$3"
						local path="$4"
						local priority="$5"

						json_add_object ""
							json_add_string "name" "$name"
							json_add_boolean "enabled" 1
							json_add_string "type" "$type"
							[ -n "$url" ] && json_add_string "url" "$url"
							[ -n "$path" ] && json_add_string "path" "$path"
							json_add_int "priority" "$priority"
							[ "$name" = "embedded" ] && json_add_boolean "active" 1 || json_add_boolean "active" 0
							json_add_string "status" "default"
							json_add_string "last_success" ""
						json_close_object
					}

					# Fast check: if UCI config doesn't exist, return sensible defaults
					if [ ! -f "/etc/config/$CONFIG_NAME" ]; then
						json_init
						json_add_array "sources"
						_add_default_source "github" "remote" "https://raw.githubusercontent.com/CyberMind-FR/secubox-openwrt/refs/heads/master/package/secubox/secubox-core/root/usr/share/secubox/catalog.json" "" 1
						_add_default_source "embedded" "embedded" "" "/usr/share/secubox/catalog.json" 999
						json_close_array
						json_add_boolean "defaults" true
						json_add_string "message" "Catalog config missing, using built-in defaults"
						json_dump
						exit 0
					fi

				json_init
				json_add_array "sources"

				# Parse UCI config sources
				. /lib/functions.sh

				# OPTIMIZATION: Add timeout guard for config_load, but still load
				if ! timeout 5 sh -c ". /lib/functions.sh; config_load $CONFIG_NAME >/dev/null 2>&1" 2>/dev/null; then
					# Config load failed or timed out, return defaults
					_add_default_source "github" "remote" "https://raw.githubusercontent.com/CyberMind-FR/secubox-openwrt/refs/heads/master/package/secubox/secubox-core/root/usr/share/secubox/catalog.json" "" 1
					_add_default_source "embedded" "embedded" "" "/usr/share/secubox/catalog.json" 999
					json_close_array
					json_add_boolean "defaults" true
					json_add_string "message" "Catalog config unreadable, using defaults"
					json_dump
					exit 0
				fi

				# Load config in current shell for config_foreach usage
				config_load "$CONFIG_NAME"

				# Get active source once (optimization)
				local active_source=""
				if [ -f "$METADATA_FILE" ]; then
					active_source=$(timeout 2 jsonfilter -i "$METADATA_FILE" -e '@.active_source' 2>/dev/null || echo "")
				fi

				# Cache metadata content to avoid multiple reads
				local metadata_content=""
				if [ -f "$METADATA_FILE" ]; then
					metadata_content=$(timeout 2 cat "$METADATA_FILE" 2>/dev/null || echo "{}")
				fi

				local sources_count=0
				local defaults_used=0
				local defaults_message=""

				_add_source_info() {
					local section="$1"
					local enabled type url path priority

					config_get_bool enabled "$section" enabled 0
					config_get type "$section" type
					config_get url "$section" url
					config_get path "$section" path
					config_get priority "$section" priority 999

					json_add_object ""
						json_add_string "name" "$section"
						json_add_boolean "enabled" "$enabled"
						json_add_string "type" "$type"
						[ -n "$url" ] && json_add_string "url" "$url"
						[ -n "$path" ] && json_add_string "path" "$path"
						json_add_int "priority" "$priority"
						json_add_boolean "active" "$([ "$section" = "$active_source" ] && echo 1 || echo 0)"

						# Get status from cached metadata (optimization with timeout)
						if [ -n "$metadata_content" ]; then
							local status=$(echo "$metadata_content" | timeout 1 jsonfilter -e "@.sources['$section'].status" 2>/dev/null || echo "")
							local last_success=$(echo "$metadata_content" | timeout 1 jsonfilter -e "@.sources['$section'].last_success" 2>/dev/null || echo "")
							[ -n "$status" ] && json_add_string "status" "$status"
							[ -n "$last_success" ] && json_add_string "last_success" "$last_success"
						fi
					json_close_object

					sources_count=$((sources_count + 1))
				}

				config_foreach _add_source_info source

				# If config exists but contains no sources, fall back to defaults
				if [ "$sources_count" -eq 0 ]; then
					_add_default_source "github" "remote" "https://raw.githubusercontent.com/CyberMind-FR/secubox-openwrt/refs/heads/master/package/secubox/secubox-core/root/usr/share/secubox/catalog.json" "" 1
					_add_default_source "embedded" "embedded" "" "/usr/share/secubox/catalog.json" 999
					defaults_used=1
					defaults_message="Catalog config empty, using built-in defaults"
				fi

				json_close_array
				if [ "$defaults_used" -eq 1 ]; then
					json_add_boolean "defaults" true
					json_add_string "message" "$defaults_message"
				fi
				json_dump
					;;

			set_catalog_source)
				# Set force_source in UCI config
				read -r input
				source=$(echo "$input" | jsonfilter -e '@.source')

				CONFIG_NAME="secubox-appstore"
				SECTION_NAME=$(uci -q show "$CONFIG_NAME" | grep "=settings" | head -n1 | cut -d'.' -f2 | cut -d'=' -f1)
				[ -z "$SECTION_NAME" ] && SECTION_NAME="main"

				if [ -n "$source" ]; then
					if uci set "${CONFIG_NAME}.${SECTION_NAME}.force_source=$source" >/dev/null 2>&1 && \
						uci commit "$CONFIG_NAME" >/dev/null 2>&1; then
						json_init
						json_add_boolean "success" 1
						json_add_string "message" "Catalog source set to: $source"
						json_dump
					else
						json_init
						json_add_boolean "success" 0
						json_add_string "error" "Failed to update UCI config"
						json_dump
					fi

				else
					json_init
					json_add_boolean "success" 0
					json_add_string "error" "No source specified"
					json_dump
				fi
				;;

			sync_catalog)
				# Trigger catalog sync
				read -r input
				source=$(echo "$input" | jsonfilter -e '@.source')

				# Call secubox-catalog-sync (with or without source)
				if /usr/sbin/secubox-appstore sync ${source:+"$source"} 2>&1; then
					json_init
					json_add_boolean "success" 1
					json_add_string "message" "Catalog synced successfully"
					[ -n "$source" ] && json_add_string "source" "$source"
					json_dump
				else
					json_init
					json_add_boolean "success" 0
					json_add_string "error" "Sync failed"
					json_dump
				fi
				;;

			check_updates)
				# Check for available updates
				/usr/sbin/secubox-appstore check-updates --json
				;;

			get_app_versions)
				# Get version info for specific app
				read -r input
				app_id=$(echo "$input" | jsonfilter -e '@.app_id')

				CATALOG_FILE="/usr/share/secubox/catalog.json"
				METADATA_FILE="/var/lib/secubox/catalog-metadata.json"

				json_init

				# Get catalog version
				if [ -f "$CATALOG_FILE" ]; then
					pkg_version=$(jsonfilter -i "$CATALOG_FILE" -e "@.plugins[@.id='$app_id'].pkg_version" 2>/dev/null)
					app_version=$(jsonfilter -i "$CATALOG_FILE" -e "@.plugins[@.id='$app_id'].app_version" 2>/dev/null)
					[ -n "$pkg_version" ] && json_add_string "catalog_pkg_version" "$pkg_version"
					[ -n "$app_version" ] && json_add_string "catalog_app_version" "$app_version"
				fi

				# Get installed version
				pkg_name=$(jsonfilter -i "$CATALOG_FILE" -e "@.plugins[@.id='$app_id'].packages.required[0]" 2>/dev/null)
				if [ -n "$pkg_name" ]; then
					installed_version=$(opkg list-installed | grep "^$pkg_name " | awk '{print $3}')
					[ -n "$installed_version" ] && json_add_string "installed_version" "$installed_version"
				fi

				# Get metadata version info
				if [ -f "$METADATA_FILE" ]; then
					metadata_version=$(jsonfilter -i "$METADATA_FILE" -e "@.installed_apps['$app_id'].installed_version" 2>/dev/null)
					update_available=$(jsonfilter -i "$METADATA_FILE" -e "@.installed_apps['$app_id'].update_available" 2>/dev/null)
					[ -n "$update_available" ] && json_add_boolean "update_available" "$update_available"
				fi

				json_add_string "app_id" "$app_id"
				json_dump
				;;

			get_changelog)
				# Get changelog for app
				read -r input
				app_id=$(echo "$input" | jsonfilter -e '@.app_id')
				from_version=$(echo "$input" | jsonfilter -e '@.from_version')
				to_version=$(echo "$input" | jsonfilter -e '@.to_version')

				# Use secubox-appstore CLI
				/usr/sbin/secubox-appstore changelog "$app_id" ${from_version:+"$from_version"} ${to_version:+"$to_version"}
				;;

			get_widget_data)
				# Get real-time widget data for app
				read -r input
				app_id=$(echo "$input" | jsonfilter -e '@.app_id')

				CATALOG_FILE="/usr/share/secubox/catalog.json"

				json_init
				json_add_string "app_id" "$app_id"
				json_add_int "timestamp" "$(date +%s)"

				# Get widget configuration from catalog
				if [ -f "$CATALOG_FILE" ]; then
					widget_enabled=$(jsonfilter -i "$CATALOG_FILE" -e "@.plugins[@.id='$app_id'].widget.enabled" 2>/dev/null)

					if [ "$widget_enabled" = "true" ]; then
						json_add_boolean "widget_enabled" true

						# Get version information from catalog
						catalog_version=$(jsonfilter -i "$CATALOG_FILE" -e "@.plugins[@.id='$app_id'].version" 2>/dev/null)
						pkg_version=$(jsonfilter -i "$CATALOG_FILE" -e "@.plugins[@.id='$app_id'].pkg_version" 2>/dev/null)

						[ -n "$catalog_version" ] && json_add_string "catalog_version" "$catalog_version"
						[ -n "$pkg_version" ] && json_add_string "pkg_version" "$pkg_version"

						# Get installed version from opkg
						installed_version=""
						if [ -n "$pkg_version" ]; then
							package_name=$(jsonfilter -i "$CATALOG_FILE" -e "@.plugins[@.id='$app_id'].packages.required[0]" 2>/dev/null)
							if [ -n "$package_name" ]; then
								installed_version=$(opkg info "$package_name" 2>/dev/null | awk '/^Version:/ {print $2}')
							fi
						fi
						[ -n "$installed_version" ] && json_add_string "installed_version" "$installed_version"

						# Check if installed and running
						json_add_boolean "installed" false
						json_add_boolean "running" false
						json_add_string "status" "unknown"

						# Check installation status via ubus
						if command -v ubus >/dev/null 2>&1; then
							modules_json=$(ubus call luci.secubox get_modules 2>/dev/null)
							if [ -n "$modules_json" ]; then
								package_name=$(jsonfilter -i "$CATALOG_FILE" -e "@.plugins[@.id='$app_id'].packages.required[0]" 2>/dev/null)
								if [ -n "$package_name" ]; then
									module_enabled=$(echo "$modules_json" | jsonfilter -e "@.modules['$package_name'].enabled" 2>/dev/null)
									module_running=$(echo "$modules_json" | jsonfilter -e "@.modules['$package_name'].running" 2>/dev/null)

									[ "$module_enabled" = "true" ] && json_add_boolean "installed" true
									[ "$module_running" = "true" ] && json_add_boolean "running" true

									# Set status based on state
									if [ "$module_running" = "true" ]; then
										json_add_string "status" "running"
									elif [ "$module_enabled" = "true" ]; then
										json_add_string "status" "stopped"
									else
										json_add_string "status" "not_installed"
									fi
								fi
							fi
						fi

						# Get metrics from catalog definition
						# This would call app-specific data sources (ubus, files, etc.)
						# For now, return placeholder structure
						json_add_array "metrics"
						json_close_array
					else
						json_add_boolean "widget_enabled" false
					fi
				else
					json_add_boolean "widget_enabled" false
				fi

				json_dump
				;;

			# State management methods
			get_component_state)
				read -r input
				component_id=$(echo "$input" | jsonfilter -e '@.component_id')
				/usr/sbin/secubox-state get "$component_id"
				;;

			set_component_state)
				read -r input
				component_id=$(echo "$input" | jsonfilter -e '@.component_id')
				new_state=$(echo "$input" | jsonfilter -e '@.new_state')
				reason=$(echo "$input" | jsonfilter -e '@.reason')

				result=$(/usr/sbin/secubox-state set "$component_id" "$new_state" "${reason:-manual}")

				json_init
				if echo "$result" | grep -q "Success:"; then
					json_add_boolean "success" 1
					json_add_string "message" "$result"
					json_add_string "component_id" "$component_id"
					json_add_string "new_state" "$new_state"
				else
					json_add_boolean "success" 0
					json_add_string "error" "$result"
				fi
				json_dump
				;;

			get_state_history)
				read -r input
				component_id=$(echo "$input" | jsonfilter -e '@.component_id')
				limit=$(echo "$input" | jsonfilter -e '@.limit')
				/usr/sbin/secubox-state history "$component_id" "${limit:-20}"
				;;

			list_components)
				read -r input
				state_filter=$(echo "$input" | jsonfilter -e '@.state_filter')
				type_filter=$(echo "$input" | jsonfilter -e '@.type_filter')

				args=""
				[ -n "$state_filter" ] && args="$args --state=$state_filter"
				[ -n "$type_filter" ] && args="$args --type=$type_filter"

				/usr/sbin/secubox-state list $args
				;;

			freeze_component)
				read -r input
				component_id=$(echo "$input" | jsonfilter -e '@.component_id')
				reason=$(echo "$input" | jsonfilter -e '@.reason')

				result=$(/usr/sbin/secubox-state freeze "$component_id" "${reason:-manual_freeze}")

				json_init
				if echo "$result" | grep -q "Success:"; then
					json_add_boolean "success" 1
					json_add_string "message" "$result"
				else
					json_add_boolean "success" 0
					json_add_string "error" "$result"
				fi
				json_dump
				;;

			clear_error_state)
				read -r input
				component_id=$(echo "$input" | jsonfilter -e '@.component_id')

				result=$(/usr/sbin/secubox-state clear-error "$component_id")

				json_init
				if echo "$result" | grep -q "Success:"; then
					json_add_boolean "success" 1
					json_add_string "message" "$result"
				else
					json_add_boolean "success" 0
					json_add_string "error" "$result"
				fi
				json_dump
				;;

			# Component registry methods
			get_component)
				read -r input
				component_id=$(echo "$input" | jsonfilter -e '@.component_id')
				/usr/sbin/secubox-component get "$component_id"
				;;

			list_all_components)
				read -r input
				type=$(echo "$input" | jsonfilter -e '@.type')
				profile=$(echo "$input" | jsonfilter -e '@.profile')

				args=""
				[ -n "$type" ] && args="$args --type=$type"
				[ -n "$profile" ] && args="$args --profile=$profile"

				/usr/sbin/secubox-component list $args
				;;

			get_component_tree)
				read -r input
				component_id=$(echo "$input" | jsonfilter -e '@.component_id')
				/usr/sbin/secubox-component tree "$component_id"
				;;

			update_component_settings)
				read -r input
				component_id=$(echo "$input" | jsonfilter -e '@.component_id')

				# Extract settings object from input
				# This is simplified - full implementation would parse settings JSON
				json_init
				json_add_boolean "success" 1
				json_add_string "message" "Settings update functionality available via CLI: secubox-component set-setting"
				json_dump
				;;

			sync_component_registry)
				result=$(/usr/sbin/secubox-sync-registry sync)

				json_init
				if echo "$result" | grep -q "successfully"; then
					json_add_boolean "success" 1
					json_add_string "message" "$result"
				else
					json_add_boolean "success" 0
					json_add_string "error" "$result"
				fi
				json_dump
				;;

			get_wan_access)
				/usr/sbin/secubox-wan-access json
				;;

			set_wan_access)
				read -r input
				enabled=$(echo "$input" | jsonfilter -e '@.enabled' 2>/dev/null)
				https_enabled=$(echo "$input" | jsonfilter -e '@.https_enabled' 2>/dev/null)
				https_port=$(echo "$input" | jsonfilter -e '@.https_port' 2>/dev/null)
				http_enabled=$(echo "$input" | jsonfilter -e '@.http_enabled' 2>/dev/null)
				http_port=$(echo "$input" | jsonfilter -e '@.http_port' 2>/dev/null)
				ssh_enabled=$(echo "$input" | jsonfilter -e '@.ssh_enabled' 2>/dev/null)
				ssh_port=$(echo "$input" | jsonfilter -e '@.ssh_port' 2>/dev/null)

				# Update UCI settings
				[ -n "$enabled" ] && uci set secubox.remote.enabled="$enabled"
				[ -n "$https_enabled" ] && uci set secubox.remote.https_enabled="$https_enabled"
				[ -n "$https_port" ] && uci set secubox.remote.https_port="$https_port"
				[ -n "$http_enabled" ] && uci set secubox.remote.http_enabled="$http_enabled"
				[ -n "$http_port" ] && uci set secubox.remote.http_port="$http_port"
				[ -n "$ssh_enabled" ] && uci set secubox.remote.ssh_enabled="$ssh_enabled"
				[ -n "$ssh_port" ] && uci set secubox.remote.ssh_port="$ssh_port"
				uci commit secubox

				json_init
				json_add_boolean "success" 1
				json_add_string "message" "WAN access settings updated"
				json_dump
				;;

			apply_wan_access)
				/usr/sbin/secubox-wan-access apply >/dev/null 2>&1
				json_init
				json_add_boolean "success" 1
				json_add_string "message" "WAN access rules applied"
				json_dump
				;;

		get_services)
			# Discover listening services from netstat
			# Save to temp file to avoid subshell issues with json
			TMP_SERVICES="/tmp/services_$$"
			netstat -tlnp 2>/dev/null | grep LISTEN | awk '{
				split($4, a, ":")
				port = a[length(a)]
				if (!seen[port]++) {
					split($7, p, "/")
					proc = p[2]
					if (proc == "") proc = "unknown"
					print port, $4, proc
				}
			}' | sort -n -u > "$TMP_SERVICES"

			json_init
			json_add_array "services"

			while read port local proc; do
				addr=$(echo "$local" | sed 's/:[^:]*$//')
				name="Service"; icon=""; category="other"; path=""

				case "$port" in
					22) name="SSH"; icon="lock"; category="system" ;;
					53) name="DNS"; icon="globe"; category="system" ;;
					80) name="HTTP"; icon="arrow"; path="/"; category="proxy" ;;
					443) name="HTTPS"; icon="shield"; path="/"; category="proxy" ;;
					3000) name="Gitea"; icon="git"; path=":3000"; category="app" ;;
					4000) name="HexoJS"; icon="blog"; path=":4000"; category="app" ;;
					8080) name="CrowdSec"; icon="security"; category="security" ;;
					8081) name="LuCI"; icon="settings"; path=":8081"; category="system" ;;
					8082) name="CyberFeed"; icon="feed"; path=":8082"; category="app" ;;
					8086) name="Netifyd"; icon="chart"; path=":8086"; category="monitoring" ;;
					8404) name="HAProxy Stats"; icon="stats"; path=":8404/stats"; category="monitoring" ;;
					8444) name="LuCI HTTPS"; icon="admin"; path=":8444"; category="system" ;;
					8501) name="Streamlit"; icon="app"; path=":8501"; category="app" ;;
					9000) name="Lyrion"; icon="music"; path=":9000"; category="media" ;;
					9050) name="Tor SOCKS"; icon="onion"; category="privacy" ;;
					9090) name="Lyrion CLI"; icon="music"; category="media" ;;
					2222) name="Gitea SSH"; icon="git"; category="app" ;;
					3483) name="Squeezebox"; icon="music"; category="media" ;;
				esac

				external=0
				case "$addr" in 0.0.0.0|::) external=1 ;; 127.0.0.1|::1) ;; *) external=1 ;; esac

				json_add_object ""
					json_add_int "port" "$port"
					json_add_string "address" "$addr"
					json_add_string "name" "$name"
					json_add_string "icon" "$icon"
					json_add_string "process" "$proc"
					json_add_string "category" "$category"
					json_add_boolean "external" "$external"
					[ -n "$path" ] && [ "$external" = "1" ] && json_add_string "url" "$path"
				json_close_object
			done < "$TMP_SERVICES"

			rm -f "$TMP_SERVICES"
			json_close_array
			json_dump
			;;


			*)
				json_init
				json_add_boolean "error" true
				json_add_string "message" "Unknown method: $2"
				json_dump
				exit 1
				;;
		esac
		;;
esac
