"""Main user-facing LibreVNA direct-USB device class."""

from __future__ import annotations

import logging
from types import TracebackType

from .api.config import ConfigController
from .api.generator import GeneratorController
from .api.vna import VNAController
from .enums import PacketType
from .models import DeviceInfo, DeviceStatus, Packet, USBDeviceDescriptor
from .session import LibreVNASession

logger = logging.getLogger(__name__)


class LibreVNADevice:
    """Main entry point for direct USB control of LibreVNA."""

    def __init__(self) -> None:
        """Create device facade with session-backed VNA/config controllers."""
        self._session = LibreVNASession()

        self.vna = VNAController(self._session)
        self.generator = GeneratorController(self._session)
        self.config = ConfigController(self._session)

    def __enter__(self) -> LibreVNADevice:
        """Return self to support context-managed lifetime in host applications."""
        return self

    def __exit__(
        self,
        exc_type: type[BaseException] | None,
        exc: BaseException | None,
        tb: TracebackType | None,
    ) -> None:
        """Always close USB session when leaving context manager block."""
        self.disconnect()

    @property
    def is_connected(self) -> bool:
        """Return connection state of underlying USB session."""
        return self._session.is_connected

    @property
    def connected_serial(self) -> str | None:
        """Return currently connected serial number when available."""
        return self._session.connected_serial

    @staticmethod
    def list_devices() -> list[USBDeviceDescriptor]:
        """Return all currently discoverable LibreVNA USB devices."""
        devices = LibreVNASession.list_devices()
        logger.debug("Discovered %d LibreVNA USB device(s)", len(devices))
        return devices

    def connect(
        self,
        serial: str | None = None,
        strict_protocol_version: int = 14,
        timeout_s: float = 1.0,
    ) -> None:
        """Connect to a LibreVNA device by optional serial number."""
        logger.info(
            "Connecting to LibreVNA (serial=%s, strict_protocol=%d, timeout=%.2fs)",
            serial,
            strict_protocol_version,
            timeout_s,
        )
        self._session.connect(
            serial=serial,
            strict_protocol_version=strict_protocol_version,
            timeout_s=timeout_s,
        )
        logger.info("Connected to LibreVNA (serial=%s)", self.connected_serial)

    def disconnect(self) -> None:
        """Disconnect USB transport and clear runtime state."""
        logger.info("Disconnecting LibreVNA session")
        self._session.disconnect()
        logger.info("LibreVNA session disconnected")

    def send(self, packet: Packet, *, require_ack: bool = True, timeout_s: float = 0.5) -> None:
        """Send low-level protocol packet."""
        logger.debug(
            "Sending packet %s (require_ack=%s, timeout=%.2fs)",
            packet.type.name,
            require_ack,
            timeout_s,
        )
        self._session.send(packet, require_ack=require_ack, timeout_s=timeout_s)

    def request(
        self,
        packet_type: PacketType,
        response_type: PacketType,
        *,
        timeout_s: float = 1.0,
    ) -> Packet:
        """Send no-payload request packet and wait for a response packet."""
        logger.debug(
            "Request packet=%s response=%s timeout=%.2fs",
            packet_type.name,
            response_type.name,
            timeout_s,
        )
        return self._session.request(packet_type, response_type, timeout_s=timeout_s)

    def get_device_info(self) -> DeviceInfo:
        """Return cached device info from handshake."""
        return self._session.get_device_info()

    def get_device_status(self, *, timeout_s: float = 1.0) -> DeviceStatus:
        """Query and return current device status."""
        return self._session.get_device_status(timeout_s=timeout_s)
