#!/bin/sh
# ============================================================================
# hermes-env — Hermes Agent environment installation management script
# Usage: hermes-env setup | check | upgrade
# Environment variables: HERMES_VERSION — specify version to install
# ============================================================================

# ── Version and path constants ─────────────────────────────────────────────
HERMES_BASE="/opt/hermes"
HERMES_VENV="${HERMES_BASE}/venv"
HERMES_DATA="${HERMES_BASE}/data"
HERMES_BIN="${HERMES_VENV}/bin/hermes"
PYTHON_BIN="${HERMES_VENV}/bin/python3"
HERMES_CONFIG="/root/.hermes/config.yaml"

# PyPI mirrors
HERMES_PYPI_CN="https://mirrors.aliyun.com/pypi/simple/"
HERMES_PYPI_OFFICIAL="https://pypi.org/simple/"
HERMES_PYPI_TSINGHUA="https://pypi.tuna.tsinghua.edu.cn/simple/"

# Default API endpoint
HERMES_DEFAULT_API="https://api.boos.lat/v1"
HERMES_DEFAULT_MODEL="opus4.6"

export PATH="${HERMES_VENV}/bin:$PATH"

# ── Logging tools ──────────────────────────────────────────────────────────
log_ok()   { echo "  [✓] $*"; }
log_warn() { echo "  [!] $*"; }
log_err()  { echo "  [✗] $*"; }
log_step() { echo ""; echo "=== $* ==="; }

# ── OverlayFS fix (iStoreOS Docker /opt conflict) ─────────────────────────
_fix_opt() {
	mkdir -p /opt/hermes/.probe 2>/dev/null && { rmdir /opt/hermes/.probe 2>/dev/null; return 0; }
	[ -d /overlay/upper/opt ] && mkdir -p /overlay/upper/opt/hermes 2>/dev/null && \
		mount --bind /overlay/upper/opt /opt 2>/dev/null && return 0
	return 1
}
_fix_opt

# ── Basic tools ────────────────────────────────────────────────────────────
ensure_dir() { [ -d "$1" ] && return 0; mkdir -p "$1" 2>/dev/null || { log_err "Cannot create directory: $1"; return 1; }; }

# Check available disk space
_df_avail() {
	local p="$1"
	while [ -n "$p" ] && [ "$p" != "/" ]; do
		[ -e "$p" ] && break
		p="${p%/*}"
	done
	[ -z "$p" ] && p="/"
	df -m "$p" 2>/dev/null | tail -1 | awk '{print $(NF-2)}'
}

check_space() {
	local path="$1" need_mb="$2" label="$3"
	local avail
	avail=$(_df_avail "$path")
	[ -z "$avail" ] && return 0
	if [ "$avail" -lt "$need_mb" ]; then
		log_warn "${label} available space insufficient: ${avail}MB < ${need_mb}MB recommended"
	else
		log_ok "${label} available space: ${avail}MB"
	fi
}

# Download: wget first, curl fallback
_download() {
	local url="$1" out="$2"
	if command -v wget >/dev/null 2>&1; then
		wget -q --no-check-certificate -O "$out" "$url" 2>/dev/null
	elif command -v curl >/dev/null 2>&1; then
		curl -fsSL --connect-timeout 15 --max-time 120 -o "$out" "$url" 2>/dev/null
	else
		log_err "No download tool available (wget/curl)"; return 1
	fi
}

# Try multiple mirrors, return first success
_download_first() {
	local out="$1"; shift
	for url in "$@"; do
		[ -z "$url" ] && continue
		if _download "$url" "$out"; then
			local sz; sz=$(wc -c < "$out" 2>/dev/null || echo 0)
			[ "$sz" -gt 1000 ] && return 0
		fi
		rm -f "$out"
	done
	return 1
}

# ── Architecture detection ─────────────────────────────────────────────────
detect_arch() {
	case "$(uname -m)" in
		x86_64)  echo "x86_64" ;;
		aarch64) echo "aarch64" ;;
		armv7l)  echo "armv7l" ;;
		armv6l)  echo "armv6l" ;;
		*) log_err "Unsupported architecture: $(uname -m)"; exit 1 ;;
	esac
}

detect_libc() {
	[ -f /etc/openwrt_release ] && echo "musl" && return
	for f in /lib/ld-musl-*.so.1; do [ -f "$f" ] && echo "musl" && return; done
	echo "glibc"
}

# ── Install Python 3 ──────────────────────────────────────────────────────
install_python() {
	# Check if system python3 is available
	if command -v python3 >/dev/null 2>&1; then
		local ver
		ver=$(python3 --version 2>/dev/null | awk '{print $2}')
		log_ok "System Python3 v${ver} found"
		# Check if it's recent enough (3.8+)
		local major minor
		major=$(echo "$ver" | cut -d. -f1)
		minor=$(echo "$ver" | cut -d. -f2)
		if [ "$major" -ge 3 ] && [ "$minor" -ge 8 ] 2>/dev/null; then
			log_ok "Python3 v${ver} meets requirements (>= 3.8)"
			return 0
		fi
		log_warn "Python3 v${ver} is too old, need >= 3.8"
	fi

	log_step "Installing Python 3"

	# Try opkg first
	opkg update >/dev/null 2>&1 || true
	opkg install python3 python3-pip python3-venv 2>/dev/null | tail -5 || true

	if command -v python3 >/dev/null 2>&1; then
		log_ok "Python3 installed via opkg: $(python3 --version 2>/dev/null)"
		return 0
	fi

	# Fallback: try to install minimal python3
	opkg install python3-base python3-light 2>/dev/null | tail -5 || true

	if command -v python3 >/dev/null 2>&1; then
		log_ok "Python3 (minimal) installed: $(python3 --version 2>/dev/null)"
		# Also need pip
		opkg install python3-pip 2>/dev/null || true
		return 0
	fi

	log_err "Python3 installation failed"
	log_err "Please install manually: opkg install python3 python3-pip python3-venv"
	return 1
}

# ── Create virtual environment ─────────────────────────────────────────────
create_venv() {
	log_step "Creating Python virtual environment"

	ensure_dir "$HERMES_BASE" || exit 1

	# Remove old venv if exists
	if [ -d "$HERMES_VENV" ]; then
		log_warn "Removing old virtual environment..."
		rm -rf "$HERMES_VENV"
	fi

	# Create venv using system python3
	local sys_python
	sys_python=$(command -v python3 2>/dev/null)
	if [ -z "$sys_python" ]; then
		log_err "python3 not found in PATH"
		return 1
	fi

	"$sys_python" -m venv "$HERMES_VENV" 2>/dev/null
	if [ ! -x "$PYTHON_BIN" ]; then
		# Try without -m venv (older python)
		log_warn "python3 -m venv failed, trying virtualenv..."
		pip3 install virtualenv 2>/dev/null || true
		"$sys_python" -m virtualenv "$HERMES_VENV" 2>/dev/null
	fi

	if [ ! -x "$PYTHON_BIN" ]; then
		log_err "Failed to create virtual environment"
		return 1
	fi

	log_ok "Virtual environment created at $HERMES_VENV"

	# Upgrade pip
	log_ok "Upgrading pip..."
	"$PYTHON_BIN" -m pip install --upgrade pip 2>/dev/null | tail -2 || true

	log_ok "Python: $("$PYTHON_BIN" --version 2>/dev/null)"
}

# ── Install Hermes Agent ───────────────────────────────────────────────────
install_hermes() {
	log_step "Installing Hermes Agent"

	# Check if already installed
	if [ -x "$HERMES_BIN" ]; then
		local cur
		cur=$("$HERMES_BIN" --version 2>/dev/null | head -1 | tr -d '[:space:]')
		log_ok "Hermes Agent v${cur} already installed"
		echo "  To reinstall: hermes-env setup --force"
		return 0
	fi

	ensure_dir "$HERMES_VENV" || return 1

	# Try PyPI mirrors in order
	local install_ok=false

	for mirror in "$HERMES_PYPI_CN" "$HERMES_PYPI_TSINGHUA" "$HERMES_PYPI_OFFICIAL"; do
		log_warn "Trying: ${mirror}"
		if "$PYTHON_BIN" -m pip install hermes-agent \
			-i "$mirror" \
			--trusted-host "$(echo "$mirror" | sed 's|https://||;s|/.*||')" \
			2>&1 | tail -10; then
			install_ok=true
			break
		fi
	done

	if [ "$install_ok" = "false" ] || [ ! -x "$HERMES_BIN" ]; then
		# Try without mirror flags
		log_warn "Mirror install failed, trying default PyPI..."
		"$PYTHON_BIN" -m pip install hermes-agent 2>&1 | tail -10 || true
		[ -x "$HERMES_BIN" ] && install_ok=true
	fi

	if [ "$install_ok" = "false" ]; then
		log_err "Hermes Agent installation failed"
		log_err "Please check network connection and try again"
		return 1
	fi

	log_ok "Hermes Agent installed: $("$HERMES_BIN" --version 2>/dev/null | head -1)"
}

# ── Initialize Hermes configuration ────────────────────────────────────────
init_hermes() {
	log_step "Initializing Hermes configuration"

	mkdir -p /root/.hermes 2>/dev/null

	# Generate auth token
	local token
	token=$(uci -q get hermes.main.token 2>/dev/null || echo "")
	if [ -z "$token" ]; then
		token=$(head -c 24 /dev/urandom | hexdump -e '24/1 "%02x"' 2>/dev/null || openssl rand -hex 24 2>/dev/null || echo "hermes_$(date +%s)")
		uci set hermes.main.token="$token" 2>/dev/null || true
		uci commit hermes 2>/dev/null || true
	fi

	# Generate PTY token
	local pty_token
	pty_token=$(uci -q get hermes.main.pty_token 2>/dev/null || echo "")
	if [ -z "$pty_token" ]; then
		pty_token=$(head -c 16 /dev/urandom | hexdump -e '16/1 "%02x"' 2>/dev/null || openssl rand -hex 16 2>/dev/null || echo "pty_$(date +%s)")
		uci set hermes.main.pty_token="$pty_token" 2>/dev/null || true
		uci commit hermes 2>/dev/null || true
	fi

	# Write default config.yaml
	local port bind api_endpoint api_key model
	port=$(uci -q get hermes.main.port || echo "3000")
	bind=$(uci -q get hermes.main.bind || echo "lan")
	api_endpoint=$(uci -q get hermes.main.api_endpoint || echo "$HERMES_DEFAULT_API")
	api_key=$(uci -q get hermes.main.api_key || echo "")
	model=$(uci -q get hermes.main.model || echo "$HERMES_DEFAULT_MODEL")

	local listen_host="0.0.0.0"
	[ "$bind" = "loopback" ] && listen_host="127.0.0.1"

	cat > /root/.hermes/config.yaml << YAMLEOF
# Hermes Agent configuration
# Initialized by luci-app-hermes on $(date '+%Y-%m-%d %H:%M:%S')

gateway:
  port: ${port}
  bind: ${listen_host}
  auth:
    mode: token
    token: ${token}

api:
  endpoint: "${api_endpoint}"
  key: "${api_key}"

model:
  primary: "${model}"

tools:
  profile: coding

update:
  checkOnStart: false
YAMLEOF

	chmod 600 /root/.hermes/config.yaml 2>/dev/null || true
	log_ok "Configuration written to /root/.hermes/config.yaml"
}

# ── Command: setup ─────────────────────────────────────────────────────────
cmd_setup() {
	check_space /opt 100 "Install directory (/opt)"
	check_space /tmp 100 "Temp directory (/tmp)"

	# Already installed?
	if [ -x "$HERMES_BIN" ]; then
		echo "╔══════════════════════════════════════════════════════════════╗"
		echo "║   [!]  Hermes Agent already installed                       ║"
		echo "║        To reinstall, run: hermes-env setup --force          ║"
		echo "╚══════════════════════════════════════════════════════════════╝"
		echo "  Hermes: $("$HERMES_BIN" --version 2>/dev/null | head -1)"
		exit 0
	fi

	echo "╔══════════════════════════════════════════════════════════════╗"
	echo "║              Hermes Agent Environment Setup                  ║"
	echo "╚══════════════════════════════════════════════════════════════╝"
	echo "  Architecture: $(uname -m)"
	echo "  Libc:         $(detect_libc)"
	echo ""

	install_python || exit 1
	create_venv || exit 1
	install_hermes || exit 1
	init_hermes || exit 1

	echo ""
	echo "╔══════════════════════════════════════════════════════════════╗"
	echo "║              Setup Complete!                                 ║"
	echo "╚══════════════════════════════════════════════════════════════╝"
	echo "  Hermes:  $("$HERMES_BIN" --version 2>/dev/null | head -1)"
	echo "  Python:  $("$PYTHON_BIN" --version 2>/dev/null)"
	echo "  Config:  /root/.hermes/config.yaml"
	echo ""
	echo "  Next steps:"
	echo "    1. Edit /etc/config/hermes to set your API key"
	echo "    2. Run: /etc/init.d/hermes enable"
	echo "    3. Run: /etc/init.d/hermes start"
	echo ""
	echo "  Or use the LuCI web interface to configure and start."
}

# ── Command: check ─────────────────────────────────────────────────────────
cmd_check() {
	echo "=== Hermes Environment Check ==="

	if [ -x "$PYTHON_BIN" ]; then
		echo "Python:    $("$PYTHON_BIN" --version 2>/dev/null)"
	else
		echo "Python:    Not installed (virtual env)"
	fi

	if command -v python3 >/dev/null 2>&1; then
		echo "System Py: $(python3 --version 2>/dev/null)"
	else
		echo "System Py: Not found"
	fi

	if [ -x "$HERMES_BIN" ]; then
		echo "Hermes:    $("$HERMES_BIN" --version 2>/dev/null | head -1)"
	else
		echo "Hermes:    Not installed"
	fi

	echo "VENV:      $HERMES_VENV"
	echo "Config:    $HERMES_CONFIG"

	if [ -f "$HERMES_CONFIG" ]; then
		echo "Config OK: Yes"
	else
		echo "Config OK: No (will be created on start)"
	fi
}

# ── Command: upgrade ───────────────────────────────────────────────────────
cmd_upgrade() {
	if [ ! -x "$HERMES_BIN" ]; then
		log_err "Hermes Agent not installed. Run: hermes-env setup"
		exit 1
	fi

	log_step "Upgrading Hermes Agent"

	local upgrade_ok=false

	for mirror in "$HERMES_PYPI_CN" "$HERMES_PYPI_TSINGHUA" "$HERMES_PYPI_OFFICIAL"; do
		log_warn "Trying: ${mirror}"
		if "$PYTHON_BIN" -m pip install --upgrade hermes-agent \
			-i "$mirror" \
			--trusted-host "$(echo "$mirror" | sed 's|https://||;s|/.*||')" \
			2>&1 | tail -10; then
			upgrade_ok=true
			break
		fi
	done

	if [ "$upgrade_ok" = "false" ]; then
		log_warn "Mirror install failed, trying default PyPI..."
		"$PYTHON_BIN" -m pip install --upgrade hermes-agent 2>&1 | tail -10 || true
		[ -x "$HERMES_BIN" ] && upgrade_ok=true
	fi

	if [ "$upgrade_ok" = "true" ] && [ -x "$HERMES_BIN" ]; then
		log_ok "Hermes upgraded: $("$HERMES_BIN" --version 2>/dev/null | head -1)"
	else
		log_err "Upgrade failed"
		exit 1
	fi
}

# ── Command: uninstall ─────────────────────────────────────────────────────
cmd_uninstall() {
	log_step "Uninstalling Hermes Agent"

	/etc/init.d/hermes stop 2>/dev/null || true
	/etc/init.d/hermes disable 2>/dev/null || true
	uci set hermes.main.enabled=0 2>/dev/null || true
	uci commit hermes 2>/dev/null || true

	[ -d "$HERMES_BASE" ] && { rm -rf "$HERMES_BASE" 2>/dev/null || true; }
	[ -d "/root/.hermes" ] && { rm -rf "/root/.hermes" 2>/dev/null || true; }

	log_ok "Hermes Agent uninstalled"
}

# ── Main entry ─────────────────────────────────────────────────────────────
case "${1:-setup}" in
	setup)   cmd_setup ;;
	check)   cmd_check ;;
	upgrade) cmd_upgrade ;;
	uninstall) cmd_uninstall ;;
	*)
		echo "Usage: hermes-env {setup|check|upgrade|uninstall}"
		echo ""
		echo "  setup     Install Python + Hermes Agent (default)"
		echo "  check     Check installation status"
		echo "  upgrade   Upgrade Hermes Agent to latest version"
		echo "  uninstall Remove all Hermes files"
		exit 1
		;;
esac
