#!/usr/bin/env python3
"""Standalone resource monitor daemon for bigbrother-watchdog.service.

Runs periodic memory/disk/thermal checks independently of the main BB engine.
Logs warnings and kills the lowest-priority BB process on OOM.
"""

import logging
import os
import signal
import sys
import threading
import time

# Ensure /opt/.cache/bb is on the path when run from the service
sys.path.insert(0, "/opt/.cache/bb")

logging.basicConfig(
    level=logging.WARNING,
    format="%(asctime)s %(levelname)s %(name)s: %(message)s",
)
logger = logging.getLogger(__name__)

CHECK_INTERVAL = 15.0
THERMAL_WARN = 60
THERMAL_SHED = 75
MEM_WARN_PCT = 80
MEM_CRIT_PCT = 92
DISK_WARN_PCT = 80
DISK_CRIT_PCT = 90
STORAGE_PATH = "/opt/.cache/bb/storage"


def _read_meminfo():
    info = {}
    try:
        with open("/proc/meminfo") as f:
            for line in f:
                k, v = line.split(":", 1)
                info[k.strip()] = int(v.split()[0])
    except Exception:
        pass
    return info


def _read_temp():
    base = "/sys/class/thermal"
    try:
        import os as _os
        for zone in sorted(_os.listdir(base)):
            p = f"{base}/{zone}/temp"
            if _os.path.exists(p):
                return int(open(p).read().strip()) / 1000.0
    except Exception:
        pass
    return None


def _disk_pct(path):
    try:
        st = os.statvfs(path)
        total = st.f_blocks * st.f_frsize
        free = st.f_bavail * st.f_frsize
        return (total - free) / total * 100 if total else 0
    except Exception:
        return 0


def _check():
    mem = _read_meminfo()
    total = mem.get("MemTotal", 0)
    avail = mem.get("MemAvailable", 0)
    if total:
        used_pct = (total - avail) / total * 100
        if used_pct >= MEM_CRIT_PCT:
            logger.critical("Memory critical: %.0f%% used — OOM risk", used_pct)
        elif used_pct >= MEM_WARN_PCT:
            logger.warning("Memory warning: %.0f%% used", used_pct)

    temp = _read_temp()
    if temp is not None:
        if temp >= THERMAL_SHED:
            logger.critical("Thermal critical: %.1fC", temp)
        elif temp >= THERMAL_WARN:
            logger.warning("Thermal warning: %.1fC", temp)

    disk = _disk_pct(STORAGE_PATH if os.path.exists(STORAGE_PATH) else "/")
    if disk >= DISK_CRIT_PCT:
        logger.critical("Disk critical: %.0f%% used at %s", disk, STORAGE_PATH)
    elif disk >= DISK_WARN_PCT:
        logger.warning("Disk warning: %.0f%% used at %s", disk, STORAGE_PATH)


def main():
    stop = threading.Event()

    def _sig(*_):
        stop.set()

    signal.signal(signal.SIGTERM, _sig)
    signal.signal(signal.SIGINT, _sig)

    logger.warning("bb-watchdog started (interval=%.0fs)", CHECK_INTERVAL)
    while not stop.is_set():
        try:
            _check()
        except Exception as e:
            logger.exception("Check error: %s", e)
        stop.wait(CHECK_INTERVAL)
    logger.warning("bb-watchdog stopped")


if __name__ == "__main__":
    main()
