#!/bin/sh
# SecuBox PicoBrew Server Controller
# Copyright (C) 2025 CyberMind.fr
#
# Manages PicoBrew Server in LXC container

CONFIG="picobrew"
LXC_NAME="picobrew"

# Paths
LXC_PATH="/srv/lxc"
LXC_ROOTFS="$LXC_PATH/$LXC_NAME/rootfs"
LXC_CONFIG="$LXC_PATH/$LXC_NAME/config"
REPO_URL="https://github.com/CyberMind-FR/picobrew-server.git"
REPO_PATH="/srv/picobrew/app"

# Logging
log_info() { echo "[INFO] $*"; logger -t picobrew "$*"; }
log_error() { echo "[ERROR] $*" >&2; logger -t picobrew -p err "$*"; }
log_debug() { [ "$DEBUG" = "1" ] && echo "[DEBUG] $*"; }

# Helpers
require_root() {
	[ "$(id -u)" -eq 0 ] || {
		log_error "This command requires root privileges"
		exit 1
	}
}

has_lxc() { command -v lxc-start >/dev/null 2>&1; }
has_git() { command -v git >/dev/null 2>&1; }

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

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

# Load configuration
load_config() {
	http_port="$(uci_get main.http_port)" || http_port="8080"
	http_host="$(uci_get main.http_host)" || http_host="0.0.0.0"
	data_path="$(uci_get main.data_path)" || data_path="/srv/picobrew"
	memory_limit="$(uci_get main.memory_limit)" || memory_limit="512M"
	log_level="$(uci_get main.log_level)" || log_level="INFO"
	dns_name="$(uci_get server.dns_name)" || dns_name=""
	https_enabled="$(uci_get server.https_enabled)" || https_enabled="0"
	units="$(uci_get brewing.units)" || units="metric"

	ensure_dir "$data_path"
	ensure_dir "$data_path/recipes"
	ensure_dir "$data_path/sessions"
	ensure_dir "$data_path/logs"
}

# Usage
usage() {
	cat <<EOF
SecuBox PicoBrew Server Controller

Usage: $(basename $0) <command> [options]

Commands:
  install       Download and install PicoBrew Server
  uninstall     Remove PicoBrew Server container
  update        Update PicoBrew Server to latest version
  status        Show service status
  logs          Show container logs
  shell         Open shell in container

  service-run   Start service (used by init)
  service-stop  Stop service (used by init)

Configuration:
  /etc/config/picobrew

Data directory:
  /srv/picobrew

EOF
}

# Check prerequisites
lxc_check_prereqs() {
	if ! has_lxc; then
		log_error "LXC not installed. Install with: opkg install lxc lxc-common"
		return 1
	fi
	if ! has_git; then
		log_error "Git not installed. Install with: opkg install git"
		return 1
	fi
	return 0
}

# Clone or update repo
repo_clone() {
	load_config

	if [ -d "$REPO_PATH/.git" ]; then
		log_info "Updating PicoBrew Server repository..."
		cd "$REPO_PATH" && git pull
	else
		log_info "Cloning PicoBrew Server repository..."
		ensure_dir "$(dirname "$REPO_PATH")"
		git clone "$REPO_URL" "$REPO_PATH"
	fi
}

# Create Python LXC rootfs from Alpine
lxc_create_rootfs() {
	local rootfs="$LXC_ROOTFS"
	local arch=$(uname -m)

	log_info "Creating Alpine rootfs for PicoBrew..."

	ensure_dir "$rootfs"

	# Use Alpine mini rootfs
	local alpine_version="3.19"
	case "$arch" in
		x86_64) alpine_arch="x86_64" ;;
		aarch64) alpine_arch="aarch64" ;;
		armv7l) alpine_arch="armv7" ;;
		*) log_error "Unsupported architecture: $arch"; return 1 ;;
	esac

	local alpine_url="https://dl-cdn.alpinelinux.org/alpine/v${alpine_version}/releases/${alpine_arch}/alpine-minirootfs-${alpine_version}.0-${alpine_arch}.tar.gz"
	local tmpfile="/tmp/alpine-rootfs.tar.gz"

	log_info "Downloading Alpine rootfs..."
	wget -q -O "$tmpfile" "$alpine_url" || {
		log_error "Failed to download Alpine rootfs"
		return 1
	}

	log_info "Extracting rootfs..."
	tar -xzf "$tmpfile" -C "$rootfs" || {
		log_error "Failed to extract rootfs"
		return 1
	}
	rm -f "$tmpfile"

	# Setup resolv.conf
	cp /etc/resolv.conf "$rootfs/etc/resolv.conf" 2>/dev/null || \
		echo "nameserver 1.1.1.1" > "$rootfs/etc/resolv.conf"

	# Create startup script
	cat > "$rootfs/opt/start-picobrew.sh" << 'STARTUP'
#!/bin/sh
set -e

# Install Python and dependencies on first run
if [ ! -f /opt/.installed ]; then
    echo "Installing Python and dependencies..."
    apk update
    apk add --no-cache python3 py3-pip

    # Install picobrew_server with compatible dependency versions
    # Flask 1.1.2 requires old versions of Jinja2, markupsafe, itsdangerous, werkzeug
    echo "Installing compatible dependencies..."
    pip3 install --break-system-packages \
        "Jinja2==2.11.3" \
        "markupsafe==1.1.1" \
        "itsdangerous==1.1.0" \
        "Werkzeug==1.0.1" \
        "click==7.1.2" \
        2>/dev/null || \
    pip3 install \
        "Jinja2==2.11.3" \
        "markupsafe==1.1.1" \
        "itsdangerous==1.1.0" \
        "Werkzeug==1.0.1" \
        "click==7.1.2" \
        2>/dev/null || true

    echo "Installing picobrew_server package..."
    pip3 install --break-system-packages --no-deps picobrew_server 2>/dev/null || \
    pip3 install --no-deps picobrew_server 2>/dev/null || true

    # Install remaining deps (pybeerxml<2.0 required for Parser import)
    pip3 install --break-system-packages Flask==1.1.2 Flask-Cors==3.0.8 "pybeerxml<2.0.0" webargs==6.0.0 "marshmallow<4.0.0" 2>/dev/null || \
    pip3 install Flask==1.1.2 Flask-Cors==3.0.8 "pybeerxml<2.0.0" webargs==6.0.0 "marshmallow<4.0.0" 2>/dev/null || true

    touch /opt/.installed
fi

# Start PicoBrew Server (use pip-installed package, not /app)
cd /
export FLASK_APP=picobrew_server
export FLASK_ENV=production
export PICOBREW_HOST="${PICOBREW_HOST:-0.0.0.0}"
export PICOBREW_PORT="${PICOBREW_PORT:-8080}"
export PICOBREW_LOG_LEVEL="${PICOBREW_LOG_LEVEL:-INFO}"

echo "Starting PicoBrew Server on ${PICOBREW_HOST}:${PICOBREW_PORT}..."
exec python3 -m flask run --host="$PICOBREW_HOST" --port="$PICOBREW_PORT"
STARTUP
	chmod +x "$rootfs/opt/start-picobrew.sh"

	log_info "Rootfs created successfully"
	return 0
}

# Create LXC config
lxc_create_config() {
	load_config

	ensure_dir "$(dirname "$LXC_CONFIG")"

	# Convert memory limit to bytes
	local mem_bytes
	case "$memory_limit" in
		*G|*g) mem_bytes=$((${memory_limit%[Gg]} * 1024 * 1024 * 1024)) ;;
		*M|*m) mem_bytes=$((${memory_limit%[Mm]} * 1024 * 1024)) ;;
		*K|*k) mem_bytes=$((${memory_limit%[Kk]} * 1024)) ;;
		*) mem_bytes="$memory_limit" ;;
	esac

	cat > "$LXC_CONFIG" << EOF
# PicoBrew Server LXC Configuration
lxc.uts.name = $LXC_NAME
lxc.rootfs.path = dir:$LXC_ROOTFS
lxc.arch = $(uname -m)

# Network: use host network for device discovery
lxc.net.0.type = none

# Mount points
lxc.mount.auto = proc:mixed sys:ro cgroup:mixed
lxc.mount.entry = $data_path/recipes srv/recipes none bind,create=dir 0 0
lxc.mount.entry = $data_path/sessions srv/sessions none bind,create=dir 0 0
lxc.mount.entry = $data_path/logs srv/logs none bind,create=dir 0 0

# Environment
lxc.environment = PICOBREW_HOST=$http_host
lxc.environment = PICOBREW_PORT=$http_port
lxc.environment = PICOBREW_LOG_LEVEL=$log_level
lxc.environment = PICOBREW_UNITS=$units

# Security
lxc.cap.drop = sys_admin sys_module mac_admin mac_override sys_time sys_rawio

# Resource limits
lxc.cgroup.memory.limit_in_bytes = $mem_bytes

# Init command
lxc.init.cmd = /opt/start-picobrew.sh
EOF

	log_info "LXC config created"
}

# Container control
lxc_running() {
	lxc-info -n "$LXC_NAME" -s 2>/dev/null | grep -q "RUNNING"
}

lxc_exists() {
	[ -f "$LXC_CONFIG" ] && [ -d "$LXC_ROOTFS" ]
}

lxc_stop() {
	if lxc_running; then
		log_info "Stopping PicoBrew container..."
		lxc-stop -n "$LXC_NAME" -k 2>/dev/null || true
		sleep 2
	fi
}

lxc_run() {
	load_config
	lxc_stop

	if ! lxc_exists; then
		log_error "Container not installed. Run: picobrewctl install"
		return 1
	fi

	# Regenerate config in case settings changed
	lxc_create_config

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

# Commands
cmd_install() {
	require_root
	load_config

	log_info "Installing PicoBrew Server..."

	lxc_check_prereqs || exit 1

	# Clone repository
	repo_clone || exit 1

	# Create container
	if ! lxc_exists; then
		lxc_create_rootfs || exit 1
	fi

	lxc_create_config || exit 1

	# Enable service
	uci_set main.enabled '1'
	/etc/init.d/picobrew enable 2>/dev/null || true

	log_info "Installation complete!"
	log_info ""
	log_info "Start with: /etc/init.d/picobrew start"
	log_info "Web interface: http://<router-ip>:$http_port"
}

cmd_uninstall() {
	require_root

	log_info "Uninstalling PicoBrew Server..."

	# Stop service
	/etc/init.d/picobrew stop 2>/dev/null || true
	/etc/init.d/picobrew disable 2>/dev/null || true

	lxc_stop

	# Remove container (keep data)
	if [ -d "$LXC_PATH/$LXC_NAME" ]; then
		rm -rf "$LXC_PATH/$LXC_NAME"
		log_info "Container removed"
	fi

	uci_set main.enabled '0'

	log_info "PicoBrew Server uninstalled"
	log_info "Data preserved in: $(uci_get main.data_path)"
}

cmd_update() {
	require_root
	load_config

	log_info "Updating PicoBrew Server..."

	# Update repo
	repo_clone || exit 1

	# Recreate container to get fresh dependencies
	lxc_stop
	if [ -d "$LXC_ROOTFS" ]; then
		rm -rf "$LXC_ROOTFS"
	fi
	lxc_create_rootfs || exit 1

	# Restart if was running
	if [ "$(uci_get main.enabled)" = "1" ]; then
		/etc/init.d/picobrew restart
	fi

	log_info "Update complete!"
}

cmd_status() {
	load_config

	local enabled="$(uci_get main.enabled)"
	local running="false"
	local uptime=""

	if lxc_running; then
		running="true"
		uptime=$(lxc-info -n "$LXC_NAME" 2>/dev/null | grep -i "cpu use" | head -1)
	fi

	cat << EOF
PicoBrew Server Status
=====================
Enabled:     $([ "$enabled" = "1" ] && echo "yes" || echo "no")
Running:     $([ "$running" = "true" ] && echo "yes" || echo "no")
HTTP Port:   $http_port
Data Path:   $data_path
Memory:      $memory_limit

Container:   $LXC_NAME
Rootfs:      $LXC_ROOTFS
Config:      $LXC_CONFIG

EOF

	if [ "$running" = "true" ]; then
		echo "Web interface: http://$(uci -q get network.lan.ipaddr || echo "localhost"):$http_port"
	fi
}

cmd_logs() {
	load_config

	if [ -d "$data_path/logs" ]; then
		if [ -n "$(ls -A "$data_path/logs" 2>/dev/null)" ]; then
			tail -f "$data_path/logs"/*.log 2>/dev/null || \
			cat "$data_path/logs"/*.log 2>/dev/null || \
			echo "No logs found"
		else
			echo "No logs yet"
		fi
	else
		echo "Log directory not found"
	fi
}

cmd_shell() {
	require_root

	if ! lxc_running; then
		log_error "Container not running"
		exit 1
	fi

	lxc-attach -n "$LXC_NAME" -- /bin/sh
}

cmd_service_run() {
	require_root
	load_config

	lxc_check_prereqs || exit 1
	lxc_run
}

cmd_service_stop() {
	require_root
	lxc_stop
}

# Main
case "${1:-}" in
	install)    shift; cmd_install "$@" ;;
	uninstall)  shift; cmd_uninstall "$@" ;;
	update)     shift; cmd_update "$@" ;;
	status)     shift; cmd_status "$@" ;;
	logs)       shift; cmd_logs "$@" ;;
	shell)      shift; cmd_shell "$@" ;;
	service-run)  shift; cmd_service_run "$@" ;;
	service-stop) shift; cmd_service_stop "$@" ;;
	*)          usage ;;
esac
