"""
Base classes and types for SDR hardware abstraction.

This module provides the core abstractions for supporting multiple SDR hardware
types (RTL-SDR, LimeSDR, HackRF, etc.) through a unified interface.
"""

from __future__ import annotations

from abc import ABC, abstractmethod
from dataclasses import dataclass, field
from enum import Enum
from typing import Optional


class SDRType(Enum):
    """Supported SDR hardware types."""
    RTL_SDR = "rtlsdr"
    LIME_SDR = "limesdr"
    HACKRF = "hackrf"
    AIRSPY = "airspy"
    SDRPLAY = "sdrplay"
    # Future support
    # USRP = "usrp"
    # BLADE_RF = "bladerf"


@dataclass
class SDRCapabilities:
    """Hardware capabilities for an SDR device."""
    sdr_type: SDRType
    freq_min_mhz: float          # Minimum frequency in MHz
    freq_max_mhz: float          # Maximum frequency in MHz
    gain_min: float              # Minimum gain in dB
    gain_max: float              # Maximum gain in dB
    sample_rates: list[int] = field(default_factory=list)  # Supported sample rates
    supports_bias_t: bool = False    # Bias-T support
    supports_ppm: bool = True        # PPM correction support
    tx_capable: bool = False         # Can transmit


@dataclass
class SDRDevice:
    """Detected SDR device."""
    sdr_type: SDRType
    index: int
    name: str
    serial: str
    driver: str                  # e.g., "rtlsdr", "lime", "hackrf"
    capabilities: SDRCapabilities
    rtl_tcp_host: Optional[str] = None   # Remote rtl_tcp server host
    rtl_tcp_port: Optional[int] = None   # Remote rtl_tcp server port

    @property
    def is_network(self) -> bool:
        """Check if this is a network/remote device."""
        return self.rtl_tcp_host is not None

    def to_dict(self) -> dict:
        """Convert to dictionary for JSON serialization."""
        result = {
            'index': self.index,
            'name': self.name,
            'serial': self.serial,
            'sdr_type': self.sdr_type.value,
            'driver': self.driver,
            'is_network': self.is_network,
            'capabilities': {
                'freq_min_mhz': self.capabilities.freq_min_mhz,
                'freq_max_mhz': self.capabilities.freq_max_mhz,
                'gain_min': self.capabilities.gain_min,
                'gain_max': self.capabilities.gain_max,
                'sample_rates': self.capabilities.sample_rates,
                'supports_bias_t': self.capabilities.supports_bias_t,
                'supports_ppm': self.capabilities.supports_ppm,
                'tx_capable': self.capabilities.tx_capable,
            }
        }
        if self.is_network:
            result['rtl_tcp_host'] = self.rtl_tcp_host
            result['rtl_tcp_port'] = self.rtl_tcp_port
        return result


class CommandBuilder(ABC):
    """Abstract base class for building SDR commands."""

    @abstractmethod
    def build_fm_demod_command(
        self,
        device: SDRDevice,
        frequency_mhz: float,
        sample_rate: int = 22050,
        gain: Optional[float] = None,
        ppm: Optional[int] = None,
        modulation: str = "fm",
        squelch: Optional[int] = None,
        bias_t: bool = False
    ) -> list[str]:
        """
        Build FM demodulation command (for pager decoding).

        Args:
            device: The SDR device to use
            frequency_mhz: Center frequency in MHz
            sample_rate: Audio sample rate (default 22050 for pager)
            gain: Gain in dB (None for auto)
            ppm: PPM frequency correction
            modulation: Modulation type (fm, am, etc.)
            squelch: Squelch level
            bias_t: Enable bias-T power (for active antennas)

        Returns:
            Command as list of strings for subprocess
        """
        pass

    @abstractmethod
    def build_adsb_command(
        self,
        device: SDRDevice,
        gain: Optional[float] = None,
        bias_t: bool = False
    ) -> list[str]:
        """
        Build ADS-B decoder command.

        Args:
            device: The SDR device to use
            gain: Gain in dB (None for auto)
            bias_t: Enable bias-T power (for active antennas)

        Returns:
            Command as list of strings for subprocess
        """
        pass

    @abstractmethod
    def build_ism_command(
        self,
        device: SDRDevice,
        frequency_mhz: float = 433.92,
        gain: Optional[float] = None,
        ppm: Optional[int] = None,
        bias_t: bool = False
    ) -> list[str]:
        """
        Build ISM band decoder command (433MHz sensors).

        Args:
            device: The SDR device to use
            frequency_mhz: Center frequency in MHz (default 433.92)
            gain: Gain in dB (None for auto)
            ppm: PPM frequency correction
            bias_t: Enable bias-T power (for active antennas)

        Returns:
            Command as list of strings for subprocess
        """
        pass

    @abstractmethod
    def get_capabilities(self) -> SDRCapabilities:
        """Return hardware capabilities for this SDR type."""
        pass

    @classmethod
    @abstractmethod
    def get_sdr_type(cls) -> SDRType:
        """Return the SDR type this builder handles."""
        pass
