"""VPS metrics via SSH for admin monitor.

Connects to the Obol VPS and fetches system stats.
Requires SSH key auth to be configured.
"""
import os
import subprocess


# VPS connection details
VPS_HOST = os.environ.get("OBOL_VPS_HOST", "46.224.205.31")
VPS_USER = os.environ.get("OBOL_VPS_USER", "gor")
SSH_TIMEOUT = 10

# Whitelist of valid service names (prevents command injection via service parameter)
VALID_SERVICES = frozenset({
    "obol-blue", "obol-green", "nginx", "postgresql", "cloudflared",
    "obol-monitor-health", "obol-monitor-crawl", "obol-monitor-signup",
    "obol-monitor-silence",
})


def _run_ssh_command(cmd: str) -> str | None:
    """Run a command on VPS via SSH. Returns stdout or None on error."""
    try:
        result = subprocess.run(
            [
                "ssh",
                "-o", "BatchMode=yes",
                "-o", "ConnectTimeout=5",
                "-o", "StrictHostKeyChecking=accept-new",
                f"{VPS_USER}@{VPS_HOST}",
                cmd,
            ],
            capture_output=True,
            text=True,
            timeout=SSH_TIMEOUT,
        )
        if result.returncode == 0:
            return result.stdout.strip()
        return None
    except Exception:
        return None


def fetch_vps_stats() -> dict | None:
    """Fetch VPS stats in a single SSH call.

    Returns dict with:
    - cpu_pct: CPU usage percentage
    - load_1m: 1-minute load average
    - mem_pct: Memory usage percentage
    - mem_used_gb: Used memory in GB
    - mem_total_gb: Total memory in GB
    - disk_pct: Disk usage percentage
    - disk_used_gb: Used disk in GB
    - disk_total_gb: Total disk in GB
    - db_connections: PostgreSQL active connections
    - db_max_connections: PostgreSQL max connections
    """
    # Single SSH call with multiple commands, each on its own line with markers
    cmd = """
echo "LOAD:$(cat /proc/loadavg | awk '{print $1}')"
echo "CPU:$(top -bn1 | grep 'Cpu(s)' | awk '{print $2}' | tr -d '%us,')"
echo "MEM:$(free -b | awk '/Mem:/ {printf \"%.2f %.2f\", $3/1073741824, $2/1073741824}')"
echo "DISK:$(df -BG / | awk 'NR==2 {gsub(/G/,\"\"); printf \"%s %s\", $3, $2}')"
echo "DBCONN:$(sudo -u postgres psql -t -c "SELECT count(*) FROM pg_stat_activity" 2>/dev/null | tr -d ' ' || echo 0)"
echo "DBMAX:$(sudo -u postgres psql -t -c "SHOW max_connections" 2>/dev/null | tr -d ' ' || echo 100)"
""".strip()

    output = _run_ssh_command(cmd)
    if not output:
        return None

    # Parse labeled output
    data = {}
    for line in output.strip().split("\n"):
        if ":" in line:
            key, val = line.split(":", 1)
            data[key.strip()] = val.strip()

    try:
        # Load average
        load_1m = float(data.get("LOAD", "0"))

        # CPU
        cpu_str = data.get("CPU", "0")
        # Handle various formats
        cpu_pct = float(cpu_str.replace(",", ".").split()[0]) if cpu_str else 0

        # Memory
        mem_parts = data.get("MEM", "0 1").split()
        mem_used_gb = float(mem_parts[0])
        mem_total_gb = float(mem_parts[1]) if len(mem_parts) > 1 else 1
        mem_pct = (mem_used_gb / mem_total_gb * 100) if mem_total_gb > 0 else 0

        # Disk
        disk_parts = data.get("DISK", "0 1").split()
        disk_used_gb = float(disk_parts[0])
        disk_total_gb = float(disk_parts[1]) if len(disk_parts) > 1 else 1
        disk_pct = (disk_used_gb / disk_total_gb * 100) if disk_total_gb > 0 else 0

        # DB connections
        db_connections = int(data.get("DBCONN", "0") or "0")
        db_max_connections = int(data.get("DBMAX", "100") or "100")

        return {
            "cpu_pct": cpu_pct,
            "load_1m": load_1m,
            "mem_pct": mem_pct,
            "mem_used_gb": mem_used_gb,
            "mem_total_gb": mem_total_gb,
            "disk_pct": disk_pct,
            "disk_used_gb": disk_used_gb,
            "disk_total_gb": disk_total_gb,
            "db_connections": db_connections,
            "db_max_connections": db_max_connections,
        }
    except (ValueError, IndexError, KeyError) as e:
        return None


def check_service_status(service: str) -> tuple[bool, str]:
    """Check if a systemd service is running.

    Returns (is_running, status_text).
    """
    if service not in VALID_SERVICES:
        return False, "invalid service"
    output = _run_ssh_command(f"systemctl is-active {service}")
    if output is None:
        return False, "unknown"
    is_running = output.strip() == "active"
    return is_running, output.strip()


def get_recent_logs(service: str, lines: int = 10) -> list[str]:
    """Get recent journalctl logs for a service."""
    if service not in VALID_SERVICES:
        return ["Error: invalid service name"]
    lines = max(1, min(lines, 100))  # Bound line count
    output = _run_ssh_command(
        f"sudo journalctl -u {service} -n {lines} --no-pager -o short-iso"
    )
    if output is None:
        return []
    return output.strip().split("\n")


if __name__ == "__main__":
    # Quick test
    import json
    stats = fetch_vps_stats()
    if stats:
        print(json.dumps(stats, indent=2))
    else:
        print("Failed to fetch VPS stats")
