"""Device listing, partitioning, and deletion."""

from __future__ import annotations

from dataclasses import dataclass
from datetime import datetime, timedelta, timezone
from typing import Any

from .client import CnMaestroClient


@dataclass(frozen=True)
class Device:
    mac: str
    name: str
    product: str
    status: str  # "online" | "offline" | other
    last_sync: datetime | None
    software_version: str | None
    tower: str | None
    network: str | None
    raw: dict[str, Any]

    @property
    def is_online(self) -> bool:
        return self.status.lower() == "online"

    @property
    def never_synced(self) -> bool:
        return self.last_sync is None


def _parse_last_sync(value: Any) -> datetime | None:
    """Parse cnMaestro last_sync (epoch ms or ISO 8601)."""
    if value in (None, "", 0):
        return None
    if isinstance(value, (int, float)):
        # cnMaestro uses epoch milliseconds
        return datetime.fromtimestamp(value / 1000, tz=timezone.utc)
    if isinstance(value, str):
        try:
            # try epoch first
            return datetime.fromtimestamp(int(value) / 1000, tz=timezone.utc)
        except ValueError:
            pass
        try:
            return datetime.fromisoformat(value.replace("Z", "+00:00"))
        except ValueError:
            return None
    return None


def device_from_api(d: dict[str, Any]) -> Device:
    return Device(
        mac=d.get("mac", "").upper(),
        name=d.get("name") or d.get("hostname") or "(unnamed)",
        product=d.get("product") or d.get("product_type") or "unknown",
        status=str(d.get("status", "")),
        last_sync=_parse_last_sync(
            d.get("last_sync") or d.get("last_seen") or d.get("status_time")
        ),
        software_version=d.get("software_version") or d.get("sw_version"),
        tower=d.get("tower"),
        network=d.get("network"),
        raw=d,
    )


def list_devices(client: CnMaestroClient) -> list[Device]:
    return [device_from_api(d) for d in client.paginated("/api/v2/devices")]


@dataclass
class CleanupPartition:
    online: list[Device]
    offline_recent: list[Device]
    offline_stale: list[Device]
    never_synced: list[Device]

    @property
    def candidates(self) -> list[Device]:
        return self.offline_stale + self.never_synced

    @property
    def total(self) -> int:
        return (
            len(self.online)
            + len(self.offline_recent)
            + len(self.offline_stale)
            + len(self.never_synced)
        )


def partition_for_cleanup(
    devices: list[Device], threshold_hours: float, now: datetime | None = None
) -> CleanupPartition:
    now = now or datetime.now(tz=timezone.utc)
    cutoff = now - timedelta(hours=threshold_hours)
    online: list[Device] = []
    offline_recent: list[Device] = []
    offline_stale: list[Device] = []
    never_synced: list[Device] = []
    for d in devices:
        if d.is_online:
            online.append(d)
            continue
        if d.last_sync is None:
            never_synced.append(d)
        elif d.last_sync < cutoff:
            offline_stale.append(d)
        else:
            offline_recent.append(d)
    return CleanupPartition(
        online=online,
        offline_recent=offline_recent,
        offline_stale=offline_stale,
        never_synced=never_synced,
    )


def delete_device(client: CnMaestroClient, mac: str) -> None:
    client.delete(f"/api/v2/devices/{mac}")
