"""Static system metadata collection."""

from __future__ import annotations

import os
import platform
import socket
from dataclasses import dataclass, field
from typing import Any

import psutil


@dataclass(frozen=True)
class SystemInfo:
    """Static system information collected at startup."""

    hostname: str
    fqdn: str
    os_name: str
    os_version: str
    os_release: str
    architecture: str
    cpu_count: int
    cpu_model: str
    total_memory_bytes: int
    python_version: str
    boot_time: float
    network_interfaces: dict[str, list[str]] = field(default_factory=dict)
    extra: dict[str, Any] = field(default_factory=dict)

    def to_dict(self) -> dict[str, Any]:
        """Convert to dictionary for serialization."""
        return {
            "hostname": self.hostname,
            "fqdn": self.fqdn,
            "os": {
                "name": self.os_name,
                "version": self.os_version,
                "release": self.os_release,
            },
            "architecture": self.architecture,
            "cpu": {
                "count": self.cpu_count,
                "model": self.cpu_model,
            },
            "memory": {
                "total_bytes": self.total_memory_bytes,
            },
            "python_version": self.python_version,
            "boot_time": self.boot_time,
            "network_interfaces": self.network_interfaces,
            **self.extra,
        }


def _get_cpu_model() -> str:
    """Get CPU model string."""
    try:
        if platform.system() == "Linux":
            with open("/proc/cpuinfo") as f:
                for line in f:
                    if line.startswith("model name"):
                        return line.split(":")[1].strip()
        elif platform.system() == "Darwin":
            import subprocess

            result = subprocess.run(
                ["sysctl", "-n", "machdep.cpu.brand_string"],
                capture_output=True,
                text=True,
                timeout=5,
            )
            if result.returncode == 0:
                return result.stdout.strip()
        elif platform.system() == "Windows":
            return platform.processor()
    except Exception:
        pass
    return platform.processor() or "unknown"


def _get_network_interfaces() -> dict[str, list[str]]:
    """Get network interface addresses."""
    interfaces: dict[str, list[str]] = {}
    try:
        for name, addrs in psutil.net_if_addrs().items():
            ips = []
            for addr in addrs:
                if addr.family == socket.AF_INET:
                    ips.append(addr.address)
                elif addr.family == socket.AF_INET6:
                    # Skip link-local IPv6
                    if not addr.address.startswith("fe80:"):
                        ips.append(addr.address)
            if ips:
                interfaces[name] = ips
    except Exception:
        pass
    return interfaces


def collect_system_info(extra: dict[str, Any] | None = None) -> SystemInfo:
    """
    Collect static system information.

    Args:
        extra: Additional key-value pairs to include

    Returns:
        SystemInfo instance with collected data
    """
    try:
        hostname = socket.gethostname()
    except Exception:
        hostname = "unknown"

    try:
        fqdn = socket.getfqdn()
    except Exception:
        fqdn = hostname

    memory = psutil.virtual_memory()

    return SystemInfo(
        hostname=hostname,
        fqdn=fqdn,
        os_name=platform.system(),
        os_version=platform.version(),
        os_release=platform.release(),
        architecture=platform.machine(),
        cpu_count=os.cpu_count() or 1,
        cpu_model=_get_cpu_model(),
        total_memory_bytes=memory.total,
        python_version=platform.python_version(),
        boot_time=psutil.boot_time(),
        network_interfaces=_get_network_interfaces(),
        extra=extra or {},
    )
