import os
from time import sleep
from neurotron.logbus import logbus


class Perception:
    """
    Sensores internos via /proc:
      - CPU % por delta de /proc/stat
      - Memória % via /proc/meminfo
      - Carga média /proc/loadavg ou os.getloadavg()
    Totalmente silencioso (sem prints).
    """

    # ----------------------------------------------------------------------
    # CPU
    # ----------------------------------------------------------------------

    def _read_proc_stat(self):
        """Lê a linha 'cpu ' de /proc/stat. Retorna dict ou None."""
        try:
            with open("/proc/stat", "r") as f:
                line = f.readline()
            if not line.startswith("cpu "):
                return None

            parts = line.strip().split()[1:]
            vals = list(map(int, parts[:10]))
            return {
                "user": vals[0], "nice": vals[1], "system": vals[2], "idle": vals[3],
                "iowait": vals[4], "irq": vals[5], "softirq": vals[6], "steal": vals[7],
                "guest": vals[8], "guest_nice": vals[9],
            }

        except Exception:
            return None

    def _cpu_percent(self, interval=0.05):
        """Computa CPU% entre duas leituras."""
        a = self._read_proc_stat()
        if not a:
            return "?"

        sleep(interval)

        b = self._read_proc_stat()
        if not b:
            return "?"

        # Totais
        idle_a = a["idle"] + a["iowait"]
        idle_b = b["idle"] + b["iowait"]

        non_a = sum(a.values()) - idle_a
        non_b = sum(b.values()) - idle_b

        total_a = idle_a + non_a
        total_b = idle_b + non_b

        totald = total_b - total_a
        idled = idle_b - idle_a

        if totald <= 0:
            return "?"

        usage = (totald - idled) * 100.0 / totald
        return round(usage, 1)

    # ----------------------------------------------------------------------
    # Memória
    # ----------------------------------------------------------------------

    def _mem_percent(self):
        try:
            info = {}
            with open("/proc/meminfo", "r") as f:
                for line in f:
                    k, v = line.split(":", 1)
                    info[k.strip()] = v.strip()

            def kB(key):
                return float(info[key].split()[0]) if key in info else None

            mem_total = kB("MemTotal")
            mem_avail = kB("MemAvailable")

            if mem_total is None or mem_avail is None:
                return "?"

            used = mem_total - mem_avail
            return round(used * 100.0 / mem_total, 1)

        except Exception:
            return "?"

    # ----------------------------------------------------------------------
    # Loadavg
    # ----------------------------------------------------------------------

    def _loadavg(self):
        try:
            if hasattr(os, "getloadavg"):
                l1, l5, l15 = os.getloadavg()
                return [round(l1, 2), round(l5, 2), round(l15, 2)]

            with open("/proc/loadavg", "r") as f:
                parts = f.read().strip().split()
                l1, l5, l15 = map(float, parts[:3])
                return [round(l1, 2), round(l5, 2), round(l15, 2)]

        except Exception:
            return ["?", "?", "?"]

    # ----------------------------------------------------------------------
    # Snapshot principal
    # ----------------------------------------------------------------------

    def snapshot(self) -> dict:
        """
        Retorna snapshot interno:
            {
                "env_user": "...",
                "env_term": "...",
                "cpu_percent": n | "?",
                "mem_percent": n | "?",
                "loadavg": [l1, l5, l15]
            }
        Sempre seguro. Nunca lança exceção.
        """
        try:
            return {
                "env_user": os.environ.get("USER") or "root",
                "env_term": os.environ.get("TERM") or "unknown",
                "cpu_percent": self._cpu_percent(),
                "mem_percent": self._mem_percent(),
                "loadavg": self._loadavg(),
            }

        except Exception as e:
            # fallback extremo — nunca quebrar o Neurotron
            logbus.debug(f"[warn] Perception.snapshot falhou: {e}")
            return {
                "env_user": "unknown",
                "env_term": "unknown",
                "cpu_percent": "?",
                "mem_percent": "?",
                "loadavg": ["?", "?", "?"],
            }

