#!/bin/sh
# SecuBox Hexo CMS Controller
# Copyright (C) 2025 CyberMind.fr
#
# Manages Hexo static site generator in LXC container
# Supports multiple instances on different ports

CONFIG="hexojs"
LXC_NAME="hexojs"

# Paths
LXC_PATH="/srv/lxc"
LXC_ROOTFS="$LXC_PATH/$LXC_NAME/rootfs"
LXC_CONFIG="$LXC_PATH/$LXC_NAME/config"
SHARE_PATH="/usr/share/hexojs"

# Logging
log_info() { echo "[INFO] $*"; logger -t hexojs "$*"; }
log_warn() { echo "[WARN] $*" >&2; logger -t hexojs -p warning "$*"; }
log_error() { echo "[ERROR] $*" >&2; logger -t hexojs -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 main configuration
load_config() {
	data_path="$(uci_get main.data_path)" || data_path="/srv/hexojs"
	memory_limit="$(uci_get main.memory_limit)" || memory_limit="512M"

	# Legacy support: active_site for default instance
	active_site="$(uci_get main.active_site)" || active_site="default"
	http_port="$(uci_get main.http_port)" || http_port="4000"

	# Gitea config (shared)
	gitea_enabled="$(uci_get gitea.enabled)" || gitea_enabled="0"
	gitea_url="$(uci_get gitea.url)" || gitea_url="http://192.168.255.1:3000"
	gitea_user="$(uci_get gitea.user)" || gitea_user="admin"
	gitea_token="$(uci_get gitea.token)" || gitea_token=""
	gitea_content_repo="$(uci_get gitea.content_repo)" || gitea_content_repo="blog-content"
	gitea_content_branch="$(uci_get gitea.content_branch)" || gitea_content_branch="main"

	ensure_dir "$data_path"
	ensure_dir "$data_path/instances"
	ensure_dir "$data_path/themes"
}

# Load instance configuration
load_instance_config() {
	local instance="$1"
	[ -z "$instance" ] && instance="default"

	current_instance="$instance"

	# Check if instance section exists
	local instance_type=$(uci_get "${instance}")
	if [ "$instance_type" != "instance" ]; then
		# Legacy: check if it's old-style site section or doesn't exist
		if [ -z "$instance_type" ] && [ "$instance" = "default" ]; then
			# Use legacy main config for default
			instance_port="$http_port"
			instance_title="$(uci_get default.title)" || instance_title="My Blog"
			instance_theme="$(uci_get default.theme)" || instance_theme="cybermind"
			instance_enabled="1"
		else
			instance_port=""
			instance_title=""
			instance_theme=""
			instance_enabled="0"
			return 1
		fi
	else
		instance_port="$(uci_get ${instance}.port)" || instance_port="4000"
		instance_title="$(uci_get ${instance}.title)" || instance_title="My Blog"
		instance_theme="$(uci_get ${instance}.theme)" || instance_theme="cybermind"
		instance_enabled="$(uci_get ${instance}.enabled)" || instance_enabled="0"
	fi

	instance_path="$data_path/instances/$instance"
	instance_site="$instance_path/site"

	return 0
}

# Get list of all enabled instances
get_enabled_instances() {
	local instances=""

	# Check for instance sections in UCI
	for section in $(uci show hexojs 2>/dev/null | grep '=instance$' | cut -d'.' -f2 | cut -d'=' -f1); do
		local enabled=$(uci_get "${section}.enabled")
		[ "$enabled" = "1" ] && instances="$instances $section"
	done

	# If no instances defined, check for legacy default
	if [ -z "$instances" ]; then
		if [ -d "$data_path/site" ] || [ -d "$data_path/instances/default/site" ]; then
			instances="default"
		fi
	fi

	echo "$instances"
}

# Usage
usage() {
	cat <<EOF
SecuBox Hexo CMS Controller (Multi-Instance)

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

Container Commands:
  install           Download and setup Hexo LXC container
  uninstall         Remove Hexo container (keeps data)
  update            Update Hexo and dependencies
  status            Show service status

Instance Management:
  instance list              List all instances
  instance create <name>     Create new instance
  instance delete <name>     Delete an instance
  instance start <name>      Start instance server
  instance stop <name>       Stop instance server
  instance status <name>     Show instance status

Site Management (operates on current/specified instance):
  site create [instance]     Create Hexo site for instance
  site delete [instance]     Delete site for instance

Content Commands:
  new post "Title" [instance]   Create new blog post
  new page "Title" [instance]   Create new page
  new draft "Title" [instance]  Create new draft
  list posts [instance]         List all posts
  list drafts [instance]        List all drafts

Build Commands:
  serve [instance]        Start preview server
  build [instance]        Generate static files
  clean [instance]        Clean generated files
  deploy [instance]       Deploy to configured target
  publish [instance]      Copy static files to /www/

Service Commands:
  service-run         Run all instances (for init)
  service-stop        Stop all instances

Gitea Integration:
  gitea setup [instance]   Configure git credentials
  gitea clone [instance]   Clone content repo
  gitea sync [instance]    Pull latest content
  gitea push [instance]    Push changes to Gitea

GitHub Integration:
  github clone <url> [instance] [branch]  Clone from GitHub

Backup/Restore:
  backup [instance] [name]     Create backup
  backup list                  List all backups
  backup delete <name>         Delete a backup
  restore <name> [instance]    Restore from backup

Quick Commands:
  quick-publish [instance]     Clean, build, and publish

Utility:
  shell               Open shell in container
  logs [instance]     View logs
  exec <cmd>          Execute command in container

Examples:
  hexoctl instance create myblog    # Create new instance
  hexoctl instance start myblog     # Start on configured port
  hexoctl site create myblog        # Initialize Hexo site
  hexoctl new post "Hello" myblog   # Create post in myblog

Configuration:
  /etc/config/hexojs

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
	return 0
}

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

	log_info "Creating Alpine rootfs for Hexo..."

	ensure_dir "$rootfs"

	local alpine_version="3.21"
	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 Hexo directory
	ensure_dir "$rootfs/opt/hexojs"

	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
# Hexo CMS LXC Configuration (Multi-Instance)
lxc.uts.name = $LXC_NAME
lxc.rootfs.path = dir:$LXC_ROOTFS
lxc.arch = $(uname -m)

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

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

# Environment
lxc.environment = NODE_ENV=production

# 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 - multi-instance manager
lxc.init.cmd = /opt/start-hexo-multi.sh
EOF

	log_info "LXC config created"
}

# Create multi-instance startup script
create_startup_script() {
	load_config

	local start_script="$LXC_ROOTFS/opt/start-hexo-multi.sh"
	cat > "$start_script" << 'STARTEOF'
#!/bin/sh
export PATH=/usr/local/bin:/usr/bin:/bin:$PATH
export HOME=/root
export NODE_ENV=production

HEXO_BASE="/opt/hexojs"
INSTANCES_DIR="$HEXO_BASE/instances"
PIDS_DIR="/var/run/hexo"
LOG_DIR="/var/log/hexo"

mkdir -p "$PIDS_DIR" "$LOG_DIR"

# Install dependencies on first run
if [ ! -f /opt/.installed ]; then
    echo "Installing Node.js and Hexo..."
    apk update
    apk add --no-cache nodejs npm git openssh-client
    npm install -g hexo-cli
    touch /opt/.installed
fi

# Function to start a single instance
start_instance() {
    local name="$1"
    local port="$2"
    local site_dir="$INSTANCES_DIR/$name/site"

    [ -d "$site_dir" ] || return 1
    [ -f "$site_dir/package.json" ] || return 1

    echo "Starting instance '$name' on port $port..."

    cd "$site_dir"
    [ -d "node_modules" ] || npm install

    # Start hexo server in background
    nohup npx hexo server -p "$port" -i 0.0.0.0 > "$LOG_DIR/$name.log" 2>&1 &
    echo $! > "$PIDS_DIR/$name.pid"

    echo "Instance '$name' started (PID: $!)"
}

# Function to stop an instance
stop_instance() {
    local name="$1"
    local pidfile="$PIDS_DIR/$name.pid"

    if [ -f "$pidfile" ]; then
        local pid=$(cat "$pidfile")
        if kill -0 "$pid" 2>/dev/null; then
            kill "$pid"
            echo "Stopped instance '$name' (PID: $pid)"
        fi
        rm -f "$pidfile"
    fi
}

# Read instances config from file
INSTANCES_CONF="$HEXO_BASE/instances.conf"

# Main loop - keep container running
if [ -f "$INSTANCES_CONF" ]; then
    echo "Loading instances from config..."
    while IFS=: read -r name port; do
        [ -n "$name" ] && [ -n "$port" ] && start_instance "$name" "$port"
    done < "$INSTANCES_CONF"
fi

# Legacy: check for old-style single site
if [ -d "$HEXO_BASE/site" ] && [ ! -L "$HEXO_BASE/site" ]; then
    echo "Starting legacy site on port ${HEXO_PORT:-4000}..."
    cd "$HEXO_BASE/site"
    [ -d "node_modules" ] || npm install
    nohup npx hexo server -p "${HEXO_PORT:-4000}" -i 0.0.0.0 > "$LOG_DIR/default.log" 2>&1 &
    echo $! > "$PIDS_DIR/default.pid"
fi

# Keep container running
echo "Hexo multi-instance manager running. Instances:"
ls -1 "$PIDS_DIR"/*.pid 2>/dev/null | while read f; do
    name=$(basename "$f" .pid)
    pid=$(cat "$f")
    echo "  - $name (PID: $pid)"
done

# Wait forever
exec tail -f /dev/null
STARTEOF
	chmod +x "$start_script"
}

# Generate instances.conf for container
generate_instances_conf() {
	load_config

	local conf_file="$data_path/instances.conf"
	> "$conf_file"

	for instance in $(get_enabled_instances); do
		load_instance_config "$instance" || continue
		[ "$instance_enabled" = "1" ] || continue
		[ -d "$instance_site" ] || continue
		echo "${instance}:${instance_port}" >> "$conf_file"
	done

	log_debug "Generated instances.conf with $(wc -l < "$conf_file") instances"
}

# 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 Hexo 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: hexoctl install"
		return 1
	fi

	# Regenerate config
	lxc_create_config
	create_startup_script
	generate_instances_conf

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

lxc_exec() {
	if ! lxc_running; then
		log_error "Container not running. Start with: /etc/init.d/hexojs start"
		return 1
	fi
	lxc-attach -n "$LXC_NAME" -- env PATH=/usr/local/bin:/usr/bin:/bin "$@"
}

# Instance management commands
cmd_instance_list() {
	load_config

	echo "Hexo Instances:"
	echo "---------------"

	local found=0
	for section in $(uci show hexojs 2>/dev/null | grep '=instance$' | cut -d'.' -f2 | cut -d'=' -f1); do
		found=1
		load_instance_config "$section"
		local status="disabled"
		[ "$instance_enabled" = "1" ] && status="enabled"

		local site_status="no site"
		[ -d "$instance_site" ] && site_status="site ready"

		local running=""
		if lxc_running && [ -f "$LXC_ROOTFS/var/run/hexo/${section}.pid" ]; then
			running=" [RUNNING]"
		fi

		printf "  %-15s port:%-5s %s (%s)%s\n" "$section" "$instance_port" "[$status]" "$site_status" "$running"
	done

	# Check for legacy default
	if [ "$found" = "0" ] && [ -d "$data_path/site" ]; then
		echo "  default         port:$http_port [legacy] (site ready)"
	fi

	[ "$found" = "0" ] && [ ! -d "$data_path/site" ] && echo "  (no instances)"
}

cmd_instance_create() {
	require_root
	load_config

	local name="$1"
	[ -z "$name" ] && { log_error "Instance name required"; return 1; }

	# Validate name
	echo "$name" | grep -qE '^[a-z][a-z0-9_]*$' || {
		log_error "Invalid instance name. Use lowercase letters, numbers, underscore. Start with letter."
		return 1
	}

	# Check if exists
	local existing=$(uci_get "$name")
	[ -n "$existing" ] && { log_error "Instance '$name' already exists"; return 1; }

	# Find next available port
	local port=4000
	while uci show hexojs 2>/dev/null | grep -q "port='$port'"; do
		port=$((port + 1))
	done

	# Create UCI config
	uci set hexojs.${name}=instance
	uci set hexojs.${name}.enabled='1'
	uci set hexojs.${name}.port="$port"
	uci set hexojs.${name}.title="$name Blog"
	uci set hexojs.${name}.theme='cybermind'
	uci commit hexojs

	# Create directory
	ensure_dir "$data_path/instances/$name"

	log_info "Instance '$name' created on port $port"
	log_info "Next: hexoctl site create $name"
}

cmd_instance_delete() {
	require_root
	load_config

	local name="$1"
	[ -z "$name" ] && { log_error "Instance name required"; return 1; }

	# Stop instance first
	cmd_instance_stop "$name" 2>/dev/null

	# Remove UCI config
	uci delete hexojs.${name} 2>/dev/null
	uci commit hexojs

	# Optionally remove data (ask user)
	local instance_dir="$data_path/instances/$name"
	if [ -d "$instance_dir" ]; then
		log_warn "Data directory exists: $instance_dir"
		log_info "Remove manually if needed: rm -rf $instance_dir"
	fi

	log_info "Instance '$name' deleted"
}

cmd_instance_start() {
	require_root
	load_config

	local name="$1"
	[ -z "$name" ] && { log_error "Instance name required"; return 1; }

	load_instance_config "$name" || { log_error "Instance '$name' not found"; return 1; }

	if ! lxc_running; then
		log_error "Container not running. Start with: /etc/init.d/hexojs start"
		return 1
	fi

	if [ ! -d "$instance_site" ]; then
		log_error "No site for instance '$name'. Create with: hexoctl site create $name"
		return 1
	fi

	log_info "Starting instance '$name' on port $instance_port..."

	lxc_exec sh -c "
		cd /opt/hexojs/instances/$name/site || exit 1
		[ -d node_modules ] || npm install

		# Kill existing if running
		[ -f /var/run/hexo/$name.pid ] && kill \$(cat /var/run/hexo/$name.pid) 2>/dev/null

		mkdir -p /var/run/hexo /var/log/hexo
		nohup npx hexo server -p $instance_port -i 0.0.0.0 > /var/log/hexo/$name.log 2>&1 &
		echo \$! > /var/run/hexo/$name.pid
		echo \"Started on port $instance_port (PID: \$!)\"
	"

	# Update instances.conf
	generate_instances_conf
}

cmd_instance_stop() {
	require_root
	load_config

	local name="$1"
	[ -z "$name" ] && { log_error "Instance name required"; return 1; }

	if ! lxc_running; then
		return 0
	fi

	log_info "Stopping instance '$name'..."

	lxc_exec sh -c "
		if [ -f /var/run/hexo/$name.pid ]; then
			kill \$(cat /var/run/hexo/$name.pid) 2>/dev/null
			rm -f /var/run/hexo/$name.pid
			echo 'Stopped'
		else
			echo 'Not running'
		fi
	"
}

cmd_instance_status() {
	load_config

	local name="$1"
	[ -z "$name" ] && { log_error "Instance name required"; return 1; }

	load_instance_config "$name" || { log_error "Instance '$name' not found"; return 1; }

	local running="false"
	local pid=""

	if lxc_running; then
		pid=$(lxc_exec cat /var/run/hexo/$name.pid 2>/dev/null)
		if [ -n "$pid" ] && lxc_exec kill -0 "$pid" 2>/dev/null; then
			running="true"
		fi
	fi

	local site_exists="false"
	[ -d "$instance_site" ] && site_exists="true"

	cat << EOF
Instance: $name
--------------
Enabled:  $([ "$instance_enabled" = "1" ] && echo "yes" || echo "no")
Running:  $([ "$running" = "true" ] && echo "yes (PID: $pid)" || echo "no")
Port:     $instance_port
Title:    $instance_title
Theme:    $instance_theme
Site:     $([ "$site_exists" = "true" ] && echo "ready" || echo "not created")
Path:     $instance_path

EOF

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

# Commands
cmd_install() {
	require_root
	load_config

	log_info "Installing Hexo CMS..."

	lxc_check_prereqs || exit 1

	if ! lxc_exists; then
		lxc_create_rootfs || exit 1
	fi

	lxc_create_config || exit 1
	create_startup_script

	# Copy theme
	if [ -d "$SHARE_PATH/themes/cybermind" ]; then
		log_info "Installing CyberMind theme..."
		ensure_dir "$data_path/themes"
		cp -r "$SHARE_PATH/themes/cybermind" "$data_path/themes/"
	fi

	# Copy scaffolds
	if [ -d "$SHARE_PATH/scaffolds" ]; then
		ensure_dir "$data_path/scaffolds"
		cp -r "$SHARE_PATH/scaffolds/"* "$data_path/scaffolds/"
	fi

	log_info "Installation complete!"
	log_info ""
	log_info "Next steps:"
	log_info "  1. Create instance: hexoctl instance create myblog"
	log_info "  2. Create site: hexoctl site create myblog"
	log_info "  3. Start service: /etc/init.d/hexojs start"
}

cmd_uninstall() {
	require_root

	log_info "Uninstalling Hexo CMS..."

	/etc/init.d/hexojs stop 2>/dev/null || true
	/etc/init.d/hexojs disable 2>/dev/null || true

	lxc_stop

	if [ -d "$LXC_PATH/$LXC_NAME" ]; then
		rm -rf "$LXC_PATH/$LXC_NAME"
		log_info "Container removed"
	fi

	log_info "Hexo CMS uninstalled"
	log_info "Data preserved in: $(uci_get main.data_path)"
}

cmd_update() {
	require_root
	load_config

	log_info "Updating Hexo CMS..."

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

	lxc_exec sh -c 'npm update -g hexo-cli'

	# Update each instance
	for instance in $(get_enabled_instances); do
		load_instance_config "$instance" || continue
		if [ -d "$instance_site" ]; then
			log_info "Updating instance '$instance'..."
			lxc_exec sh -c "cd /opt/hexojs/instances/$instance/site && npm update"
		fi
	done

	log_info "Update complete!"
}

cmd_status() {
	load_config

	local enabled="$(uci_get main.enabled)"
	local running="false"
	lxc_running && running="true"

	cat << EOF
Hexo CMS Status
===============
Enabled:     $([ "$enabled" = "1" ] && echo "yes" || echo "no")
Running:     $([ "$running" = "true" ] && echo "yes" || echo "no")
Data Path:   $data_path
Memory:      $memory_limit
Container:   $LXC_NAME

Instances:
EOF

	for instance in $(get_enabled_instances); do
		load_instance_config "$instance" || continue
		local status="stopped"
		if [ "$running" = "true" ]; then
			local pid=$(lxc_exec cat /var/run/hexo/$instance.pid 2>/dev/null)
			[ -n "$pid" ] && status="running:$instance_port"
		fi
		printf "  %-15s %s\n" "$instance" "[$status]"
	done
}

# Site management (instance-aware)
cmd_site_create() {
	require_root
	load_config

	local instance="${1:-default}"
	load_instance_config "$instance" || {
		# Auto-create instance if it doesn't exist
		log_info "Creating instance '$instance'..."
		cmd_instance_create "$instance"
		load_instance_config "$instance"
	}

	log_info "Creating Hexo site for instance: $instance"

	if [ -d "$instance_site" ]; then
		log_error "Site already exists at $instance_site"
		return 1
	fi

	ensure_dir "$instance_path"

	# Start container if not running
	local was_stopped=0
	if ! lxc_running; then
		was_stopped=1
		lxc_create_config
		create_startup_script
		lxc-start -n "$LXC_NAME" -d -f "$LXC_CONFIG"
		sleep 5
	fi

	# Create site in container
	lxc_exec sh -c "cd /opt/hexojs/instances/$instance && hexo init site" || {
		log_error "Failed to initialize site"
		return 1
	}

	# Install dependencies
	lxc_exec sh -c "cd /opt/hexojs/instances/$instance/site && npm install" || {
		log_error "Failed to install dependencies"
		return 1
	}

	# Install deploy plugin
	lxc_exec sh -c "cd /opt/hexojs/instances/$instance/site && npm install hexo-deployer-git --save" || true

	# Install theme
	if [ -d "$data_path/themes/cybermind" ]; then
		log_info "Installing CyberMind theme..."
		cp -r "$data_path/themes/cybermind" "$instance_site/themes/"
		sed -i 's/^theme:.*/theme: cybermind/' "$instance_site/_config.yml"
	fi

	# Copy scaffolds
	if [ -d "$data_path/scaffolds" ]; then
		cp -r "$data_path/scaffolds/"* "$instance_site/scaffolds/" 2>/dev/null || true
	fi

	# Update config
	if [ -f "$instance_site/_config.yml" ]; then
		sed -i "s/^title:.*/title: $instance_title/" "$instance_site/_config.yml"
		sed -i "s|^url:.*|url: http://localhost:$instance_port|" "$instance_site/_config.yml"
	fi

	if [ "$was_stopped" = "1" ]; then
		lxc_stop
	fi

	log_info "Site created for instance '$instance'!"
	log_info "Start with: hexoctl instance start $instance"
}

cmd_site_delete() {
	require_root
	load_config

	local instance="${1:-default}"
	load_instance_config "$instance" || { log_error "Instance not found"; return 1; }

	if [ ! -d "$instance_site" ]; then
		log_error "No site exists for instance '$instance'"
		return 1
	fi

	cmd_instance_stop "$instance" 2>/dev/null

	rm -rf "$instance_site"
	log_info "Site deleted for instance '$instance'"
}

# Content commands (instance-aware)
cmd_new_post() {
	require_root
	load_config

	local title="$1"
	local instance="${2:-default}"

	[ -z "$title" ] && { log_error "Title required"; return 1; }

	load_instance_config "$instance" || { log_error "Instance not found"; return 1; }

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

	lxc_exec sh -c "cd /opt/hexojs/instances/$instance/site && hexo new post \"$title\""
}

cmd_new_page() {
	require_root
	load_config

	local title="$1"
	local instance="${2:-default}"

	[ -z "$title" ] && { log_error "Title required"; return 1; }

	load_instance_config "$instance" || { log_error "Instance not found"; return 1; }

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

	lxc_exec sh -c "cd /opt/hexojs/instances/$instance/site && hexo new page \"$title\""
}

cmd_new_draft() {
	require_root
	load_config

	local title="$1"
	local instance="${2:-default}"

	[ -z "$title" ] && { log_error "Title required"; return 1; }

	load_instance_config "$instance" || { log_error "Instance not found"; return 1; }

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

	lxc_exec sh -c "cd /opt/hexojs/instances/$instance/site && hexo new draft \"$title\""
}

cmd_list_posts() {
	load_config

	local instance="${1:-default}"
	load_instance_config "$instance" || { log_error "Instance not found"; return 1; }

	local posts_dir="$instance_site/source/_posts"
	[ -d "$posts_dir" ] || { echo "[]"; return; }

	echo "["
	local first=1
	for f in "$posts_dir"/*.md; do
		[ -f "$f" ] || continue
		local filename=$(basename "$f")
		local slug="${filename%.md}"
		local title=$(grep -m1 "^title:" "$f" | sed 's/^title:[[:space:]]*//' | tr -d '"' | tr -d "'")

		[ "$first" = "1" ] || echo ","
		first=0
		echo "  {\"slug\": \"$slug\", \"title\": \"$title\"}"
	done
	echo "]"
}

cmd_list_drafts() {
	load_config

	local instance="${1:-default}"
	load_instance_config "$instance" || { log_error "Instance not found"; return 1; }

	local drafts_dir="$instance_site/source/_drafts"
	[ -d "$drafts_dir" ] || { echo "[]"; return; }

	echo "["
	local first=1
	for f in "$drafts_dir"/*.md; do
		[ -f "$f" ] || continue
		local filename=$(basename "$f")
		local slug="${filename%.md}"
		local title=$(grep -m1 "^title:" "$f" | sed 's/^title:[[:space:]]*//' | tr -d '"' | tr -d "'")

		[ "$first" = "1" ] || echo ","
		first=0
		echo "  {\"slug\": \"$slug\", \"title\": \"$title\"}"
	done
	echo "]"
}

# Build commands (instance-aware)
cmd_serve() {
	require_root
	load_config

	local instance="${1:-default}"
	load_instance_config "$instance" || { log_error "Instance not found"; return 1; }

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

	log_info "Starting preview server for '$instance' on port $instance_port..."
	lxc_exec sh -c "cd /opt/hexojs/instances/$instance/site && hexo server -p $instance_port -i 0.0.0.0"
}

cmd_build() {
	require_root
	load_config

	local instance="${1:-default}"
	load_instance_config "$instance" || { log_error "Instance not found"; return 1; }

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

	log_info "Generating static files for '$instance'..."
	lxc_exec sh -c "cd /opt/hexojs/instances/$instance/site && hexo generate"
	log_info "Build complete!"
}

cmd_clean() {
	require_root
	load_config

	local instance="${1:-default}"
	load_instance_config "$instance" || { log_error "Instance not found"; return 1; }

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

	log_info "Cleaning generated files for '$instance'..."
	lxc_exec sh -c "cd /opt/hexojs/instances/$instance/site && hexo clean"
}

cmd_publish() {
	require_root
	load_config

	local instance="${1:-default}"
	load_instance_config "$instance" || { log_error "Instance not found"; return 1; }

	local public_dir="$instance_site/public"
	local portal_path="$(uci_get ${instance}.publish_path)" || portal_path="/www/${instance}"

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

	# Calculate web root
	local web_root="${portal_path#/www}"
	[ -z "$web_root" ] && web_root="/"
	[ "${web_root%/}" = "$web_root" ] && web_root="$web_root/"

	log_info "Setting root to: $web_root"

	# Update config
	sed -i "s|^root:.*|root: $web_root|" "$instance_site/_config.yml"

	log_info "Regenerating..."
	lxc_exec sh -c "cd /opt/hexojs/instances/$instance/site && hexo clean && hexo generate"

	[ -d "$public_dir" ] || { log_error "Build failed"; return 1; }

	log_info "Publishing to $portal_path..."
	ensure_dir "$portal_path"
	rsync -av --delete "$public_dir/" "$portal_path/"

	log_info "Published $(find "$portal_path" -type f | wc -l) files"
}

cmd_logs() {
	load_config

	local instance="${1:-default}"

	if lxc_running; then
		lxc_exec cat /var/log/hexo/$instance.log 2>/dev/null || echo "No logs for '$instance'"
	else
		echo "Container not running"
	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_exec() {
	require_root
	lxc_exec "$@"
}

cmd_service_run() {
	require_root
	load_config

	lxc_check_prereqs || exit 1
	lxc_run
}

cmd_service_stop() {
	require_root
	lxc_stop
}

# Gitea integration (instance-aware)
cmd_gitea_setup() {
	require_root
	load_config

	local instance="${1:-default}"

	if [ -z "$gitea_token" ]; then
		log_error "Gitea token not configured"
		return 1
	fi

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

	log_info "Configuring git credentials..."

	local gitea_host=$(echo "$gitea_url" | sed 's|^https\?://||' | sed 's|/.*||')

	lxc_exec sh -c "
		export PATH=/usr/local/bin:\$PATH
		git config --global user.name '$gitea_user'
		git config --global user.email '${gitea_user}@localhost'
		git config --global credential.helper store

		rm -rf ~/.git-credentials
		cat > ~/.git-credentials << CRED
https://${gitea_user}:${gitea_token}@${gitea_host}
http://${gitea_user}:${gitea_token}@${gitea_host}
CRED
		chmod 600 ~/.git-credentials
	"

	log_info "Git credentials configured"
}

cmd_gitea_clone() {
	require_root
	load_config

	local instance="${1:-default}"
	load_instance_config "$instance" || { log_error "Instance not found"; return 1; }

	if [ "$gitea_enabled" != "1" ]; then
		log_error "Gitea integration not enabled"
		return 1
	fi

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

	local content_path="$instance_path/content"

	if [ -d "$content_path/.git" ]; then
		log_info "Content repo already cloned, pulling..."
		cd "$content_path" && git pull
	else
		log_info "Cloning content repo..."

		local gitea_host=$(echo "$gitea_url" | sed 's|^https\?://||' | sed 's|/.*||')
		local clone_url="http://${gitea_user}:${gitea_token}@${gitea_host}/${gitea_user}/${gitea_content_repo}.git"

		ensure_dir "$(dirname "$content_path")"
		rm -rf "$content_path"

		git clone -b "$gitea_content_branch" "$clone_url" "$content_path" || {
			log_error "Failed to clone"
			return 1
		}
	fi

	# Check if content is a full hexo site
	if [ -f "$content_path/package.json" ] && [ -d "$content_path/source" ]; then
		log_info "Content is a complete Hexo site, linking..."
		lxc_exec sh -c "
			rm -rf /opt/hexojs/instances/$instance/site
			ln -sf /opt/hexojs/instances/$instance/content /opt/hexojs/instances/$instance/site
			cd /opt/hexojs/instances/$instance/site && npm install
		"
	fi

	log_info "Content cloned for instance '$instance'"
}

cmd_gitea_sync() {
	require_root
	load_config

	local instance="${1:-default}"
	load_instance_config "$instance" || { log_error "Instance not found"; return 1; }

	local content_path="$instance_path/content"

	[ -d "$content_path/.git" ] || { log_error "Content not cloned"; return 1; }

	log_info "Pulling latest content..."
	cd "$content_path" && git pull

	log_info "Content synced for '$instance'"
}

cmd_gitea_push() {
	require_root
	load_config

	local instance="${1:-default}"
	local message="${2:-Auto-commit from SecuBox}"
	load_instance_config "$instance" || { log_error "Instance not found"; return 1; }

	local content_path="$instance_path/content"
	[ -d "$content_path/.git" ] || { log_error "Content not cloned"; return 1; }

	log_info "Pushing changes for '$instance'..."
	cd "$content_path"
	git add -A
	git commit -m "$message" 2>/dev/null || log_info "Nothing to commit"
	git push

	log_info "Content pushed for '$instance'"
}

# GitHub integration (public repos)
cmd_github_clone() {
	require_root
	load_config

	local repo_url="$1"
	local instance="${2:-default}"
	local branch="${3:-main}"

	[ -z "$repo_url" ] && { log_error "GitHub repo URL required"; return 1; }
	load_instance_config "$instance" || {
		log_info "Creating instance '$instance'..."
		cmd_instance_create "$instance"
		load_instance_config "$instance"
	}

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

	local content_path="$instance_path/content"
	log_info "Cloning from GitHub: $repo_url (branch: $branch)"

	ensure_dir "$(dirname "$content_path")"
	rm -rf "$content_path"

	git clone -b "$branch" "$repo_url" "$content_path" || {
		log_error "Failed to clone from GitHub"
		return 1
	}

	# Check if content is a full hexo site
	if [ -f "$content_path/package.json" ] && [ -d "$content_path/source" ]; then
		log_info "Content is a complete Hexo site, linking..."
		lxc_exec sh -c "
			rm -rf /opt/hexojs/instances/$instance/site
			ln -sf /opt/hexojs/instances/$instance/content /opt/hexojs/instances/$instance/site
			cd /opt/hexojs/instances/$instance/site && npm install
		"
	fi

	log_info "GitHub repo cloned for instance '$instance'"
}

# Backup/Restore commands
cmd_backup() {
	require_root
	load_config

	local instance="${1:-default}"
	local backup_name="${2:-$(date +%Y%m%d-%H%M%S)}"

	load_instance_config "$instance" || { log_error "Instance not found"; return 1; }

	local backup_dir="$data_path/backups"
	ensure_dir "$backup_dir"

	local backup_file="$backup_dir/${instance}_${backup_name}.tar.gz"

	if [ ! -d "$instance_site" ]; then
		log_error "No site to backup for instance '$instance'"
		return 1
	fi

	log_info "Creating backup: $backup_file"

	# Backup site directory and config
	tar -czf "$backup_file" \
		-C "$instance_path" site \
		-C /etc/config hexojs 2>/dev/null || {
		log_error "Backup failed"
		return 1
	}

	local size=$(du -h "$backup_file" | cut -f1)
	log_info "Backup created: $backup_file ($size)"
}

cmd_restore() {
	require_root
	load_config

	local backup_name="$1"
	local instance="${2:-default}"

	[ -z "$backup_name" ] && { log_error "Backup name required"; return 1; }

	local backup_dir="$data_path/backups"
	local backup_file="$backup_dir/$backup_name"

	# Try with and without .tar.gz extension
	[ -f "$backup_file" ] || backup_file="$backup_dir/${backup_name}.tar.gz"
	[ -f "$backup_file" ] || backup_file="$backup_dir/${instance}_${backup_name}.tar.gz"
	[ -f "$backup_file" ] || { log_error "Backup not found: $backup_name"; return 1; }

	load_instance_config "$instance" || {
		log_info "Creating instance '$instance'..."
		cmd_instance_create "$instance"
		load_instance_config "$instance"
	}

	# Stop instance if running
	cmd_instance_stop "$instance" 2>/dev/null

	log_info "Restoring from: $backup_file"

	# Remove existing site
	rm -rf "$instance_site"
	ensure_dir "$instance_path"

	# Extract backup
	tar -xzf "$backup_file" -C "$instance_path" || {
		log_error "Restore failed"
		return 1
	}

	log_info "Backup restored for instance '$instance'"
	log_info "Start with: hexoctl instance start $instance"
}

cmd_backup_list() {
	load_config

	local backup_dir="$data_path/backups"
	[ -d "$backup_dir" ] || { echo "[]"; return; }

	echo "["
	local first=1
	for f in "$backup_dir"/*.tar.gz; do
		[ -f "$f" ] || continue
		local name=$(basename "$f" .tar.gz)
		local size=$(du -h "$f" | cut -f1)
		local ts=$(stat -c %Y "$f" 2>/dev/null || stat -f %m "$f" 2>/dev/null)

		[ "$first" = "1" ] || echo ","
		first=0
		printf '  {"name": "%s", "size": "%s", "timestamp": %s}' "$name" "$size" "${ts:-0}"
	done
	echo ""
	echo "]"
}

cmd_backup_delete() {
	require_root
	load_config

	local backup_name="$1"
	[ -z "$backup_name" ] && { log_error "Backup name required"; return 1; }

	local backup_dir="$data_path/backups"
	local backup_file="$backup_dir/$backup_name"

	[ -f "$backup_file" ] || backup_file="$backup_dir/${backup_name}.tar.gz"
	[ -f "$backup_file" ] || { log_error "Backup not found: $backup_name"; return 1; }

	rm -f "$backup_file"
	log_info "Backup deleted: $backup_name"
}

# Quick publish (build + deploy in one command)
cmd_quick_publish() {
	require_root
	load_config

	local instance="${1:-default}"
	load_instance_config "$instance" || { log_error "Instance not found"; return 1; }

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

	log_info "Quick publish for '$instance'..."

	# Clean, build, publish
	lxc_exec sh -c "cd /opt/hexojs/instances/$instance/site && hexo clean && hexo generate" || {
		log_error "Build failed"
		return 1
	}

	cmd_publish "$instance"
	log_info "Quick publish complete!"
}

# Status JSON (for RPCD)
cmd_status_json() {
	load_config

	local enabled="$(uci_get main.enabled)"
	local running="false"
	lxc_running && running="true"

	local installed="false"
	lxc_exists && installed="true"

	cat << EOF
{
  "enabled": $([ "$enabled" = "1" ] && echo true || echo false),
  "running": $running,
  "installed": $installed,
  "data_path": "$data_path",
  "memory_limit": "$memory_limit",
  "instances": [
EOF

	local first=1
	for instance in $(get_enabled_instances); do
		load_instance_config "$instance" || continue
		local inst_running="false"
		if [ "$running" = "true" ]; then
			local pid=$(lxc_exec cat /var/run/hexo/$instance.pid 2>/dev/null)
			[ -n "$pid" ] && inst_running="true"
		fi
		local site_exists="false"
		[ -d "$instance_site" ] && site_exists="true"

		[ "$first" = "1" ] || printf ","
		first=0
		cat << EOF
    {
      "name": "$instance",
      "enabled": $([ "$instance_enabled" = "1" ] && echo true || echo false),
      "running": $inst_running,
      "port": $instance_port,
      "title": "$instance_title",
      "theme": "$instance_theme",
      "site_exists": $site_exists
    }
EOF
	done

	echo "  ]"
	echo "}"
}

cmd_instance_list_json() {
	load_config

	echo "["
	local first=1
	for section in $(uci show hexojs 2>/dev/null | grep '=instance$' | cut -d'.' -f2 | cut -d'=' -f1); do
		load_instance_config "$section"
		local running="false"
		if lxc_running && [ -f "$LXC_ROOTFS/var/run/hexo/${section}.pid" ]; then
			running="true"
		fi
		local site_exists="false"
		[ -d "$instance_site" ] && site_exists="true"

		[ "$first" = "1" ] || echo ","
		first=0
		cat << EOF
  {
    "name": "$section",
    "enabled": $([ "$instance_enabled" = "1" ] && echo true || echo false),
    "running": $running,
    "port": $instance_port,
    "title": "$instance_title",
    "theme": "$instance_theme",
    "site_exists": $site_exists
  }
EOF
	done
	echo "]"
}

# Main
case "${1:-}" in
	install)    shift; cmd_install "$@" ;;
	uninstall)  shift; cmd_uninstall "$@" ;;
	update)     shift; cmd_update "$@" ;;
	status)     shift; cmd_status "$@" ;;

	instance)
		shift
		case "${1:-}" in
			list)   shift; cmd_instance_list "$@" ;;
			create) shift; cmd_instance_create "$@" ;;
			delete) shift; cmd_instance_delete "$@" ;;
			start)  shift; cmd_instance_start "$@" ;;
			stop)   shift; cmd_instance_stop "$@" ;;
			status) shift; cmd_instance_status "$@" ;;
			*)      echo "Usage: hexoctl instance {list|create|delete|start|stop|status} [name]" ;;
		esac
		;;

	site)
		shift
		case "${1:-}" in
			create) shift; cmd_site_create "$@" ;;
			delete) shift; cmd_site_delete "$@" ;;
			list)   shift; cmd_instance_list "$@" ;;
			*)      echo "Usage: hexoctl site {create|delete|list} [instance]" ;;
		esac
		;;

	new)
		shift
		case "${1:-}" in
			post)  shift; cmd_new_post "$@" ;;
			page)  shift; cmd_new_page "$@" ;;
			draft) shift; cmd_new_draft "$@" ;;
			*)     echo "Usage: hexoctl new {post|page|draft} \"Title\" [instance]" ;;
		esac
		;;

	list)
		shift
		case "${1:-}" in
			posts)  shift; cmd_list_posts "$@" ;;
			drafts) shift; cmd_list_drafts "$@" ;;
			*)      echo "Usage: hexoctl list {posts|drafts} [instance]" ;;
		esac
		;;

	serve)      shift; cmd_serve "$@" ;;
	build|generate) shift; cmd_build "$@" ;;
	clean)      shift; cmd_clean "$@" ;;
	publish)    shift; cmd_publish "$@" ;;

	logs)       shift; cmd_logs "$@" ;;
	shell)      shift; cmd_shell "$@" ;;
	exec)       shift; cmd_exec "$@" ;;

	service-run)  shift; cmd_service_run "$@" ;;
	service-stop) shift; cmd_service_stop "$@" ;;

	gitea)
		shift
		case "${1:-}" in
			setup)  shift; cmd_gitea_setup "$@" ;;
			clone)  shift; cmd_gitea_clone "$@" ;;
			sync)   shift; cmd_gitea_sync "$@" ;;
			push)   shift; cmd_gitea_push "$@" ;;
			*)      echo "Usage: hexoctl gitea {setup|clone|sync|push} [instance] [message]" ;;
		esac
		;;

	github)
		shift
		case "${1:-}" in
			clone)  shift; cmd_github_clone "$@" ;;
			*)      echo "Usage: hexoctl github clone <repo_url> [instance] [branch]" ;;
		esac
		;;

	backup)
		shift
		case "${1:-}" in
			list)   shift; cmd_backup_list "$@" ;;
			create) shift; cmd_backup "$@" ;;
			delete) shift; cmd_backup_delete "$@" ;;
			restore) shift; cmd_restore "$@" ;;
			"")     cmd_backup "$@" ;;
			*)      cmd_backup "$@" ;;
		esac
		;;

	restore)    shift; cmd_restore "$@" ;;
	quick-publish) shift; cmd_quick_publish "$@" ;;
	status-json) cmd_status_json ;;
	instance-list-json) cmd_instance_list_json ;;

	*)          usage ;;
esac
