#!/bin/sh
#
# secubox-cloner - On-device clone image builder and server
#
# Builds and serves SecuBox clone images for same-device-type deployment.
# Cloned devices auto-resize root and join mesh as peers.
#
# Usage:
#   secubox-cloner build [--device TYPE] [--resize SIZE]  Build clone image
#   secubox-cloner serve [--start|--stop]   Manage TFTP clone server
#   secubox-cloner devices                  List supported device types
#   secubox-cloner token [--auto-approve]   Generate clone join token
#   secubox-cloner status                   Show cloner status
#   secubox-cloner list                     List pending/joined clones
#   secubox-cloner export [FILE]            Export clone image to file
#

VERSION="1.0.0"

# Directories
CLONE_DIR="/srv/secubox/clone"
TFTP_ROOT="/srv/tftp"
TOKENS_DIR="/var/run/secubox/clone-tokens"
STATE_FILE="/var/run/secubox/cloner.state"

# Colors
RED='\033[0;31m'
GREEN='\033[0;32m'
YELLOW='\033[1;33m'
CYAN='\033[0;36m'
BOLD='\033[1m'
NC='\033[0m'

log() { echo -e "${GREEN}[CLONER]${NC} $1"; }
warn() { echo -e "${YELLOW}[WARN]${NC} $1"; }
error() { echo -e "${RED}[ERROR]${NC} $1"; }

# ============================================================================
# Device Detection
# ============================================================================

detect_device() {
	local board_name=""

	# Try /tmp/sysinfo/board_name first (most reliable)
	if [ -f /tmp/sysinfo/board_name ]; then
		board_name=$(cat /tmp/sysinfo/board_name)
	fi

	# Fallback to uci
	if [ -z "$board_name" ]; then
		board_name=$(uci -q get system.@system[0].hostname 2>/dev/null || echo "")
	fi

	# Map board name to device type
	case "$board_name" in
		*mochabin*|*MOCHAbin*|globalscale,mochabin)
			echo "mochabin"
			;;
		*espressobin*ultra*|globalscale,espressobin-ultra)
			echo "espressobin-ultra"
			;;
		*espressobin*|globalscale,espressobin*)
			echo "espressobin-v7"
			;;
		*x86*|*generic*)
			echo "x86-64"
			;;
		*)
			# Try to detect from kernel
			if grep -q "Marvell" /proc/cpuinfo 2>/dev/null; then
				if grep -q "Cortex-A72" /proc/cpuinfo 2>/dev/null; then
					echo "mochabin"
				else
					echo "espressobin-v7"
				fi
			elif uname -m | grep -q "x86_64"; then
				echo "x86-64"
			else
				echo "unknown"
			fi
			;;
	esac
}

get_lan_ip() {
	uci -q get network.lan.ipaddr 2>/dev/null || echo "192.168.255.1"
}

get_device_id() {
	uci -q get secubox.main.device_id 2>/dev/null || \
		(cat /sys/class/net/eth0/address 2>/dev/null | tr -d ':' | sha256sum | cut -d' ' -f1 | cut -c1-16)
}

# ============================================================================
# Image Building
# ============================================================================

build_image() {
	local device_type="${1:-}"
	local resize_target="${2:-}"

	log "Building clone image..."

	# Use specified device type or detect current
	if [ -z "$device_type" ]; then
		device_type=$(detect_device)
	fi

	# Validate device type
	case "$device_type" in
		mochabin|espressobin-v7|espressobin-ultra|x86-64)
			;;
		*)
			error "Unknown device type: $device_type"
			error "Supported: mochabin, espressobin-v7, espressobin-ultra, x86-64"
			return 1
			;;
	esac

	log "Device type: $device_type"

	# Create directories
	mkdir -p "$CLONE_DIR"
	mkdir -p "$TFTP_ROOT"

	# Image paths - each device type has its own image
	local image_name="secubox-clone-${device_type}.img"
	local image_path="$CLONE_DIR/$image_name"
	local tftp_image="$TFTP_ROOT/${image_name}"

	# Check if we have a pre-built image for this device type
	local existing_image=$(ls -t "$CLONE_DIR"/secubox-clone-${device_type}.img* 2>/dev/null | head -1)
	if [ -n "$existing_image" ] && [ -f "$existing_image" ]; then
		log "Using existing image: $existing_image"
		image_path="$existing_image"
	else
		# Try to build via ASU API if curl is available
		if command -v curl >/dev/null 2>&1; then
			log "Building image via ASU API..."
			build_via_asu "$device_type" "$image_path" || {
				warn "ASU build failed, trying local export..."
				build_local_export "$image_path"
			}
		else
			build_local_export "$image_path"
		fi
	fi

	# Inject clone provisioning script
	inject_clone_provision "$image_path"

	# Optionally resize image
	if [ -n "$resize_target" ]; then
		resize_image "$image_path" "$resize_target"
	fi

	# Copy to TFTP root with device-specific name
	log "Copying to TFTP root..."
	if [ -f "$image_path" ]; then
		if echo "$image_path" | grep -q "\.gz$"; then
			gunzip -c "$image_path" > "$tftp_image"
		else
			cp "$image_path" "$tftp_image"
		fi
		log "Clone image ready: $tftp_image"
		log "Size: $(ls -lh "$tftp_image" | awk '{print $5}')"

		# Also create generic symlink for backward compatibility
		ln -sf "$image_name" "$TFTP_ROOT/secubox-clone.img" 2>/dev/null
	fi

	# Save state
	cat > "$STATE_FILE" <<EOF
DEVICE_TYPE="$device_type"
IMAGE_PATH="$image_path"
TFTP_IMAGE="$tftp_image"
BUILD_TIME="$(date -Iseconds)"
LAN_IP="$(get_lan_ip)"
EOF

	return 0

}

# List supported devices
list_devices() {
	echo ""
	echo -e "${BOLD}Supported Device Types${NC}"
	echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
	echo "  mochabin          Globalscale MOCHAbin (Cortex-A72)"
	echo "  espressobin-v7    Globalscale ESPRESSObin v7 (Cortex-A53)"
	echo "  espressobin-ultra Globalscale ESPRESSObin Ultra"
	echo "  x86-64            Generic x86-64 PC"
	echo ""
	echo "Current device: $(detect_device)"
	echo ""
}

build_via_asu() {
	local device_type="$1"
	local output="$2"

	# Map device type to ASU profile
	local target=""
	local profile=""

	case "$device_type" in
		mochabin)
			target="mvebu/cortexa72"
			profile="globalscale_mochabin"
			;;
		espressobin-v7)
			target="mvebu/cortexa53"
			profile="globalscale_espressobin"
			;;
		espressobin-ultra)
			target="mvebu/cortexa53"
			profile="globalscale_espressobin-ultra"
			;;
		x86-64)
			target="x86/64"
			profile="generic"
			;;
		*)
			error "Unknown device type: $device_type"
			return 1
			;;
	esac

	# Get installed packages (for cloning same config)
	local packages=$(opkg list-installed 2>/dev/null | awk '{print $1}' | grep -v "^kernel" | tr '\n' ' ')

	# Minimal clone packages (core system + SecuBox essentials)
	# Use -dnsmasq to remove default and replace with dnsmasq-full
	local clone_packages="-dnsmasq dnsmasq-full luci luci-ssl curl wget-ssl ca-certificates"
	clone_packages="$clone_packages wireguard-tools luci-proto-wireguard"
	clone_packages="$clone_packages block-mount e2fsprogs"

	# Convert packages string to JSON array
	local packages_json=$(echo "$clone_packages" | tr ' ' '\n' | grep -v '^$' | sed 's/.*/"&"/' | tr '\n' ',' | sed 's/,$//')

	# Build request JSON
	local request_json="/tmp/asu-request.json"
	cat > "$request_json" <<EOF
{
  "profile": "$profile",
  "target": "$target",
  "version": "24.10.0",
  "packages": [$packages_json],
  "rootfs_size_mb": 512,
  "client": "secubox-cloner/1.0"
}
EOF

	log "Submitting ASU build request..."
	local response
	response=$(curl -s -w "\n%{http_code}" \
		-H "Content-Type: application/json" \
		-d "@$request_json" \
		"https://sysupgrade.openwrt.org/api/v1/build" 2>/dev/null)

	local http_code=$(echo "$response" | tail -1)
	local body=$(echo "$response" | sed '$d')

	if [ "$http_code" = "200" ] || [ "$http_code" = "202" ]; then
		# Extract request hash
		local request_hash=$(echo "$body" | jsonfilter -e '@.request_hash' 2>/dev/null)

		if [ -n "$request_hash" ]; then
			log "Build queued: $request_hash"
			log "This may take several minutes..."

			# Poll for completion
			local max_wait=600
			local elapsed=0
			while [ $elapsed -lt $max_wait ]; do
				sleep 10
				elapsed=$((elapsed + 10))

				response=$(curl -s "https://sysupgrade.openwrt.org/api/v1/build/$request_hash" 2>/dev/null)
				local images=$(echo "$response" | jsonfilter -e '@.images[*]' 2>/dev/null | wc -l)

				if [ "$images" -gt 0 ]; then
					# Find ext4-sdcard image
					local image_name=$(echo "$response" | jsonfilter -e '@.images[*].name' 2>/dev/null | grep -E "ext4.*sdcard" | head -1)
					if [ -z "$image_name" ]; then
						image_name=$(echo "$response" | jsonfilter -e '@.images[0].name' 2>/dev/null)
					fi

					if [ -n "$image_name" ]; then
						log "Downloading: $image_name"
						curl -# -o "$output" \
							"https://sysupgrade.openwrt.org/store/$request_hash/$image_name" || {
							error "Download failed"
							return 1
						}
						log "Image downloaded: $output"
						return 0
					fi
				fi

				printf "\r  Waiting... %ds   " "$elapsed" >&2
			done

			error "Build timed out"
			return 1
		fi
	fi

	error "ASU request failed: HTTP $http_code"
	return 1
}

build_local_export() {
	local output="$1"

	log "Creating local system export..."

	# Use sysupgrade backup as base
	local backup="/tmp/secubox-backup.tar.gz"
	sysupgrade -b "$backup" 2>/dev/null

	if [ -f "$backup" ]; then
		log "System backup created: $(ls -lh "$backup" | awk '{print $5}')"
		# For now, just note that we need a pre-built base image
		warn "Full image build requires base firmware image"
		warn "Use ASU API or provide pre-built image in $CLONE_DIR"
		return 1
	fi

	return 1
}

resize_image() {
	local image="$1"
	local target_size="$2"

	log "Resizing image to $target_size..."

	# Check for resize tools
	if ! command -v parted >/dev/null 2>&1; then
		warn "parted not available, skipping resize"
		return 1
	fi

	# This would use the resize-openwrt-image.sh approach
	# For on-device use, we'll defer resize to first boot
	log "Image will auto-resize to full disk at first boot"
	return 0
}

inject_clone_provision() {
	local image="$1"
	local master_ip=$(get_lan_ip)

	log "Generating clone provision script..."

	# Create provision script for TFTP download at first boot
	local script="$TFTP_ROOT/clone-provision.sh"
	cat > "$script" <<PROVISION
#!/bin/sh
# SecuBox Clone Provision Script
# Downloaded and executed at first boot by cloned device

MASTER_IP="$master_ip"
CLONE_TOKEN="${CLONE_TOKEN:-}"

log() { logger -t secubox-clone "\$*"; echo "\$*"; }

log "SecuBox clone provisioning starting..."
log "Master: \$MASTER_IP"

# Step 1: Resize root partition to full disk
log "Resizing root partition..."
ROOT_DEV=\$(awk '\$2=="/" {print \$1}' /proc/mounts)
if [ -n "\$ROOT_DEV" ]; then
    DISK=\$(echo "\$ROOT_DEV" | sed 's/p\\?[0-9]*\$//')
    [ "\$DISK" = "\$ROOT_DEV" ] && DISK=\$(echo "\$ROOT_DEV" | sed 's/[0-9]*\$//')
    PART_NUM=\$(echo "\$ROOT_DEV" | grep -o '[0-9]*\$')
    if command -v parted >/dev/null 2>&1; then
        parted -s "\$DISK" resizepart "\$PART_NUM" 100% 2>/dev/null || true
        resize2fs "\$ROOT_DEV" 2>/dev/null || true
        sync
        log "Root resized: \$(df -h / | tail -1 | awk '{print \$2}')"
    else
        log "parted not available, skipping resize"
    fi
fi

# Step 2: Configure as mesh peer
log "Configuring as mesh peer..."
uci set master-link.main=master-link
uci set master-link.main.role='peer'
uci set master-link.main.upstream="\$MASTER_IP"
uci commit master-link

# Step 3: Join mesh
if [ -n "\$CLONE_TOKEN" ]; then
    log "Joining mesh with pre-approved token..."
    /usr/lib/secubox/master-link.sh join "\$MASTER_IP" "\$CLONE_TOKEN" 2>/dev/null || {
        log "Token join failed, requesting approval..."
        /usr/lib/secubox/master-link.sh request_join "\$MASTER_IP" 2>/dev/null || true
    }
else
    log "No token provided, requesting mesh join (needs approval)..."
    /usr/lib/secubox/master-link.sh request_join "\$MASTER_IP" 2>/dev/null || true
fi

# Step 4: Start SecuBox services
log "Starting SecuBox services..."
/etc/init.d/secubox-core enable 2>/dev/null
/etc/init.d/secubox-core start 2>/dev/null

log "Clone provisioning complete"
PROVISION

	chmod +x "$script"
	log "Clone provision script: $script"
}

# ============================================================================
# TFTP Server
# ============================================================================

serve_start() {
	log "Starting clone TFTP server..."

	# Use existing TFTP recovery infrastructure
	if [ -x /usr/sbin/secubox-tftp-recovery ]; then
		/usr/sbin/secubox-tftp-recovery start
	else
		# Manual dnsmasq TFTP setup
		mkdir -p "$TFTP_ROOT"

		uci -q set dhcp.@dnsmasq[0].enable_tftp='1'
		uci -q set dhcp.@dnsmasq[0].tftp_root="$TFTP_ROOT"
		uci commit dhcp

		/etc/init.d/dnsmasq restart
	fi

	# Generate U-Boot script for clone
	generate_uboot_script

	local lan_ip=$(get_lan_ip)
	log "TFTP server running"
	log "Clone image: $TFTP_ROOT/secubox-clone.img"
	log "Server IP: $lan_ip:69"

	echo ""
	echo "To flash a target device, use these U-Boot commands:"
	echo "  setenv serverip $lan_ip"
	echo "  dhcp"
	echo "  tftpboot 0x20000000 secubox-clone.img"
	echo "  mmc dev 0"
	echo '  mmc write 0x20000000 0 ${filesize}'
	echo "  reset"
}

serve_stop() {
	log "Stopping clone TFTP server..."

	if [ -x /usr/sbin/secubox-tftp-recovery ]; then
		/usr/sbin/secubox-tftp-recovery stop
	else
		uci -q set dhcp.@dnsmasq[0].enable_tftp='0'
		uci commit dhcp
		/etc/init.d/dnsmasq restart
	fi

	log "TFTP server stopped"
}

generate_uboot_script() {
	local lan_ip=$(get_lan_ip)
	local script_dir="$TFTP_ROOT"

	# Generate human-readable U-Boot commands
	cat > "$script_dir/clone-uboot.txt" <<UBOOT
# SecuBox Clone Boot Commands
# Run these in U-Boot to flash the clone image

# 1. Set network
setenv serverip $lan_ip
setenv ipaddr 192.168.1.100

# 2. Get IP via DHCP (optional)
dhcp

# 3. Download clone image
tftpboot 0x20000000 secubox-clone.img

# 4. Write to eMMC/SD
mmc dev 0
mmc write 0x20000000 0 \${filesize}

# 5. Boot cloned system
reset
UBOOT

	log "U-Boot commands: $script_dir/clone-uboot.txt"
}

# ============================================================================
# Token Management
# ============================================================================

generate_token() {
	local auto_approve="${1:-0}"
	local ttl="${2:-86400}"  # 24 hours default

	mkdir -p "$TOKENS_DIR"

	# Generate random token
	local token=$(head -c 32 /dev/urandom | sha256sum | cut -d' ' -f1)

	# Save token metadata
	local token_file="$TOKENS_DIR/${token}.json"
	cat > "$token_file" <<EOF
{
  "token": "$token",
  "created": "$(date -Iseconds)",
  "expires": "$(date -d "+${ttl} seconds" -Iseconds 2>/dev/null || date -Iseconds)",
  "ttl": $ttl,
  "auto_approve": $([ "$auto_approve" = "1" ] && echo "true" || echo "false"),
  "type": "clone",
  "used": false
}
EOF

	# Also register with master-link if available
	if [ -x /usr/lib/secubox/master-link.sh ]; then
		/usr/lib/secubox/master-link.sh register-token "$token" "$ttl" "clone" >/dev/null 2>&1 || true
	fi

	# Export for use in provision script
	export CLONE_TOKEN="$token"

	echo "$token"
}

# ============================================================================
# Status & Listing
# ============================================================================

show_status() {
	echo ""
	echo -e "${BOLD}SecuBox Cloner v$VERSION${NC}"
	echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"

	# Device info
	local device_type=$(detect_device)
	local device_id=$(get_device_id)
	local lan_ip=$(get_lan_ip)

	echo "Device:     $device_type"
	echo "Device ID:  ${device_id:0:16}..."
	echo "LAN IP:     $lan_ip"
	echo ""

	# Build state
	echo "Clone Images:"
	if [ -d "$CLONE_DIR" ]; then
		ls "$CLONE_DIR"/*.img "$CLONE_DIR"/*.img.gz 2>/dev/null | while read img; do
			[ -f "$img" ] || continue
			local size=$(ls -lh "$img" 2>/dev/null | awk '{print $5}')
			echo "  - $(basename "$img") ($size)"
		done
	fi

	if [ -f "$TFTP_ROOT/secubox-clone.img" ]; then
		local size=$(ls -lh "$TFTP_ROOT/secubox-clone.img" | awk '{print $5}')
		echo "  - TFTP: secubox-clone.img ($size)"
	fi
	echo ""

	# TFTP status
	local tftp_enabled=$(uci -q get dhcp.@dnsmasq[0].enable_tftp)
	if [ "$tftp_enabled" = "1" ]; then
		echo -e "TFTP:       ${GREEN}Running${NC} ($lan_ip:69)"
	else
		echo -e "TFTP:       ${YELLOW}Stopped${NC}"
	fi
	echo ""

	# Pending tokens
	echo "Clone Tokens:"
	local token_count=0
	if [ -d "$TOKENS_DIR" ]; then
		ls "$TOKENS_DIR"/*.json 2>/dev/null | while read tf; do
			[ -f "$tf" ] || continue
			local token=$(jsonfilter -i "$tf" -e '@.token' 2>/dev/null | cut -c1-16)
			local used=$(jsonfilter -i "$tf" -e '@.used' 2>/dev/null)
			local auto=$(jsonfilter -i "$tf" -e '@.auto_approve' 2>/dev/null)
			if [ "$used" = "true" ]; then
				echo "  - ${token}... (used)"
			elif [ "$auto" = "true" ]; then
				echo "  - ${token}... (auto-approve)"
			else
				echo "  - ${token}... (pending)"
			fi
			token_count=$((token_count + 1))
		done
	fi
	[ $token_count -eq 0 ] && echo "  (none)"
	echo ""

	# Mesh peers (clones)
	echo "Joined Clones:"
	if [ -x /usr/lib/secubox/master-link.sh ]; then
		/usr/lib/secubox/master-link.sh peers 2>/dev/null | head -5 || echo "  (none)"
	else
		echo "  (master-link not available)"
	fi
	echo ""
}

list_clones() {
	echo ""
	echo -e "${BOLD}Cloned Devices${NC}"
	echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"

	# List from master-link
	if [ -x /usr/lib/secubox/master-link.sh ]; then
		echo ""
		echo "Active Peers:"
		/usr/lib/secubox/master-link.sh peers 2>/dev/null || echo "  (none)"

		echo ""
		echo "Pending Approvals:"
		/usr/lib/secubox/master-link.sh pending 2>/dev/null || echo "  (none)"
	else
		echo "master-link not available"
	fi
	echo ""
}

export_image() {
	local output="${1:-/tmp/secubox-clone-$(date +%Y%m%d).img.gz}"

	if [ -f "$TFTP_ROOT/secubox-clone.img" ]; then
		log "Exporting clone image..."
		gzip -c "$TFTP_ROOT/secubox-clone.img" > "$output"
		log "Exported: $output"
		log "Size: $(ls -lh "$output" | awk '{print $5}')"
	elif [ -d "$CLONE_DIR" ]; then
		local latest=$(ls -t "$CLONE_DIR"/*.img* 2>/dev/null | head -1)
		if [ -n "$latest" ]; then
			log "Copying: $latest"
			cp "$latest" "$output"
			log "Exported: $output"
		else
			error "No clone image available. Run: secubox-cloner build"
			return 1
		fi
	else
		error "No clone image available. Run: secubox-cloner build"
		return 1
	fi
}

# ============================================================================
# Serial Flash Operations
# ============================================================================

SERIAL_PORT="/dev/ttyUSB0"
SERIAL_BAUD="115200"

serial_detect() {
	log "Detecting serial ports..."
	local found=0
	for port in /dev/ttyUSB* /dev/ttyACM*; do
		if [ -c "$port" ]; then
			echo "  Found: $port"
			found=1
		fi
	done
	if [ "$found" = "0" ]; then
		warn "No serial ports found"
		return 1
	fi

	# Check if default port exists
	if [ -c "$SERIAL_PORT" ]; then
		log "Default port $SERIAL_PORT is available"
	fi
}

serial_configure() {
	local port="${1:-$SERIAL_PORT}"
	if [ ! -c "$port" ]; then
		error "Serial port $port not found"
		return 1
	fi

	# Configure serial port
	stty -F "$port" "$SERIAL_BAUD" cs8 -cstopb -parenb raw -echo 2>/dev/null
	log "Configured $port at $SERIAL_BAUD baud"
}

serial_send() {
	local port="${1:-$SERIAL_PORT}"
	local cmd="$2"
	local wait="${3:-1}"

	echo "$cmd" > "$port"
	sleep "$wait"
}

serial_break() {
	local port="${1:-$SERIAL_PORT}"
	log "Sending break sequence to enter U-Boot..."

	serial_configure "$port" || return 1

	# Send multiple newlines/breaks to catch U-Boot
	for i in 1 2 3 4 5 6 7 8 9 10; do
		echo "" > "$port"
		sleep 0.1
	done

	log "Break sequence sent - check for 'Marvell>>' prompt"
	log "Use: secubox-cloner flash console"
}

serial_console() {
	local port="${1:-$SERIAL_PORT}"

	if ! command -v socat >/dev/null 2>&1; then
		error "socat not installed. Install with: opkg install socat"
		return 1
	fi

	serial_configure "$port" || return 1

	log "Starting interactive console on $port"
	log "Press Ctrl+C to exit"
	echo ""

	socat -,raw,echo=0 "$port,b$SERIAL_BAUD,raw,echo=0"
}

serial_monitor() {
	local port="${1:-$SERIAL_PORT}"

	serial_configure "$port" || return 1

	log "Monitoring $port (Ctrl+C to exit)..."
	cat "$port"
}

serial_flash() {
	local port="${1:-$SERIAL_PORT}"
	local image="${2:-secubox-clone.img}"
	local lan_ip=$(get_lan_ip)

	# Check prerequisites
	if [ ! -c "$port" ]; then
		error "Serial port $port not found"
		return 1
	fi

	if [ ! -f "$TFTP_ROOT/$image" ]; then
		error "Image not found: $TFTP_ROOT/$image"
		error "Run: secubox-cloner build && secubox-cloner serve --start"
		return 1
	fi

	local image_size=$(stat -c%s "$TFTP_ROOT/$image" 2>/dev/null)
	local image_blocks=$((image_size / 512))

	log "=== SecuBox Serial Flash ==="
	log "Port: $port"
	log "TFTP Server: $lan_ip"
	log "Image: $image ($((image_size / 1024 / 1024)) MB)"
	log "Blocks: $image_blocks (0x$(printf '%x' $image_blocks))"
	echo ""

	serial_configure "$port" || return 1

	log "Step 1: Setting up network..."
	serial_send "$port" "setenv serverip $lan_ip" 2
	serial_send "$port" "setenv ipaddr 192.168.255.100" 2
	serial_send "$port" "setenv netmask 255.255.255.0" 1

	log "Step 2: Downloading image via TFTP..."
	serial_send "$port" "tftpboot 0x6000000 $image" 120

	log "Step 3: Writing to MMC..."
	serial_send "$port" "mmc dev 1" 3
	serial_send "$port" "mmc write 0x6000000 0 0x$(printf '%x' $image_blocks)" 180

	log "Step 4: Booting..."
	serial_send "$port" "reset" 3

	log "Flash commands sent!"
	log "Monitor progress: secubox-cloner flash console"
}

serial_uboot_cmds() {
	local lan_ip=$(get_lan_ip)
	local image="secubox-clone.img"

	if [ -f "$TFTP_ROOT/$image" ]; then
		local image_size=$(stat -c%s "$TFTP_ROOT/$image" 2>/dev/null)
		local image_blocks=$((image_size / 512))
	else
		local image_blocks="0x100000"
	fi

	echo ""
	echo -e "${BOLD}U-Boot Commands for Manual Flash:${NC}"
	echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
	echo ""
	echo "# 1. Set network (at Marvell>> prompt)"
	echo "setenv serverip $lan_ip"
	echo "setenv ipaddr 192.168.255.100"
	echo "setenv netmask 255.255.255.0"
	echo ""
	echo "# 2. Download image"
	echo "tftpboot 0x6000000 $image"
	echo ""
	echo "# 3. Write to eMMC"
	echo "mmc dev 1"
	echo "mmc write 0x6000000 0 0x$(printf '%x' $image_blocks)"
	echo ""
	echo "# 4. Boot"
	echo "reset"
	echo ""
}

# ============================================================================
# Usage
# ============================================================================

usage() {
	cat <<'EOF'
SecuBox Cloner - On-device clone image builder and server

Usage: secubox-cloner <command> [options]

Commands:
  build [--resize SIZE]     Build clone image for current device type
  serve [--start|--stop]    Manage TFTP clone server
  token [--auto-approve]    Generate clone join token (24h TTL)
  status                    Show cloner status (images, tokens, clones)
  list                      List pending and joined clones
  export [FILE]             Export clone image to file

Serial Flash Commands:
  flash detect              Detect available serial ports
  flash break [PORT]        Send break to enter U-Boot
  flash console [PORT]      Interactive serial console (socat)
  flash monitor [PORT]      Monitor serial output
  flash run [PORT] [IMAGE]  Send U-Boot flash commands
  flash uboot               Print manual U-Boot commands

Options:
  --resize SIZE             Pre-resize image (e.g., 16G for eMMC)
  --auto-approve            Token auto-approves clone join (no manual step)

Examples:
  # Build and serve clone image
  secubox-cloner build
  secubox-cloner serve --start

  # Flash a clone device via serial
  secubox-cloner flash break        # Enter U-Boot on target
  secubox-cloner flash run          # Send TFTP flash commands
  secubox-cloner flash console      # Monitor progress

  # Generate auto-approve token
  secubox-cloner token --auto-approve

  # Check status
  secubox-cloner status

  # Export for USB transfer
  secubox-cloner export /mnt/usb/clone.img.gz

Clone Workflow:
  1. Master: secubox-cloner build && secubox-cloner serve --start
  2. Target: Boot via TFTP (U-Boot commands shown after serve)
  3. Target auto-resizes root and joins mesh
  4. Master: secubox-cloner list (shows new clone)
EOF
}

# ============================================================================
# Main
# ============================================================================

case "${1:-}" in
	build)
		shift
		device_type=""
		resize=""
		while [ $# -gt 0 ]; do
			case "$1" in
				--device|-d) device_type="$2"; shift 2 ;;
				--resize) resize="$2"; shift 2 ;;
				mochabin|espressobin-v7|espressobin-ultra|x86-64) device_type="$1"; shift ;;
				*) shift ;;
			esac
		done
		build_image "$device_type" "$resize"
		;;

	devices)
		list_devices
		;;

	serve)
		case "${2:-start}" in
			--start|start) serve_start ;;
			--stop|stop) serve_stop ;;
			*) serve_start ;;
		esac
		;;

	token)
		auto_approve=0
		[ "$2" = "--auto-approve" ] && auto_approve=1
		generate_token "$auto_approve"
		;;

	status)
		show_status
		;;

	list)
		list_clones
		;;

	export)
		shift
		export_image "$@"
		;;

	flash)
		shift
		case "${1:-help}" in
			detect)
				serial_detect
				;;
			break)
				serial_break "${2:-$SERIAL_PORT}"
				;;
			console)
				serial_console "${2:-$SERIAL_PORT}"
				;;
			monitor)
				serial_monitor "${2:-$SERIAL_PORT}"
				;;
			run)
				serial_flash "${2:-$SERIAL_PORT}" "${3:-secubox-clone.img}"
				;;
			uboot|commands|cmd)
				serial_uboot_cmds
				;;
			*)
				echo "Usage: secubox-cloner flash <command> [port]"
				echo ""
				echo "Commands:"
				echo "  detect              Detect available serial ports"
				echo "  break [PORT]        Send break to enter U-Boot"
				echo "  console [PORT]      Interactive serial console"
				echo "  monitor [PORT]      Monitor serial output"
				echo "  run [PORT] [IMAGE]  Send U-Boot flash commands"
				echo "  uboot               Print manual U-Boot commands"
				;;
		esac
		;;

	help|--help|-h|"")
		usage
		;;

	*)
		error "Unknown command: $1"
		echo ""
		usage >&2
		exit 1
		;;
esac
