#!/usr/bin/env python3
from __future__ import annotations

import os
import sys
import time
from pathlib import Path


def collect(proc_root: Path = Path("/proc"), inotify_watches: int | None = None) -> dict[str, float | int]:
    try:
        allocated, _unused, maximum = [int(x) for x in (proc_root / "sys" / "fs" / "file-nr").read_text().split()[:3]]
        open_fds_pct = round(allocated * 100.0 / max(1, maximum), 2)
    except (OSError, ValueError):
        open_fds_pct = 0.0
    proc_count = 0
    for entry in proc_root.iterdir():
        if entry.name.isdigit():
            proc_count += 1
    if inotify_watches is None:
        inotify_watches = count_inotify_watches(proc_root)
    try:
        max_watches = int((proc_root / "sys" / "fs" / "inotify" / "max_user_watches").read_text())
    except (OSError, ValueError):
        max_watches = 1
    return {
        "open_fds_pct": open_fds_pct,
        "proc_count": proc_count,
        "inotify_watch_pct": round(inotify_watches * 100.0 / max(1, max_watches), 2),
    }


def count_inotify_watches(proc_root: Path) -> int:
    total = 0
    for entry in proc_root.iterdir():
        fdinfo = entry / "fdinfo"
        if not entry.name.isdigit() or not fdinfo.exists():
            continue
        for info in fdinfo.iterdir():
            try:
                total += sum(1 for line in info.read_text(errors="ignore").splitlines() if line.startswith("inotify "))
            except OSError:
                continue
    return total


def main() -> int:
    update = 15
    proc_root = Path(os.environ.get("SM_PROC_ROOT", "/proc"))
    print(f"CHART system_monitor.proc_fd '' 'Process and FD pressure' 'percent count percent' system_monitor proc_fd line 60030 {update}")
    print("DIMENSION open_fds_pct 'open_fds_pct' absolute 1 1")
    print("DIMENSION proc_count 'proc_count' absolute 1 1")
    print("DIMENSION inotify_watch_pct 'inotify_watch_pct' absolute 1 1")
    while True:
        metrics = collect(proc_root)
        print("BEGIN system_monitor.proc_fd")
        for key in ("open_fds_pct", "proc_count", "inotify_watch_pct"):
            print(f"SET {key} = {metrics[key]}")
        print("END")
        sys.stdout.flush()
        if os.environ.get("SM_ONESHOT"):
            return 0
        time.sleep(update)


if __name__ == "__main__":
    raise SystemExit(main())
