import logging
from dataclasses import dataclass

from clan_lib.api import API
from clan_lib.errors import ClanError
from clan_lib.machines.machines import Machine
from clan_lib.metrics.telegraf import get_metrics
from clan_lib.nix import nix_eval
from clan_lib.ssh.localhost import LocalHost
from clan_lib.ssh.remote import Remote

log = logging.getLogger(__name__)


@dataclass(frozen=True)
class NixOSSystems:
    current_system: str
    booted_system: str
    current_kernel: str
    booted_kernel: str


def get_nixos_systems(
    machine: Machine,
    target_host: Remote | LocalHost,
) -> NixOSSystems | None:
    """Get the nixos systems from the target host."""
    parsed_metrics = get_metrics(machine, target_host)

    for metric in parsed_metrics:
        if metric["name"] == "nixos_systems":
            return NixOSSystems(
                current_system=metric["tags"]["current_system"],
                booted_system=metric["tags"]["booted_system"],
                current_kernel=metric["tags"]["current_kernel"],
                booted_kernel=metric["tags"]["booted_kernel"],
            )
    return None


@API.register
def check_machine_up_to_date(
    machine: Machine,
    target_host: Remote | LocalHost,
) -> bool:
    """Check if a machine needs an update.

    Args:
        machine: The Machine instance to check.
        target_host: Optional Remote or LocalHost instance representing the target host.

    Returns:
        bool: True if the machine needs an update, False otherwise.

    """
    nixos_systems = get_nixos_systems(machine, target_host)

    if nixos_systems is None:
        msg = "Failed to find 'current_system_present' metric in telegraf logs."
        raise ClanError(msg)

    machine.info(f"Getting system outPath from {machine.name}...")

    git_out_path = nix_eval(
        [
            f"{machine.flake}#nixosConfigurations.'{machine.name}'.config.system.build.toplevel.outPath",
        ],
    )

    machine.debug(
        f"Checking up-to-date:\n"
        f"Machine outPath: {nixos_systems.current_system}\n"
        f"Git outPath    : {git_out_path}\n",
    )

    return git_out_path != nixos_systems.current_system
