#!/bin/bash
# Copyright (C) 2026 Stefy Lanza <stefy@nexlab.net>
# SPDX-License-Identifier: GPL-3.0-or-later
# Copyleft: this program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
# Hermes Node Protocol
# Copyright (c) 2026 Stefy (nextime) Lanza <stefy@nexlab.net>
# All rights reserved.
# 
# This software is released under the MIT License with a copyleft clause.
# See the LICENSE file for full terms.
# Hermes Node Agent Installer — Linux Version
# Installs the Hermes Node Agent as a SysV init service
# Requires: bash, Python 3, pip, root (for service)

set -e

echo "=== Hermes Node Agent Installer (Linux) ==="
echo ""

# Check if running as root (for service setup)
if [ "$EUID" -eq 0 ]; then 
    RUN_AS_ROOT=true
else
    RUN_AS_ROOT=false
    echo "⚠️  Not running as root — skipping service installation."
    echo "   To install as a service, run: sudo $0"
    echo ""
fi

# Check for Python 3
if ! command -v python3 &> /dev/null; then
    echo "❌ ERROR: Python 3 is required but not found."
    exit 1
fi
echo "✓ Python: $(python3 --version)"

# Check for pip
if ! command -v pip3 &> /dev/null; then
    echo "❌ ERROR: pip3 is required but not found."
    if [ "$RUN_AS_ROOT" = true ]; then
        echo "   Install with: apt install python3-pip"
    else
        echo "   Install with: pip install --user websockets"
    fi
    exit 1
fi

# Install websockets library only if missing
# On modern Debian/Ubuntu with PEP 668, system pip may be externally managed.
echo "[1/5] Installing Python dependencies..."
if python3 -c "import websockets" 2>/dev/null; then
    echo "✓ websockets library already installed"
else
    PIP_OK=false
    if command -v pip3 >/dev/null 2>&1; then
        if pip3 install --quiet --user websockets 2>/dev/null; then
            PIP_OK=true
        fi
    fi
    if [ "$PIP_OK" != true ] && command -v pip >/dev/null 2>&1; then
        if pip install --quiet --user websockets 2>/dev/null; then
            PIP_OK=true
        fi
    fi
    if [ "$PIP_OK" != true ]; then
        echo "❌ Failed to install websockets in user site-packages."
        echo "   Try one of:"
        echo "   - apt install python3-websockets"
        echo "   - python3 -m venv ~/hermes-node-venv && ~/hermes-node-venv/bin/pip install websockets"
        exit 1
    fi
    echo "✓ websockets library installed"
fi

# Determine install locations
if [ "$RUN_AS_ROOT" = true ]; then
    AGENT_DIR="/usr/local/bin"
    CONFIG_DIR="/etc/hermes-node"
    SERVICE_FILE="$(pwd)/node-agent/hermes-node-agent.init.d"
else
    AGENT_DIR="$HOME/.local/bin"
    CONFIG_DIR="$HOME/.config/hermes-node"
    SERVICE_FILE=""
fi

mkdir -p "$AGENT_DIR"
mkdir -p "$CONFIG_DIR"

# Copy agent script
echo "[2/5] Installing agent script..."
cp "$(pwd)/node-agent/hermes_node_agent.py" "$AGENT_DIR/hermes-node-agent"
chmod +x "$AGENT_DIR/hermes-node-agent"
echo "✓ Installed: $AGENT_DIR/hermes-node-agent"

# Create or update config interactively, using existing values as defaults
echo "[3/5] Configuring node..."
EXISTING_GATEWAY_URL="wss://YOUR-GATEWAY-HOST:8765"
EXISTING_NODE_NAME="$(hostname)"
EXISTING_TOKEN="$(python3 -c "import secrets; print(secrets.token_hex(16))")"
EXISTING_ENABLE_BROWSER="false"
EXISTING_ENABLE_COMPUTER_CONTROL="false"
EXISTING_ENABLE_DESKTOP_OBSERVE="false"
EXISTING_ENABLE_AUDIO_CONTROL="false"

if [ -f "$CONFIG_DIR/config.json" ]; then
    EXISTING_GATEWAY_URL=$(python3 - <<PY
import json
from pathlib import Path
p = Path(r'''$CONFIG_DIR/config.json''')
data = json.loads(p.read_text())
print(data.get('gateway_url', 'wss://YOUR-GATEWAY-HOST:8765'))
PY
)
    EXISTING_NODE_NAME=$(python3 - <<PY
import json
from pathlib import Path
p = Path(r'''$CONFIG_DIR/config.json''')
data = json.loads(p.read_text())
print(data.get('node_name', '$(hostname)'))
PY
)
    EXISTING_TOKEN=$(python3 - <<PY
import json
from pathlib import Path
p = Path(r'''$CONFIG_DIR/config.json''')
data = json.loads(p.read_text())
print(data.get('token', ''))
PY
)
    EXISTING_ENABLE_BROWSER=$(python3 - <<PY
import json
from pathlib import Path
p = Path(r'''$CONFIG_DIR/config.json''')
data = json.loads(p.read_text())
print(str(bool(data.get('enable_browser', False))).lower())
PY
)
    EXISTING_ENABLE_COMPUTER_CONTROL=$(python3 - <<PY
import json
from pathlib import Path
p = Path(r'''$CONFIG_DIR/config.json''')
data = json.loads(p.read_text())
print(str(bool(data.get('enable_computer_control', False))).lower())
PY
)
    EXISTING_ENABLE_DESKTOP_OBSERVE=$(python3 - <<PY
import json
from pathlib import Path
p = Path(r'''$CONFIG_DIR/config.json''')
data = json.loads(p.read_text())
print(str(bool(data.get('enable_desktop_observe', False))).lower())
PY
)
    EXISTING_ENABLE_AUDIO_CONTROL=$(python3 - <<PY
import json
from pathlib import Path
p = Path(r'''$CONFIG_DIR/config.json''')
data = json.loads(p.read_text())
print(str(bool(data.get('enable_audio_control', False))).lower())
PY
)
    EXISTING_ENABLE_CAMERA_CONTROL=$(python3 - <<PY
import json
from pathlib import Path
p = Path(r'''$CONFIG_DIR/config.json''')
data = json.loads(p.read_text())
print(str(bool(data.get('enable_camera_control', False))).lower())
PY
)
    echo "   Existing config found: $CONFIG_DIR/config.json"
fi

read -r -p "Gateway URL [$EXISTING_GATEWAY_URL]: " GATEWAY_URL
GATEWAY_URL=${GATEWAY_URL:-$EXISTING_GATEWAY_URL}

read -r -p "Node name [$EXISTING_NODE_NAME]: " NODE_NAME
NODE_NAME=${NODE_NAME:-$EXISTING_NODE_NAME}

read -r -p "Token [$EXISTING_TOKEN]: " TOKEN
TOKEN=${TOKEN:-$EXISTING_TOKEN}

DEFAULT_BROWSER_CHOICE="n"
[ "$EXISTING_ENABLE_BROWSER" = "true" ] && DEFAULT_BROWSER_CHOICE="y"
read -r -p "Enable browser_control? (y/N) [$DEFAULT_BROWSER_CHOICE]: " ENABLE_BROWSER_INPUT
ENABLE_BROWSER_INPUT=${ENABLE_BROWSER_INPUT:-$DEFAULT_BROWSER_CHOICE}
case "$ENABLE_BROWSER_INPUT" in
  y|Y|yes|YES) ENABLE_BROWSER=true ;;
  *) ENABLE_BROWSER=false ;;
esac

DEFAULT_COMPUTER_CHOICE="n"
[ "$EXISTING_ENABLE_COMPUTER_CONTROL" = "true" ] && DEFAULT_COMPUTER_CHOICE="y"
read -r -p "Enable computer_control? (y/N) [$DEFAULT_COMPUTER_CHOICE]: " ENABLE_COMPUTER_INPUT
ENABLE_COMPUTER_INPUT=${ENABLE_COMPUTER_INPUT:-$DEFAULT_COMPUTER_CHOICE}
case "$ENABLE_COMPUTER_INPUT" in
  y|Y|yes|YES) ENABLE_COMPUTER_CONTROL=true ;;
  *) ENABLE_COMPUTER_CONTROL=false ;;
esac

DEFAULT_DESKTOP_CHOICE="n"
[ "$EXISTING_ENABLE_DESKTOP_OBSERVE" = "true" ] && DEFAULT_DESKTOP_CHOICE="y"
read -r -p "Enable desktop_observe? (y/N) [$DEFAULT_DESKTOP_CHOICE]: " ENABLE_DESKTOP_INPUT
ENABLE_DESKTOP_INPUT=${ENABLE_DESKTOP_INPUT:-$DEFAULT_DESKTOP_CHOICE}
case "$ENABLE_DESKTOP_INPUT" in
  y|Y|yes|YES) ENABLE_DESKTOP_OBSERVE=true ;;
  *) ENABLE_DESKTOP_OBSERVE=false ;;
esac

DEFAULT_AUDIO_CHOICE="n"
[ "$EXISTING_ENABLE_AUDIO_CONTROL" = "true" ] && DEFAULT_AUDIO_CHOICE="y"
read -r -p "Enable audio_control? (y/N) [$DEFAULT_AUDIO_CHOICE]: " ENABLE_AUDIO_INPUT
ENABLE_AUDIO_INPUT=${ENABLE_AUDIO_INPUT:-$DEFAULT_AUDIO_CHOICE}
case "$ENABLE_AUDIO_INPUT" in
  y|Y|yes|YES) ENABLE_AUDIO_CONTROL=true ;;
  *) ENABLE_AUDIO_CONTROL=false ;;
esac

DEFAULT_CAMERA_CHOICE="n"
[ "$EXISTING_ENABLE_CAMERA_CONTROL" = "true" ] && DEFAULT_CAMERA_CHOICE="y"
read -r -p "Enable camera_control? (y/N) [$DEFAULT_CAMERA_CHOICE]: " ENABLE_CAMERA_INPUT
ENABLE_CAMERA_INPUT=${ENABLE_CAMERA_INPUT:-$DEFAULT_CAMERA_CHOICE}
case "$ENABLE_CAMERA_INPUT" in
  y|Y|yes|YES) ENABLE_CAMERA_CONTROL=true ;;
  *) ENABLE_CAMERA_CONTROL=false ;;
esac

CAPABILITIES='["exec"]'
if [ "$ENABLE_BROWSER" = true ]; then
    CAPABILITIES=$(python3 - <<'PY' "$CAPABILITIES"
import json, sys
caps = json.loads(sys.argv[1])
if 'browser_control' not in caps:
    caps.append('browser_control')
print(json.dumps(caps))
PY
)
fi
if [ "$ENABLE_COMPUTER_CONTROL" = true ]; then
    CAPABILITIES=$(python3 - <<'PY' "$CAPABILITIES"
import json, sys
caps = json.loads(sys.argv[1])
if 'computer_control' not in caps:
    caps.append('computer_control')
print(json.dumps(caps))
PY
)
fi
if [ "$ENABLE_DESKTOP_OBSERVE" = true ]; then
    CAPABILITIES=$(python3 - <<'PY' "$CAPABILITIES"
import json, sys
caps = json.loads(sys.argv[1])
if 'desktop_observe' not in caps:
    caps.append('desktop_observe')
print(json.dumps(caps))
PY
)
fi
if [ "$ENABLE_AUDIO_CONTROL" = true ]; then
    CAPABILITIES=$(python3 - <<'PY' "$CAPABILITIES"
import json, sys
caps = json.loads(sys.argv[1])
if 'audio_control' not in caps:
    caps.append('audio_control')
print(json.dumps(caps))
PY
)
fi
if [ "$ENABLE_CAMERA_CONTROL" = true ]; then
    CAPABILITIES=$(python3 - <<'PY' "$CAPABILITIES"
import json, sys
caps = json.loads(sys.argv[1])
if 'camera_control' not in caps:
    caps.append('camera_control')
print(json.dumps(caps))
PY
)
fi

cat > "$CONFIG_DIR/config.json" << EOF
{
  "gateway_url": "$GATEWAY_URL",
  "node_name": "$NODE_NAME",
  "token": "$TOKEN",
  "reconnect_interval": 5,
  "heartbeat_interval": 30,
  "capabilities": $CAPABILITIES,
  "enable_browser": $ENABLE_BROWSER,
  "enable_computer_control": $ENABLE_COMPUTER_CONTROL,
  "enable_desktop_observe": $ENABLE_DESKTOP_OBSERVE,
  "enable_audio_control": $ENABLE_AUDIO_CONTROL,
  "enable_camera_control": $ENABLE_CAMERA_CONTROL,
  "permissions": {
    "deny": ["sudo", "su", "doas", "dd if=", "mkfs", "fdisk", "wipe"],
    "ask": [
      "rm -rf",
      "dd if=",
      "> /dev/",
      "chmod",
      "chown",
      "mv /",
      ":/usr/",
      ":/etc/",
      ":/bin/",
      ":/sbin/",
      "> ~/.config/hermes-node/",
      ">> ~/.config/hermes-node/",
      "tee ~/.config/hermes-node/",
      "cp ~/.config/hermes-node/",
      "mv ~/.config/hermes-node/",
      "sed -i ~/.config/hermes-node/",
      "> ~/.local/bin/",
      ">> ~/.local/bin/",
      "tee ~/.local/bin/",
      "cp ~/.local/bin/",
      "mv ~/.local/bin/",
      "chmod ~/.local/bin/",
      "sed -i ~/.local/bin/"
    ],
    "allow": []
  }
}
EOF

echo "[4/5] Wrote config: $CONFIG_DIR/config.json"

# Install SysV init service (root only)
if [ "$RUN_AS_ROOT" = true ] && [ -f "$SERVICE_FILE" ]; then
    echo "[5/5] Installing SysV init service..."
    cp "$SERVICE_FILE" /etc/init.d/hermes-node-agent
    chmod +x /etc/init.d/hermes-node-agent
    update-rc.d hermes-node-agent defaults 2>/dev/null || true
    echo "✓ Service: /etc/init.d/hermes-node-agent"
    echo ""
    echo "Service commands:"
    echo "  /etc/init.d/hermes-node-agent start|stop|restart|status"
else
    echo "[5/5] Skipping service installation (not root)"
    echo ""
fi

echo "=== Installation Complete ==="
echo ""
echo "Next steps:"
echo "  1. Edit config:  $CONFIG_DIR/config.json"
echo "  2. Start agent: $AGENT_DIR/hermes-node-agent --config $CONFIG_DIR/config.json"
echo "  3. Verify logs live: $AGENT_DIR/hermes-node-agent --config $CONFIG_DIR/config.json"
echo "     (or with debug: $AGENT_DIR/hermes-node-agent --debug --config $CONFIG_DIR/config.json)"
echo ""
echo "For Windows nodes, see WINDOWS_INSTALL.md"
echo "For full deployment guide, see DEPLOYMENT.md"
