"""Data models for NUT (Network UPS Tools) provider."""

from __future__ import annotations

from dataclasses import dataclass, field


@dataclass
class NutUpsData:
    """Parsed UPS telemetry from upsd variables."""

    name: str
    description: str = ""
    status: str = ""  # e.g. "OL", "OB LB", "OL CHRG"
    battery_charge: float | None = None
    battery_runtime: int | None = None  # seconds
    ups_load: float | None = None
    input_voltage: float | None = None
    output_voltage: float | None = None
    model: str = ""
    manufacturer: str = ""

    @classmethod
    def from_variables(cls, name: str, variables: dict[str, str]) -> NutUpsData:
        """Build from a dict of NUT variable name -> value."""
        return cls(
            name=name,
            description=variables.get("ups.description", ""),
            status=variables.get("ups.status", ""),
            battery_charge=_float_or_none(variables.get("battery.charge")),
            battery_runtime=_int_or_none(variables.get("battery.runtime")),
            ups_load=_float_or_none(variables.get("ups.load")),
            input_voltage=_float_or_none(variables.get("input.voltage")),
            output_voltage=_float_or_none(variables.get("output.voltage")),
            model=variables.get("device.model", variables.get("ups.model", "")),
            manufacturer=variables.get("device.mfr", variables.get("ups.mfr", "")),
        )

    @property
    def status_flags(self) -> set[str]:
        """Parse status string into individual flags (e.g. {'OL', 'CHRG'})."""
        return set(self.status.split()) if self.status else set()

    @property
    def battery_runtime_formatted(self) -> str:
        """Format runtime seconds as H:MM:SS or M:SS."""
        if self.battery_runtime is None:
            return "N/A"
        total = self.battery_runtime
        hours, remainder = divmod(total, 3600)
        minutes, seconds = divmod(remainder, 60)
        if hours > 0:
            return f"{hours}:{minutes:02d}:{seconds:02d}"
        return f"{minutes}:{seconds:02d}"


def _float_or_none(val: str | None) -> float | None:
    if val is None:
        return None
    try:
        return float(val)
    except (ValueError, TypeError):
        return None


def _int_or_none(val: str | None) -> int | None:
    if val is None:
        return None
    try:
        return int(float(val))
    except (ValueError, TypeError):
        return None
