#!/bin/bash
# ==========================================
# AEA SERVER MODULE: STANDALONE AGENT
# VERSION: 1.12 (Offline APT dependencies)
# ==========================================
AEA_VERSION="1.12"
MODULE_DATE="2026-04-27"

# 1. Возврат версии для проверки обновлений в Android
if [ "$1" == "--version" ] || [ "$1" == "-v" ]; then
    echo "$AEA_VERSION"
    exit 0
fi

echo "[AEA] Configuring telemetry agent (v$AEA_VERSION)..."

# 2. Подготовка рабочей директории
AGENT_DIR="/opt/aea_standalone_agent"
mkdir -p "$AGENT_DIR"
cd "$AGENT_DIR"

# 3. Настройка системного окружения (APT вместо PIP для автономности)
echo "[AEA] Setting up system environment..."
export DEBIAN_FRONTEND=noninteractive
apt-get update -yq >/dev/null 2>&1
apt-get install -yq python3-psutil >/dev/null 2>&1

# ==========================================
# 4. СОЗДАНИЕ НОЧНОГО МОДУЛЯ (Тяжелые задачи)
# ==========================================
echo "[AEA] Creating heavy background tasks module..."
cat << 'EOF' > "$AGENT_DIR/heavy_tasks.py"
import subprocess
import json
import os

CACHE_FILE = "/opt/aea_standalone_agent/heavy_cache.json"

heavy_data = {
    "updates_available": 0,
    "updates_status": {"packages_to_update": 0, "security_updates": 0, "reboot_required": False},
    "heavy_tests": {"speedtest": None}
}

# 1. Тяжелый тест сети (Speedtest)
try:
    proc = subprocess.run(["speedtest-cli", "--secure", "--json"], capture_output=True, text=True)
    if proc.returncode == 0:
        data = json.loads(proc.stdout)
        heavy_data["heavy_tests"]["speedtest"] = {
            "ping_ms": round(data.get("ping", 0), 1),
            "download_mbps": round(data.get("download", 0) / 1_000_000, 1),
            "upload_mbps": round(data.get("upload", 0) / 1_000_000, 1),
            "error": None
        }
    else:
        heavy_data["heavy_tests"]["speedtest"] = {"ping_ms": 0, "download_mbps": 0, "upload_mbps": 0, "error": "Error: " + proc.stderr[:50]}
except Exception as e:
    heavy_data["heavy_tests"]["speedtest"] = {"ping_ms": 0, "download_mbps": 0, "upload_mbps": 0, "error": str(e)}

# 2. Обновления пакетов ОС
try:
    apt_out = subprocess.getoutput("/usr/lib/update-notifier/apt-check 2>/dev/null")
    if ";" in apt_out:
        parts = apt_out.split(';')
        heavy_data["updates_available"] = int(parts[0])
        heavy_data["updates_status"]["packages_to_update"] = int(parts[0])
        heavy_data["updates_status"]["security_updates"] = int(parts[1])
    heavy_data["updates_status"]["reboot_required"] = os.path.exists("/var/run/reboot-required")
except: pass

# Сохраняем в кэш-файл
with open(CACHE_FILE, "w") as f:
    json.dump(heavy_data, f)
EOF

# ==========================================
# 5. СОЗДАНИЕ БЫСТРОГО МОДУЛЯ (Ответ для Android)
# ==========================================
echo "[AEA] Creating fast telemetry collection module..."
cat << 'EOF' > "$AGENT_DIR/get_metrics.py"
import psutil
import subprocess
import json
import socket
import time
import re
import os

BOOT_TIME = psutil.boot_time()
CACHE_FILE = "/opt/aea_standalone_agent/heavy_cache.json"

def get_metrics():
    # Базовая структура как у Мастера
    state = {
        "module_info": {"name": "AEA Standalone Agent", "version": "1.12", "date": "2026-04-27", "desc": "Offline APT dependencies"},
        "id": socket.gethostname(),
        "status": "online",
        "uptime_hours": round((time.time() - BOOT_TIME) / 3600, 1),
        "os_version": "",
        "updates_available": 0,
        "location": {"country": "", "city": "", "flag": ""},
        "hardware": {"cpu": {}, "ram": {}},
        "disk": [],
        "network": {"max_speed_mbps": 1000, "traffic_stats": {}},
        "security": {"firewall_active": False, "failed_logins_today": 0, "active_connections": 0, "active_ssh_users": [], "open_ports": []},
        "gpus": [],
        "updates_status": {"packages_to_update": 0, "security_updates": 0, "reboot_required": False},
        "deep_metrics": {"rdp_users": [], "load_average": [], "cpu_temp_c": 0.0, "disks_health": []},
        "heavy_tests": {"speedtest": None},
        "extras": {}
    }

    # Подгружаем тяжелые данные из ночного кэша
    if os.path.exists(CACHE_FILE):
        try:
            with open(CACHE_FILE, "r") as f:
                heavy_data = json.load(f)
                state["updates_available"] = heavy_data.get("updates_available", 0)
                state["updates_status"] = heavy_data.get("updates_status", state["updates_status"])
                state["heavy_tests"] = heavy_data.get("heavy_tests", state["heavy_tests"])
        except: pass

    # ОС
    os_name = subprocess.getoutput("cat /etc/os-release 2>/dev/null | grep PRETTY_NAME | cut -d'\"' -f2").strip()
    if not os_name: os_name = subprocess.getoutput("uname -srm").strip()
    state["os_version"] = os_name

    # CPU и RAM
    state["hardware"]["cpu"] = {"load_percent": psutil.cpu_percent(interval=0.1), "cores": psutil.cpu_count(logical=True)}
    ram = psutil.virtual_memory()
    state["hardware"]["ram"] = {"used_gb": round(ram.used / (1024**3), 2), "total_gb": round(ram.total / (1024**3), 2), "percent": ram.percent}

    # ДИСКИ (Мгновенное чтение S.M.A.R.T.)
    physical_disks = {}
    for part in psutil.disk_partitions(all=False):
        if part.fstype in ('ext4', 'ext3', 'xfs', 'btrfs', 'vfat', 'ntfs'):
            try:
                usage = psutil.disk_usage(part.mountpoint)
                dev_name = part.device.split('/')[-1]
                label = subprocess.getoutput(f"lsblk -n -o LABEL {part.device} 2>/dev/null").strip()
                mnt_str = part.mountpoint
                if label: mnt_str = f"{mnt_str} [{label}]"

                if 'nvme' in dev_name: base_dev = re.sub(r'p\d+$', '', dev_name)
                else: base_dev = re.sub(r'\d+$', '', dev_name)

                if base_dev not in physical_disks: physical_disks[base_dev] = []
                physical_disks[base_dev].append({
                    "name": dev_name, "mountpoint": mnt_str,
                    "used_gb": round(usage.used / (1024**3), 2),
                    "total_gb": round(usage.total / (1024**3), 2), "percent": round(usage.percent, 1)
                })
            except: continue

    final_disk_list = []
    for base_dev, partitions in physical_disks.items():
        smart_json = subprocess.getoutput(f"sudo smartctl -j -a /dev/{base_dev} 2>/dev/null")
        model, passed, temp, hours = "Unknown", True, 0, 0
        try:
            sj = json.loads(smart_json)
            passed = sj.get("smart_status", {}).get("passed", True)
            model = sj.get("model_name", sj.get("model_family", "Unknown"))
            hours = sj.get("power_on_time", {}).get("hours", 0)
            temp = sj.get("temperature", {}).get("current", 0)
        except: pass

        if model == "Unknown" or not model:
            model = subprocess.getoutput(f"lsblk -d -n -o MODEL /dev/{base_dev} 2>/dev/null").strip() or "Virtual Drive"

        is_virtual = "virtual" in model.lower() or "qemu" in model.lower() or (hours == 0 and temp == 0)
        final_disk_list.append({
            "device": base_dev, "model": model, "smart_status": "PASSED" if passed else "FAILED",
            "power_on_hours": hours, "temp_c": temp, "is_virtual": is_virtual, "partitions": partitions
        })
    state["disk"] = final_disk_list

    # СЕТЬ (vnstat)
    try:
        iface_out = subprocess.getoutput("ip route show default | awk '/default/ {print $5}'")
        iface = iface_out.split('\n')[0].strip() if iface_out else "ens3"
        vnstat_out = subprocess.getoutput(f"vnstat -i {iface} --json 2>/dev/null")
        data = json.loads(vnstat_out)
        traffic = data.get("interfaces", [{}])[0].get("traffic", {})
        d = traffic.get("day", [{}])[-1] if traffic.get("day") else {"rx":0, "tx":0}
        m = traffic.get("month", [{}])[-1] if traffic.get("month") else {"rx":0, "tx":0}
        state["network"]["traffic_stats"] = {
            "today_rx_gb": round(d.get("rx", 0) / (1024**3), 2), "today_tx_gb": round(d.get("tx", 0) / (1024**3), 2),
            "month_rx_gb": round(m.get("rx", 0) / (1024**3), 2), "month_tx_gb": round(m.get("tx", 0) / (1024**3), 2)
        }
    except: pass

    # БЕЗОПАСНОСТЬ
    active_ssh, active_rdp, open_ports = set(), set(), set()
    for conn in psutil.net_connections(kind='inet'):
        if conn.status == 'ESTABLISHED' and conn.raddr:
            if conn.laddr.port in (22, 44815): active_ssh.add(conn.raddr.ip)
            elif conn.laddr.port == 3389: active_rdp.add(conn.raddr.ip)
        elif conn.status == 'LISTEN':
            open_ports.add(conn.laddr.port)

    state["security"]["open_ports"] = sorted(list(open_ports))
    state["security"]["active_ssh_users"] = list(active_ssh)
    state["deep_metrics"]["rdp_users"] = list(active_rdp)
    state["security"]["active_connections"] = int(subprocess.getoutput('ss -Htu state established | wc -l 2>/dev/null') or 0)
    state["security"]["failed_logins_today"] = int(subprocess.getoutput('journalctl -u ssh --since today | grep -E "Failed password|Invalid user" | wc -l 2>/dev/null') or 0)
    state["security"]["firewall_active"] = "Status: active" in subprocess.getoutput('sudo ufw status 2>/dev/null')

    # GPU
    try:
        import pynvml
        pynvml.nvmlInit()
        gpu_count = pynvml.nvmlDeviceGetCount()
        gpus = []
        for i in range(gpu_count):
            handle = pynvml.nvmlDeviceGetHandleByIndex(i)
            name = pynvml.nvmlDeviceGetName(handle)
            if isinstance(name, bytes): name = name.decode('utf-8')
            util = pynvml.nvmlDeviceGetUtilizationRates(handle)
            mem = pynvml.nvmlDeviceGetMemoryInfo(handle)
            temp = pynvml.nvmlDeviceGetTemperature(handle, pynvml.NVML_TEMPERATURE_GPU)
            gpus.append({
                "model": name, "temp_c": temp, "load_percent": util.gpu,
                "vram": {"used_gb": round(mem.used / (1024**3), 2), "total_gb": round(mem.total / (1024**3), 2), "percent": round((mem.used / mem.total) * 100, 1)}
            })
        state["gpus"] = gpus
    except: pass

    try: state["deep_metrics"]["load_average"] = list(psutil.getloadavg())
    except: pass
    state["extras"]["Launched Processes"] = len(psutil.pids())

    print(json.dumps(state))

if __name__ == "__main__":
    get_metrics()
EOF

# ==========================================
# 6. НАСТРОЙКА CRON И СИСТЕМНОГО ЯРЛЫКА
# ==========================================
echo "[AEA] Configuring Cron schedule (03:00)..."
# Удаляем старые записи, чтобы не плодить дубликаты
crontab -l 2>/dev/null | grep -v 'heavy_tasks.py' | crontab -
# Прописываем запуск в 3 ночи, используем системный Python3
(crontab -l 2>/dev/null; echo "0 3 * * * /usr/bin/python3 /opt/aea_standalone_agent/heavy_tasks.py") | crontab -

echo "[AEA] Running first heavy test (creating primary cache)..."
/usr/bin/python3 /opt/aea_standalone_agent/heavy_tasks.py

# Создаем глобальную команду для Android
cat << 'EOF' > /usr/local/bin/aea_get_metrics
#!/bin/bash
/usr/bin/python3 /opt/aea_standalone_agent/get_metrics.py
EOF
chmod +x /usr/local/bin/aea_get_metrics

# Сохраняем копию шаблона, чтобы Android мог прочитать AEA_VERSION в будущем
cp "$0" /usr/local/bin/aea_standalone_agent_template.sh
chmod +x /usr/local/bin/aea_standalone_agent_template.sh

echo "[AEA] Agent successfully installed! Telemetry available via command: aea_get_metrics"
exit 0
