import csv
import io
import json
import os
import subprocess
import time
from datetime import datetime, timezone
from pathlib import Path

CONFIG_PATH = Path(__file__).resolve().parent.parent / "config" / "process_monitor_config.json"


def utc_now():
    return datetime.now(timezone.utc).isoformat()


def load_config():
    with CONFIG_PATH.open("r", encoding="utf-8") as handle:
        return json.load(handle)


def append_jsonl(path: Path, event: dict):
    path.parent.mkdir(parents=True, exist_ok=True)
    with path.open("a", encoding="utf-8") as handle:
        handle.write(json.dumps(event, separators=(",", ":")) + "\n")


def snapshot_processes():
    completed = subprocess.run(
        ["tasklist", "/FO", "CSV", "/NH"],
        capture_output=True,
        text=True,
        check=True,
        creationflags=getattr(subprocess, "CREATE_NO_WINDOW", 0),
    )

    processes = {}
    for row in csv.reader(io.StringIO(completed.stdout)):
        if len(row) < 2:
            continue
        name = row[0].strip()
        try:
            pid = int(row[1].replace(",", "").strip())
        except ValueError:
            continue
        processes[pid] = name
    return processes


def normalize_name(name: str) -> str:
    return (name or "").strip().lower()


def detect_severity(image_name: str, command_line: str = "") -> tuple[str, bool]:
    lowered_image = normalize_name(image_name)
    lowered_command = normalize_name(command_line)
    watchlist = {"ollama.exe", "python.exe", "node.exe", "java.exe", "rundll32.exe", "mshta.exe", "regsvr32.exe"}
    if lowered_image in watchlist:
        return "medium", True

    for keyword in ("powershell", "rundll32", "regsvr32", "base64", "-enc", "curl http", "wget http", "python -c"):
        if keyword in lowered_command:
            return "high", True

    if "ollama" in lowered_command or lowered_image == "ollama.exe":
        return "medium", True

    return "low", False


def main():
    config = load_config()
    if not config.get("Enabled", True):
        print("Telemetry relay disabled by configuration.")
        return

    telemetry = config.get("Telemetry", {})
    output_path = Path(telemetry.get("Path", "C:/Logs/process_monitor_events.jsonl"))
    poll_interval = max(1, int(telemetry.get("PollIntervalSeconds", 2)))
    heartbeat_interval = max(5, int(telemetry.get("HeartbeatIntervalSeconds", 30)))

    allowlist = {normalize_name(name) for name in config.get("AllowList", [])}
    watchlist = {normalize_name(name) for name in config.get("WatchList", [])}

    previous = snapshot_processes()
    last_heartbeat = 0.0

    append_jsonl(output_path, {
        "timestamp": utc_now(),
        "source": "user_mode_relay",
        "event": "relay_started",
        "baselineProcessCount": len(previous),
        "configVersion": "professional-monitoring-v1",
    })

    print(f"Process telemetry relay started. Writing to {output_path}")

    try:
        while True:
            time.sleep(poll_interval)
            current = snapshot_processes()

            for pid, name in current.items():
                if pid in previous:
                    continue

                lowered = normalize_name(name)
                severity, trigger = detect_severity(name)
                append_jsonl(output_path, {
                    "timestamp": utc_now(),
                    "source": "user_mode_relay",
                    "event": "process_started",
                    "pid": pid,
                    "image": name,
                    "allowlisted": lowered in allowlist,
                    "watchlisted": lowered in watchlist,
                    "severity": severity,
                    "triggered_rule": trigger,
                })

            for pid, name in previous.items():
                if pid not in current:
                    append_jsonl(output_path, {
                        "timestamp": utc_now(),
                        "source": "user_mode_relay",
                        "event": "process_exited",
                        "pid": pid,
                        "image": name,
                    })

            now = time.monotonic()
            if now - last_heartbeat >= heartbeat_interval:
                append_jsonl(output_path, {
                    "timestamp": utc_now(),
                    "source": "user_mode_relay",
                    "event": "heartbeat",
                    "processCount": len(current),
                })
                last_heartbeat = now

            previous = current

    except KeyboardInterrupt:
        append_jsonl(output_path, {
            "timestamp": utc_now(),
            "source": "user_mode_relay",
            "event": "relay_stopped",
        })
        print("Telemetry relay stopped.")


if __name__ == "__main__":
    main()
