"""Signal-generator controller for direct protocol packets."""

from __future__ import annotations

import logging
import time

from ..enums import PacketType
from ..exceptions import TimeoutError
from ..models import DeviceStatus, GeneratorSettings, Packet
from ..session import LibreVNASession

logger = logging.getLogger(__name__)


class GeneratorController:
    """Signal-generator operations built on direct packet protocol."""

    def __init__(self, session: LibreVNASession) -> None:
        """Bind generator controller to active session."""
        self._session = session
        self._settings: GeneratorSettings | None = None

    def configure(self, settings: GeneratorSettings, *, timeout_s: float = 1.0) -> None:
        """Configure generator mode and active CW output."""
        self._settings = settings
        self._session.send(Packet(PacketType.GENERATOR, settings), require_ack=True, timeout_s=timeout_s)
        logger.info(
            "Generator configured: freq=%.3fHz power=%.2fdBm port=%d correction=%s",
            settings.frequency_hz,
            settings.power_dbm,
            settings.active_port,
            settings.apply_amplitude_correction,
        )

    def set_idle(self, *, timeout_s: float = 1.0) -> None:
        """Return device to idle mode and stop generator output."""
        logger.info("Setting LibreVNA idle mode")
        self._session.send(Packet(PacketType.SET_IDLE), require_ack=True, timeout_s=timeout_s)

    def wait_until_ready(
        self,
        *,
        timeout_s: float,
        poll_interval_s: float,
    ) -> DeviceStatus:
        """Wait until available lock flags report the generator is ready."""

        deadline = time.monotonic() + timeout_s

        while True:
            status = self._session.get_device_status(timeout_s=min(timeout_s, 1.0))
            lock_values = [value for value in (status.source_locked, status.lo_locked) if value is not None]
            if lock_values:
                if all(lock_values):
                    return status
            else:
                raise RuntimeError(
                    f"Generator lock telemetry is unavailable for hardware family {status.family.name}"
                )

            remaining = deadline - time.monotonic()
            if remaining <= 0:
                raise TimeoutError("Timed out waiting for LibreVNA generator lock")
            time.sleep(min(poll_interval_s, remaining))
