from pathlib import Path
from typing import Any

from ..models import CollectorError, InstanceDescriptor, JobDescriptor
from ..normalizer import observation_from_signals
from .base import CollectorContext, result


class ProcessCollector:
    name = "process"
    version = "0.1"

    def collect(self, context: CollectorContext):  # type: ignore[no-untyped-def]
        started = context.now
        observations = []
        errors: list[CollectorError] = []
        for definition in context.config.definitions:
            process_name = str(definition["process_name"])
            job = JobDescriptor(str(definition["job_key"]), str(definition.get("display_name", process_name)), "process",
                                str(definition.get("job_type", "worker")), stale_after_seconds=definition.get("stale_after_seconds"),
                                timeout_seconds=context.config.timeout_seconds)
            instance = InstanceDescriptor(job, context.host, "process", process_name, process_name=process_name)
            signals: dict[str, Any] = {"source": "procfs", "process_name": process_name, "process_exists": False}
            try:
                for proc in Path("/proc").glob("[0-9]*"):
                    try:
                        cmdline = (proc / "cmdline").read_bytes().replace(b"\x00", b" ").decode(errors="replace").strip()
                        comm = (proc / "comm").read_text(encoding="utf-8").strip()
                        if comm == process_name or Path(cmdline.split(" ", 1)[0]).name == process_name:
                            signals.update({"process_exists": True, "process_id": int(proc.name), "process_status": (proc / "status").read_text(encoding="utf-8")[:4096]})
                            break
                    except (FileNotFoundError, PermissionError, ValueError):
                        continue
            except PermissionError as exc:
                errors.append(CollectorError("permission_denied", str(exc), instance.instance_key))
                signals["permission_denied"] = True
            observations.append(observation_from_signals(job, instance, None, signals, started))
        return result(self.name, self.version, started, observations, errors, {"read_only": True, "source": "/proc"})
