#!/data/data/com.termux/files/usr/bin/sh
# Cerberus installer for Termux.
#
#   curl -fsSL https://cerberus.lain.ch/install.sh | sh
#
# Root mode (su available): installs the daemon under /data/adb/cerberus, adds the
# Termux uid to the socket allow-list, starts the daemon and verifies that `cerberus
# status` answers. The user-visible config lives in ~/.config/cerberus so the TUI can
# read it without root; the binary itself is replaced by /update.
#
# Non-root mode: the same binary and daemon run as the Termux user with a reduced
# perimeter: no root shell, no package changes, workspace-only sandbox.
set -eu

BASE=${CERBERUS_UPDATE_URL:-https://cerberus.lain.ch}
PREFIX=${PREFIX:-}
HOME=${HOME:-}
CONFIG_DIR=$HOME/.config/cerberus
CONFIG=$CONFIG_DIR/config.json

die() { printf 'cerberus: %s\n' "$*" >&2; exit 1; }
say() { printf '%s\n' "$*"; }

[ -n "$PREFIX" ] && [ -d "$PREFIX" ] || die "run this inside Termux (PREFIX is not set)"
[ -n "$HOME" ] && [ -d "$HOME" ] || die "HOME is not set"
command -v curl >/dev/null 2>&1 || die "curl is required: pkg install curl"

case $(uname -m) in
aarch64 | arm64) ARCH=arm64 ;;
x86_64 | amd64) ARCH=amd64 ;;
*) die "unsupported architecture $(uname -m)" ;;
esac

# --- root detection ----------------------------------------------------------------------
ROOT_MODE=none
if [ "$(id -u)" = 0 ]; then
	ROOT_MODE=direct
elif command -v su >/dev/null 2>&1 && su -c id 2>/dev/null | grep -q 'uid=0'; then
	ROOT_MODE=su
fi

asroot() { # asroot <script>
	if [ "$ROOT_MODE" = su ]; then
		su -c "sh $1"
	else
		sh "$1"
	fi
}

UID_ME=$(id -u)
TMP=${TMPDIR:-$PREFIX/tmp}
mkdir -p "$TMP"
mkdir -p "$PREFIX/bin"
DL=$TMP/cerberus.$$
ROOT_SCRIPT=$TMP/cerberus-root.$$
cleanup() { rm -f "$DL" "$ROOT_SCRIPT"; }
trap cleanup EXIT INT TERM

# --- download and check ------------------------------------------------------------------
say "→ скачиваю cerberus ($ARCH) с $BASE"
curl -fL --retry 2 --connect-timeout 15 -o "$DL" "$BASE/download?arch=$ARCH" ||
	die "не удалось скачать бинарник с $BASE"
chmod 700 "$DL"
VERSION=$("$DL" version 2>/dev/null | awk '{print $2}')
[ -n "$VERSION" ] || die "скачанный файл не запускается: битый бинарник или чужая архитектура"
say "→ cerberus $VERSION"

mkdir -p "$CONFIG_DIR"

# The Termux wrapper is what the user runs. The real binary lives elsewhere in root mode
# and is the only file /update replaces.
write_wrapper() { # write_wrapper <target>
	cat >"$PREFIX/bin/cerberus" <<EOF
#!/data/data/com.termux/files/usr/bin/sh
# Cerberus launcher. The binary updates itself; this file never changes.
CERBERUS_CONFIG=\${CERBERUS_CONFIG:-$CONFIG}
export CERBERUS_CONFIG
exec "$1" "\$@"
EOF
	chmod 755 "$PREFIX/bin/cerberus"
}

if [ "$ROOT_MODE" != none ]; then
	# --- root mode -------------------------------------------------------------------
	say "→ root найден: ставлю демон в /data/adb/cerberus"
	CONF_DIR=""
	cat >"$ROOT_SCRIPT" <<EOF
#!/system/bin/sh
mkdir -p /storage/emulated/0/Documents/Cerberus/.conf
EOF
	if asroot "$ROOT_SCRIPT" 2>/dev/null; then CONF_DIR=/storage/emulated/0/Documents/Cerberus/.conf; fi
	rm -f "$ROOT_SCRIPT"

	cat >"$CONFIG" <<EOF
{
  "data_root": "/data/adb/cerberus",
  "conf_dir": "$CONF_DIR",
  "socket": "/dev/socket/cerberus.sock",
  "workspace": "/data/adb/cerberus/workspace",
  "provider": {"kind": "gemini", "temperature": 0.2},
  "max_steps": 24,
  "tool_timeout_sec": 120,
  "allow_root": true,
  "allowed_uids": [$UID_ME],
  "update_url": "$BASE"
}
EOF
	chmod 600 "$CONFIG"

	cat >"$ROOT_SCRIPT" <<EOF
#!/system/bin/sh
set -eu
DATA=/data/adb/cerberus
BIN=\$DATA/cerberus
CFG=$CONFIG
mkdir -p "\$DATA"
chmod 700 "\$DATA"
# The KSU/Magisk boot module reads this copy; the TUI uses the Termux-home one
# because /data/adb is root-only. Both describe the same daemon.
cp "\$CFG" "\$DATA/config.json"
chmod 600 "\$DATA/config.json"
cp "$DL" "\$BIN.new"
chmod 755 "\$BIN.new"
mv -f "\$BIN.new" "\$BIN"

# Stop the previous daemon so the new binary starts clean.
if [ -f "\$DATA/daemon.pid" ]; then
	pid=\$(cat "\$DATA/daemon.pid" 2>/dev/null || true)
	if [ -n "\$pid" ] && kill -0 "\$pid" 2>/dev/null; then
		kill "\$pid" 2>/dev/null || true
		i=0
		while kill -0 "\$pid" 2>/dev/null && [ "\$i" -lt 20 ]; do
			i=\$((i + 1))
			sleep 0.25
		done
		kill -9 "\$pid" 2>/dev/null || true
	fi
fi

cd "\$DATA"
nohup setsid "\$BIN" daemon -config "\$CFG" >>"\$DATA/daemon.log" 2>&1 &
EOF
	asroot "$ROOT_SCRIPT" || die "не удалось установить демон (нужен рабочий su)"
	rm -f "$ROOT_SCRIPT"
	write_wrapper /data/adb/cerberus/cerberus
	TARGET=/data/adb/cerberus/cerberus

	# Verify: the daemon must answer over the socket as the Termux uid.
	i=0
	OK=0
	while [ "$i" -lt 20 ]; do
		if "$TARGET" status -config "$CONFIG" >/dev/null 2>&1; then
			OK=1
			break
		fi
		i=$((i + 1))
		sleep 0.5
	done
	[ "$OK" = 1 ] || {
		say "── daemon.log ──"
		asroot_log=$TMP/cerberus-log.$$
		printf '#!/system/bin/sh\ntail -n 40 /data/adb/cerberus/daemon.log\n' >"$asroot_log"
		asroot "$asroot_log" || true
		rm -f "$asroot_log"
		die "демон не отвечает на $CONFIG"
	}

	# Termux:Boot hook, when the addon is installed.
	if [ -d "$HOME/.termux/boot" ]; then
		cat >"$HOME/.termux/boot/cerberus.sh" <<EOF
#!/data/data/com.termux/files/usr/bin/sh
su -c 'nohup setsid /data/adb/cerberus/cerberus daemon -config $CONFIG >>/data/adb/cerberus/daemon.log 2>&1 &'
EOF
		chmod 755 "$HOME/.termux/boot/cerberus.sh"
	fi

	say ""
	say "Cerberus $VERSION установлен (root)."
	say "  TUI:     cerberus"
	say "  статус:  cerberus status"
	say "  конфиг:  $CONFIG"
	[ -n "$CONF_DIR" ] && say "  зеркало: $CONF_DIR (ключи и модели — в .env)"
	say "  модели:  /model      каталог: /skills /mcp      обновление: /update"
	exit 0
fi

# --- non-root mode -----------------------------------------------------------------------
say "→ root недоступен: ставлю в Termux home (сокращённый режим)"
DATA_ROOT=$HOME/.cerberus
CONF_DIR=""
if mkdir -p "$HOME/storage/shared/Documents/Cerberus/.conf" 2>/dev/null; then
	CONF_DIR=$HOME/storage/shared/Documents/Cerberus/.conf
fi
mkdir -p "$DATA_ROOT"

cat >"$CONFIG" <<EOF
{
  "data_root": "$DATA_ROOT",
  "conf_dir": "$CONF_DIR",
  "socket": "$DATA_ROOT/cerberus.sock",
  "workspace": "$HOME/cerberus-workspace",
  "provider": {"kind": "gemini", "temperature": 0.2},
  "max_steps": 24,
  "tool_timeout_sec": 120,
  "allow_root": false,
  "allowed_uids": [$UID_ME],
  "update_url": "$BASE"
}
EOF
chmod 600 "$CONFIG"

mkdir -p "$PREFIX/bin"
cp "$DL" "$PREFIX/bin/cerberus.new"
chmod 755 "$PREFIX/bin/cerberus.new"
mv -f "$PREFIX/bin/cerberus.new" "$PREFIX/bin/cerberus"

if [ -f "$DATA_ROOT/daemon.pid" ]; then
	pid=$(cat "$DATA_ROOT/daemon.pid" 2>/dev/null || true)
	if [ -n "$pid" ] && kill -0 "$pid" 2>/dev/null; then
		kill "$pid" 2>/dev/null || true
		sleep 1
		kill -9 "$pid" 2>/dev/null || true
	fi
fi
nohup setsid "$PREFIX/bin/cerberus" daemon -config "$CONFIG" >>"$DATA_ROOT/daemon.log" 2>&1 &

i=0
OK=0
while [ "$i" -lt 20 ]; do
	if "$PREFIX/bin/cerberus" status -config "$CONFIG" >/dev/null 2>&1; then
		OK=1
		break
	fi
	i=$((i + 1))
	sleep 0.5
done
if [ "$OK" != 1 ]; then
	say "── daemon.log ──"
	tail -n 40 "$DATA_ROOT/daemon.log" 2>/dev/null || true
	die "демон не отвечает на $CONFIG"
fi

if [ -d "$HOME/.termux/boot" ]; then
	cat >"$HOME/.termux/boot/cerberus.sh" <<EOF
#!/data/data/com.termux/files/usr/bin/sh
nohup setsid "$PREFIX/bin/cerberus" daemon -config "$CONFIG" >>"$DATA_ROOT/daemon.log" 2>&1 &
EOF
	chmod 755 "$HOME/.termux/boot/cerberus.sh"
fi

say ""
say "Cerberus $VERSION установлен (без root, сокращённый режим)."
say "  TUI:     cerberus"
say "  статус:  cerberus status"
say "  конфиг:  $CONFIG"
[ -n "$CONF_DIR" ] && say "  зеркало: $CONF_DIR"
say ""
say "Без root недоступны: системный shell от root, pm/settings/logcat,"
say "изменение системных файлов. Песочница и workspace работают."
say "Для полного режима: установите KernelSU/Magisk и запустите установщик снова."
