#!/bin/sh
# SecuBox Lyrion manager - Multi-runtime support (Docker/LXC)
# Copyright (C) 2024 CyberMind.fr

CONFIG="lyrion"
CONTAINER_NAME="secbx-lyrion"
LXC_NAME="lyrion"
OPKG_UPDATED=0

# Paths
LXC_PATH="/srv/lxc"
LXC_ROOTFS="$LXC_PATH/$LXC_NAME/rootfs"
LXC_CONFIG="$LXC_PATH/$LXC_NAME/config"
LYRION_ROOTFS_SCRIPT="/usr/share/lyrion/create-lxc-rootfs.sh"

usage() {
	cat <<'EOF'
Usage: lyrionctl <command>

Commands:
  install         Install prerequisites, prep folders, pull/create container
  check           Run prerequisite checks (storage, runtime)
  update          Update container image and restart service
  destroy         Remove container and rootfs (for reinstall)
  status          Show container status
  logs            Show container logs (use -f to follow)
  shell           Open shell in container
  service-run     Internal: run container under procd
  service-stop    Stop container
  runtime         Show detected/configured runtime

Runtime Selection:
  The runtime can be configured in /etc/config/lyrion:
    option runtime 'auto'    # auto-detect (LXC preferred if available)
    option runtime 'docker'  # Force Docker
    option runtime 'lxc'     # Force LXC
EOF
}

require_root() { [ "$(id -u)" -eq 0 ] || { echo "Root required" >&2; exit 1; }; }

log_info() { echo "[INFO] $*"; }
log_warn() { echo "[WARN] $*" >&2; }
log_error() { echo "[ERROR] $*" >&2; }

uci_get() { uci -q get ${CONFIG}.main.$1; }
uci_set() { uci set ${CONFIG}.main.$1="$2" && uci commit ${CONFIG}; }

# Load configuration with defaults
load_config() {
	runtime="$(uci_get runtime || echo auto)"
	image="$(uci_get image || echo ghcr.io/lms-community/lyrionmusicserver:stable)"
	data_path="$(uci_get data_path || echo /srv/lyrion)"
	media_path="$(uci_get media_path || echo /mnt/MUSIC)"
	port="$(uci_get port || echo 9000)"
	timezone="$(uci_get timezone || cat /etc/TZ 2>/dev/null || echo UTC)"
	memory_limit="$(uci_get memory_limit || echo 256M)"
	lxc_rootfs_url="$(uci_get lxc_rootfs_url || echo '')"
	wan_access="$(uci_get wan_access || echo 0)"
	# Extra media paths (space-separated list of host:container pairs or just paths)
	# Example: /mnt/usb:/mnt/usb /mnt/sdb1
	extra_media_paths="$(uci_get extra_media_paths || echo '')"
}

ensure_dir() { [ -d "$1" ] || mkdir -p "$1"; }

# Firewall management - open Lyrion ports for LAN device access
firewall_ensure_rules() {
	local changed=0

	# Lyrion Web UI (TCP 9000)
	if ! uci show firewall 2>/dev/null | grep -q "Lyrion-Web"; then
		log_info "Creating firewall rule for Lyrion Web UI (TCP $port)..."
		uci add firewall rule
		uci set firewall.@rule[-1].name='Lyrion-Web'
		uci set firewall.@rule[-1].src='lan'
		uci set firewall.@rule[-1].dest_port="$port"
		uci set firewall.@rule[-1].proto='tcp'
		uci set firewall.@rule[-1].target='ACCEPT'
		uci set firewall.@rule[-1].enabled='1'
		changed=1
	fi

	# Lyrion CLI (TCP 9090)
	if ! uci show firewall 2>/dev/null | grep -q "Lyrion-CLI"; then
		log_info "Creating firewall rule for Lyrion CLI (TCP 9090)..."
		uci add firewall rule
		uci set firewall.@rule[-1].name='Lyrion-CLI'
		uci set firewall.@rule[-1].src='lan'
		uci set firewall.@rule[-1].dest_port='9090'
		uci set firewall.@rule[-1].proto='tcp'
		uci set firewall.@rule[-1].target='ACCEPT'
		uci set firewall.@rule[-1].enabled='1'
		changed=1
	fi

	# Slim Protocol TCP (TCP 3483) - player control
	if ! uci show firewall 2>/dev/null | grep -q "Lyrion-Slim-TCP"; then
		log_info "Creating firewall rule for Slim Protocol (TCP 3483)..."
		uci add firewall rule
		uci set firewall.@rule[-1].name='Lyrion-Slim-TCP'
		uci set firewall.@rule[-1].src='lan'
		uci set firewall.@rule[-1].dest_port='3483'
		uci set firewall.@rule[-1].proto='tcp'
		uci set firewall.@rule[-1].target='ACCEPT'
		uci set firewall.@rule[-1].enabled='1'
		changed=1
	fi

	# Slim Protocol UDP (UDP 3483) - player discovery
	if ! uci show firewall 2>/dev/null | grep -q "Lyrion-Slim-UDP"; then
		log_info "Creating firewall rule for Slim Discovery (UDP 3483)..."
		uci add firewall rule
		uci set firewall.@rule[-1].name='Lyrion-Slim-UDP'
		uci set firewall.@rule[-1].src='lan'
		uci set firewall.@rule[-1].dest_port='3483'
		uci set firewall.@rule[-1].proto='udp'
		uci set firewall.@rule[-1].target='ACCEPT'
		uci set firewall.@rule[-1].enabled='1'
		changed=1
	fi

	# WAN rules (optional, controlled by wan_access UCI option)
	if [ "$wan_access" = "1" ]; then
		# Lyrion Web UI on WAN
		if ! uci show firewall 2>/dev/null | grep -q "Lyrion-WAN-Web"; then
			log_info "Creating WAN firewall rule for Lyrion Web UI (TCP $port)..."
			uci add firewall rule
			uci set firewall.@rule[-1].name='Lyrion-WAN-Web'
			uci set firewall.@rule[-1].src='wan'
			uci set firewall.@rule[-1].dest_port="$port"
			uci set firewall.@rule[-1].proto='tcp'
			uci set firewall.@rule[-1].target='ACCEPT'
			uci set firewall.@rule[-1].enabled='1'
			changed=1
		fi

		# Lyrion CLI on WAN
		if ! uci show firewall 2>/dev/null | grep -q "Lyrion-WAN-CLI"; then
			log_info "Creating WAN firewall rule for Lyrion CLI (TCP 9090)..."
			uci add firewall rule
			uci set firewall.@rule[-1].name='Lyrion-WAN-CLI'
			uci set firewall.@rule[-1].src='wan'
			uci set firewall.@rule[-1].dest_port='9090'
			uci set firewall.@rule[-1].proto='tcp'
			uci set firewall.@rule[-1].target='ACCEPT'
			uci set firewall.@rule[-1].enabled='1'
			changed=1
		fi

		# Slim Protocol TCP on WAN
		if ! uci show firewall 2>/dev/null | grep -q "Lyrion-WAN-Slim-TCP"; then
			log_info "Creating WAN firewall rule for Slim Protocol (TCP 3483)..."
			uci add firewall rule
			uci set firewall.@rule[-1].name='Lyrion-WAN-Slim-TCP'
			uci set firewall.@rule[-1].src='wan'
			uci set firewall.@rule[-1].dest_port='3483'
			uci set firewall.@rule[-1].proto='tcp'
			uci set firewall.@rule[-1].target='ACCEPT'
			uci set firewall.@rule[-1].enabled='1'
			changed=1
		fi

		# Slim Protocol UDP on WAN
		if ! uci show firewall 2>/dev/null | grep -q "Lyrion-WAN-Slim-UDP"; then
			log_info "Creating WAN firewall rule for Slim Discovery (UDP 3483)..."
			uci add firewall rule
			uci set firewall.@rule[-1].name='Lyrion-WAN-Slim-UDP'
			uci set firewall.@rule[-1].src='wan'
			uci set firewall.@rule[-1].dest_port='3483'
			uci set firewall.@rule[-1].proto='udp'
			uci set firewall.@rule[-1].target='ACCEPT'
			uci set firewall.@rule[-1].enabled='1'
			changed=1
		fi
	else
		# Remove WAN rules if wan_access is disabled
		local i=0
		while uci -q get firewall.@rule[$i] >/dev/null 2>&1; do
			local name=$(uci -q get firewall.@rule[$i].name)
			case "$name" in
				Lyrion-WAN-*)
					uci delete "firewall.@rule[$i]"
					changed=1
					# Don't increment - array shifted after delete
					continue
					;;
			esac
			i=$((i + 1))
		done
	fi

	if [ "$changed" = "1" ]; then
		uci commit firewall
		/etc/init.d/firewall reload 2>/dev/null || true
		log_info "Firewall rules updated - Lyrion ports open on LAN${wan_access:+/WAN}"
	fi
}

# Check if a runtime is available
has_docker() {
	command -v docker >/dev/null 2>&1 && \
	command -v dockerd >/dev/null 2>&1 && \
	[ -S /var/run/docker.sock ]
}

has_lxc() {
	command -v lxc-start >/dev/null 2>&1 && \
	command -v lxc-stop >/dev/null 2>&1
}

# Detect best available runtime
detect_runtime() {
	load_config

	case "$runtime" in
		docker)
			if has_docker; then
				echo "docker"
			else
				log_error "Docker requested but not available"
				return 1
			fi
			;;
		lxc)
			if has_lxc; then
				echo "lxc"
			else
				log_error "LXC requested but not available"
				return 1
			fi
			;;
		auto|*)
			# Prefer LXC if available (lighter weight)
			if has_lxc; then
				echo "lxc"
			elif has_docker; then
				echo "docker"
			else
				log_error "No container runtime available (install lxc or docker)"
				return 1
			fi
			;;
	esac
}

# Ensure required packages are installed
ensure_packages() {
	require_root
	for pkg in "$@"; do
		if ! opkg list-installed | grep -q "^$pkg "; then
			if [ "$OPKG_UPDATED" -eq 0 ]; then
				opkg update || return 1
				OPKG_UPDATED=1
			fi
			opkg install "$pkg" || return 1
		fi
	done
}

# =============================================================================
# Docker Runtime Functions
# =============================================================================

docker_check_prereqs() {
	log_info "Checking Docker prerequisites..."
	ensure_packages dockerd docker containerd || return 1

	# Enable and start Docker
	/etc/init.d/dockerd enable >/dev/null 2>&1
	if ! /etc/init.d/dockerd status >/dev/null 2>&1; then
		/etc/init.d/dockerd start || return 1
		sleep 3
	fi

	# Wait for Docker socket
	local retry=0
	while [ ! -S /var/run/docker.sock ] && [ $retry -lt 30 ]; do
		sleep 1
		retry=$((retry + 1))
	done

	[ -S /var/run/docker.sock ] || { log_error "Docker socket not available"; return 1; }
	log_info "Docker ready"
}

docker_pull() {
	load_config
	log_info "Pulling Docker image: $image"
	docker pull "$image"
}

docker_stop() {
	docker stop "$CONTAINER_NAME" >/dev/null 2>&1 || true
	docker rm "$CONTAINER_NAME" >/dev/null 2>&1 || true
}

docker_run() {
	load_config
	docker_stop

	log_info "Starting Lyrion Docker container..."
	exec docker run --rm \
		--name "$CONTAINER_NAME" \
		-p "${port}:9000" \
		-p "9090:9090" \
		-p "3483:3483" \
		-p "3483:3483/udp" \
		-v "$data_path:/config" \
		-v "$media_path:/music:ro" \
		-e TZ="$timezone" \
		--memory="$memory_limit" \
		"$image"
}

docker_status() {
	docker ps -a --filter "name=$CONTAINER_NAME" --format "table {{.Names}}\t{{.Status}}\t{{.Ports}}"
}

docker_logs() {
	docker logs "$@" "$CONTAINER_NAME"
}

docker_shell() {
	docker exec -it "$CONTAINER_NAME" /bin/sh
}

# =============================================================================
# LXC Runtime Functions
# =============================================================================

lxc_check_prereqs() {
	log_info "Checking LXC prerequisites..."

	# Check if LXC binaries are already available (pre-installed)
	if ! has_lxc; then
		log_info "LXC not found, attempting to install..."
		ensure_packages lxc lxc-common lxc-attach lxc-start lxc-stop lxc-destroy || return 1
	fi

	# Check cgroups
	if [ ! -d /sys/fs/cgroup ]; then
		log_error "cgroups not mounted at /sys/fs/cgroup"
		return 1
	fi

	log_info "LXC ready"
}

lxc_create_rootfs() {
	load_config

	# Check for COMPLETE installation (Lyrion installed via Debian package)
	if [ -d "$LXC_ROOTFS" ] && [ -x "$LXC_ROOTFS/usr/sbin/squeezeboxserver" ] && [ -f "$LXC_CONFIG" ]; then
		log_info "LXC rootfs already exists with Lyrion installed"
		return 0
	fi

	# Check for incomplete installation (Debian exists but Lyrion not installed)
	if [ -d "$LXC_ROOTFS" ] && [ -f "$LXC_ROOTFS/etc/debian_version" ] && [ ! -x "$LXC_ROOTFS/usr/sbin/squeezeboxserver" ]; then
		log_warn "Incomplete installation detected (Debian downloaded but Lyrion not installed)"
		log_info "Cleaning up incomplete rootfs..."
		rm -rf "$LXC_PATH/$LXC_NAME"
	fi

	# Clean up old Alpine-based installation if present
	if [ -d "$LXC_ROOTFS" ] && [ -f "$LXC_ROOTFS/etc/alpine-release" ]; then
		log_warn "Old Alpine-based installation detected, replacing with Debian..."
		rm -rf "$LXC_PATH/$LXC_NAME"
	fi

	log_info "Creating LXC rootfs for Lyrion..."
	ensure_dir "$LXC_PATH/$LXC_NAME"

	# Use external script if available
	if [ -x "$LYRION_ROOTFS_SCRIPT" ]; then
		"$LYRION_ROOTFS_SCRIPT" "$LXC_ROOTFS" || return 1
	else
		# Inline rootfs creation (Debian-based)
		lxc_create_debian_rootfs || return 1
	fi

	# Verify Lyrion was actually installed
	if [ ! -x "$LXC_ROOTFS/usr/sbin/squeezeboxserver" ]; then
		log_error "Lyrion installation failed - squeezeboxserver not found"
		log_error "Check network connectivity and try again"
		return 1
	fi

	# Create LXC config
	lxc_create_config || return 1

	log_info "LXC rootfs created successfully"
}

lxc_create_debian_rootfs() {
	local arch="arm64"
	local debian_version="bookworm"
	local rootfs="$LXC_ROOTFS"

	# Detect architecture
	case "$(uname -m)" in
		x86_64) arch="amd64" ;;
		aarch64) arch="arm64" ;;
		armv7l) arch="armhf" ;;
		*) arch="amd64" ;;
	esac

	log_info "Creating Debian $debian_version ($arch) rootfs..."

	ensure_dir "$rootfs"

	# Check if debootstrap is available
	if ! command -v debootstrap >/dev/null 2>&1; then
		log_info "Installing debootstrap..."
		ensure_packages debootstrap || return 1
	fi

	# Create minimal Debian rootfs
	log_info "Running debootstrap (this may take several minutes)..."
	debootstrap --arch="$arch" --variant=minbase "$debian_version" "$rootfs" http://deb.debian.org/debian || {
		log_error "Failed to create Debian rootfs"
		return 1
	}

	# Configure DNS (use local gateway + fallback)
	cat > "$rootfs/etc/resolv.conf" << 'RESOLV'
nameserver 1.1.1.1
nameserver 8.8.8.8
search lan
RESOLV

	# Install Lyrion in the container
	cat > "$rootfs/tmp/setup-lyrion.sh" << 'SETUP'
#!/bin/bash
set -e
export DEBIAN_FRONTEND=noninteractive
export LANG=en_US.UTF-8
export LC_ALL=en_US.UTF-8

echo "Updating package lists..."
apt-get update

echo "Installing Lyrion Music Server..."
# Add Lyrion repository
apt-get install -y gnupg curl ca-certificates locales

# Generate locale
echo "en_US.UTF-8 UTF-8" > /etc/locale.gen
locale-gen

# Add Lyrion repository key and source
curl -fsSL https://downloads.lms-community.org/LyrionMusicServer.gpg -o /etc/apt/keyrings/lyrionmusicserver.gpg
echo "deb [signed-by=/etc/apt/keyrings/lyrionmusicserver.gpg] https://downloads.lms-community.org/repo/apt stable main" > /etc/apt/sources.list.d/lyrionmusicserver.list

apt-get update
apt-get install -y lyrionmusicserver

# Install additional audio codecs
apt-get install -y --no-install-recommends \
    flac \
    lame \
    sox \
    faad \
    libio-socket-ssl-perl

# Create directories with proper permissions
mkdir -p /config/prefs/plugin /config/cache /music /var/log/lyrion
chown -R nobody:nogroup /config /var/log/lyrion

# Create startup script
cat > /opt/init.sh << 'START'
#!/bin/bash
export LANG=en_US.UTF-8
export LC_ALL=en_US.UTF-8

# Ensure directories exist with proper permissions
mkdir -p /config/prefs /config/cache /var/log/lyrion /music
chown -R nobody:nogroup /config /var/log/lyrion
chmod -R 777 /config /var/log/lyrion

# Create default prefs if not exists
if [ ! -f /config/prefs/server.prefs ]; then
    cat > /config/prefs/server.prefs << PREFS
---
mediadirs:
  - /music
httpaddr: 0.0.0.0
httpport: 9000
cliport: 9090
PREFS
    chown nobody:nogroup /config/prefs/server.prefs
fi

# Run Lyrion (squeezeboxserver drops privileges to nobody when run as root)
# Listen on all interfaces (0.0.0.0) to allow WAN devices to stream
exec /usr/sbin/squeezeboxserver \
    --prefsdir /config/prefs \
    --cachedir /config/cache \
    --logdir /var/log/lyrion \
    --httpaddr 0.0.0.0 \
    --httpport 9000 \
    --cliport 9090
START
chmod +x /opt/init.sh

# Clean up
apt-get clean
rm -rf /var/lib/apt/lists/*

echo "Lyrion installed successfully"
SETUP

	chmod +x "$rootfs/tmp/setup-lyrion.sh"

	# Run setup in chroot
	log_info "Installing Lyrion in container (this may take a while)..."
	chroot "$rootfs" /bin/bash /tmp/setup-lyrion.sh || {
		log_error "Failed to install Lyrion in container"
		return 1
	}

	rm -f "$rootfs/tmp/setup-lyrion.sh"
}

lxc_create_config() {
	load_config

	# Convert memory limit to bytes for cgroup2
	local mem_bytes
	case "$memory_limit" in
		*G) mem_bytes=$(( ${memory_limit%G} * 1073741824 )) ;;
		*M) mem_bytes=$(( ${memory_limit%M} * 1048576 )) ;;
		*K) mem_bytes=$(( ${memory_limit%K} * 1024 )) ;;
		*) mem_bytes="$memory_limit" ;;
	esac

	cat > "$LXC_CONFIG" << EOF
# Lyrion LXC Configuration
lxc.uts.name = $LXC_NAME

# Root filesystem
lxc.rootfs.path = dir:$LXC_ROOTFS

# Network - share host network namespace
# Needed for Squeezebox UDP 3483 broadcast discovery
lxc.net.0.type = none

# Mounts (no cgroup:mixed - incompatible with cgroup v2)
lxc.mount.auto = proc:mixed sys:ro
lxc.mount.entry = $data_path config none bind,create=dir 0 0
lxc.mount.entry = $media_path music none bind,ro,create=dir 0 0
EOF

	# Add extra media paths if configured
	if [ -n "$extra_media_paths" ]; then
		for path_spec in $extra_media_paths; do
			local host_path container_path
			if echo "$path_spec" | grep -q ':'; then
				host_path="${path_spec%%:*}"
				container_path="${path_spec#*:}"
			else
				host_path="$path_spec"
				container_path="$path_spec"
			fi
			# Remove leading slash for container path (LXC relative mount)
			container_path="${container_path#/}"
			if [ -d "$host_path" ]; then
				echo "lxc.mount.entry = $host_path $container_path none bind,ro,create=dir 0 0" >> "$LXC_CONFIG"
				log_info "Added media path: $host_path -> /$container_path"
			else
				log_info "Skipping non-existent path: $host_path"
			fi
		done
	fi

	cat >> "$LXC_CONFIG" << EOF

# Capabilities
lxc.cap.drop = sys_admin sys_module mac_admin mac_override

# cgroups limits (cgroup2 format)
lxc.cgroup2.memory.max = $mem_bytes

# cgroup v2 compatibility
lxc.seccomp.profile =
lxc.autodev = 1

# Init - Debian-based with squeezeboxserver (drops privileges to nobody internally)
lxc.init.cmd = /opt/init.sh

# Console
lxc.console.size = 1024
lxc.pty.max = 1024
EOF

	# Set ownership on data directory for nobody user
	chown -R 65534:65534 "$data_path" 2>/dev/null || true

	log_info "LXC config created at $LXC_CONFIG"
}

lxc_stop() {
	if lxc-info -n "$LXC_NAME" >/dev/null 2>&1; then
		lxc-stop -n "$LXC_NAME" -k >/dev/null 2>&1 || true
	fi
}

lxc_run() {
	load_config
	lxc_stop

	if [ ! -f "$LXC_CONFIG" ]; then
		log_error "LXC not configured. Run 'lyrionctl install' first."
		return 1
	fi

	# Ensure mount points exist
	ensure_dir "$data_path"
	ensure_dir "$media_path"

	log_info "Starting Lyrion LXC container..."
	exec lxc-start -n "$LXC_NAME" -F -f "$LXC_CONFIG"
}

lxc_status() {
	if lxc-info -n "$LXC_NAME" >/dev/null 2>&1; then
		lxc-info -n "$LXC_NAME"
	else
		echo "LXC container '$LXC_NAME' not found or not configured"
	fi
}

lxc_logs() {
	load_config
	local logfile="$LXC_ROOTFS/var/log/lyrion/server.log"

	# Also check container logs via lxc-attach if container is running
	if lxc-info -n "$LXC_NAME" -s 2>/dev/null | grep -q "RUNNING"; then
		if [ "$1" = "-f" ]; then
			lxc-attach -n "$LXC_NAME" -- tail -f /var/log/lyrion/server.log
		else
			lxc-attach -n "$LXC_NAME" -- tail -100 /var/log/lyrion/server.log
		fi
	elif [ -f "$logfile" ]; then
		if [ "$1" = "-f" ]; then
			tail -f "$logfile"
		else
			tail -100 "$logfile"
		fi
	else
		log_warn "Container not running and no log file found"
		log_info "Start the service with: /etc/init.d/lyrion start"
	fi
}

lxc_shell() {
	lxc-attach -n "$LXC_NAME" -- /bin/sh
}

lxc_destroy() {
	lxc_stop
	if [ -d "$LXC_PATH/$LXC_NAME" ]; then
		rm -rf "$LXC_PATH/$LXC_NAME"
		log_info "LXC container destroyed"
	fi
}

# =============================================================================
# Main Commands
# =============================================================================

cmd_install() {
	require_root
	load_config

	local rt=$(detect_runtime) || exit 1
	log_info "Using runtime: $rt"

	# Save detected runtime if auto
	[ "$runtime" = "auto" ] && uci_set detected_runtime "$rt"

	# Create directories
	ensure_dir "$data_path"
	ensure_dir "$media_path"

	case "$rt" in
		docker)
			docker_check_prereqs || exit 1
			docker_pull || exit 1
			;;
		lxc)
			lxc_check_prereqs || exit 1
			lxc_create_rootfs || exit 1
			;;
	esac

	# Ensure firewall rules are in place
	firewall_ensure_rules

	uci_set enabled '1'
	/etc/init.d/lyrion enable

	log_info "Lyrion installed. Start with: /etc/init.d/lyrion start"
	log_info "Web interface will be at: http://<router-ip>:$port"
}

cmd_check() {
	load_config

	log_info "Checking prerequisites..."
	log_info "Configured runtime: $runtime"

	local rt=$(detect_runtime)
	if [ -n "$rt" ]; then
		log_info "Detected runtime: $rt"
		case "$rt" in
			docker) docker_check_prereqs ;;
			lxc) lxc_check_prereqs ;;
		esac
	fi
}

cmd_update() {
	require_root
	load_config

	local rt=$(detect_runtime) || exit 1

	case "$rt" in
		docker)
			docker_pull || exit 1
			;;
		lxc)
			log_info "Updating LXC rootfs..."
			lxc_destroy
			lxc_create_rootfs || exit 1
			;;
	esac

	if /etc/init.d/lyrion enabled >/dev/null 2>&1; then
		/etc/init.d/lyrion restart
	else
		log_info "Update complete. Restart manually to apply."
	fi
}

cmd_destroy() {
	require_root
	load_config

	local rt=$(detect_runtime 2>/dev/null)

	case "$rt" in
		docker)
			docker_stop
			log_info "Docker container stopped. Image kept for reinstall."
			log_info "To remove image: docker rmi $image"
			;;
		lxc)
			lxc_destroy
			;;
		*)
			# No runtime detected, but try to clean up LXC anyway
			if [ -d "$LXC_PATH/$LXC_NAME" ]; then
				log_info "Removing LXC rootfs..."
				rm -rf "$LXC_PATH/$LXC_NAME"
				log_info "LXC container destroyed"
			else
				log_info "No container found to destroy"
			fi
			;;
	esac

	log_info "To reinstall: lyrionctl install"
}

cmd_status() {
	local rt=$(detect_runtime 2>/dev/null)
	case "$rt" in
		docker) docker_status ;;
		lxc) lxc_status ;;
		*) echo "No runtime detected" ;;
	esac
}

cmd_logs() {
	local rt=$(detect_runtime 2>/dev/null)
	case "$rt" in
		docker) docker_logs "$@" ;;
		lxc) lxc_logs "$@" ;;
		*) echo "No runtime detected" ;;
	esac
}

cmd_shell() {
	local rt=$(detect_runtime 2>/dev/null)
	case "$rt" in
		docker) docker_shell ;;
		lxc) lxc_shell ;;
		*) echo "No runtime detected" ;;
	esac
}

cmd_service_run() {
	require_root
	load_config

	# Ensure firewall rules on every start
	firewall_ensure_rules

	local rt=$(detect_runtime) || exit 1

	case "$rt" in
		docker)
			docker_check_prereqs || exit 1
			docker_run
			;;
		lxc)
			lxc_check_prereqs || exit 1
			lxc_run
			;;
	esac
}

cmd_service_stop() {
	require_root
	local rt=$(detect_runtime 2>/dev/null)
	case "$rt" in
		docker) docker_stop ;;
		lxc) lxc_stop ;;
	esac
}

cmd_runtime() {
	load_config
	echo "Configured: $runtime"

	local detected=$(detect_runtime 2>/dev/null)
	if [ -n "$detected" ]; then
		echo "Detected: $detected"
	else
		echo "Detected: none"
	fi

	echo ""
	echo "Available runtimes:"
	has_docker && echo "  - docker" || echo "  - docker (not installed)"
	has_lxc && echo "  - lxc" || echo "  - lxc (not installed)"
}

# =============================================================================
# Main Entry Point
# =============================================================================

case "${1:-}" in
	install) shift; cmd_install "$@" ;;
	check) shift; cmd_check "$@" ;;
	update) shift; cmd_update "$@" ;;
	destroy) shift; cmd_destroy "$@" ;;
	status) shift; cmd_status "$@" ;;
	logs) shift; cmd_logs "$@" ;;
	shell) shift; cmd_shell "$@" ;;
	service-run) shift; cmd_service_run "$@" ;;
	service-stop) shift; cmd_service_stop "$@" ;;
	runtime) shift; cmd_runtime "$@" ;;
	help|--help|-h|'') usage ;;
	*) echo "Unknown command: $1" >&2; usage >&2; exit 1 ;;
esac
