"""AlphaTRACER radon sensor implementation."""

from multipledispatch import dispatch
from minimalmodbus import Instrument, BYTEORDER_BIG

from atmospyre.sensors import Sensor
from atmospyre.sensors.read_tag import ReadTag
from atmospyre.sensors.read_tag import ReadTagMetadata


# ============================================================================
# AlphaTRACER-specific tags (empty structs)
# ============================================================================


class RadonLiveTag(ReadTag):
    """Tag for live radon concentration measurement.

    This tag class represents real-time radon concentration measurements
    from the AlphaTRACER sensor. It is used with the dispatch mechanism
    to route read operations to the appropriate register reading function.

    See Also
    --------
    ReadTag : Base tag class
    RADON_LIVE : Singleton instance of this tag class
    """
    pass


class Radon24hTag(ReadTag):
    """Tag for 24-hour average radon concentration measurement.

    This tag class represents 24-hour rolling average radon concentration
    measurements from the AlphaTRACER sensor. It is used with the dispatch
    mechanism to route read operations to the appropriate register reading
    function.

    See Also
    --------
    ReadTag : Base tag class
    RADON_24H : Singleton instance of this tag class
    """
    pass


class RadonLongTermTag(ReadTag):
    """Tag for long-term average radon concentration measurement.

    This tag class represents long-term rolling average radon concentration
    measurements from the AlphaTRACER sensor. It is used with the dispatch
    mechanism to route read operations to the appropriate register reading
    function.

    See Also
    --------
    ReadTag : Base tag class
    RADON_LONG_TERM : Singleton instance of this tag class
    """
    pass


# ============================================================================
# Tag instances (singleton instances to use)
# ============================================================================

RADON_LIVE = RadonLiveTag(ReadTagMetadata(
    unit="Bq/m³",
    description="Live radon concentration",
    precision=0,
    source="AlphaTRACER Manual, Register 20 (Long, BYTEORDER_BIG)"
))
"""Live radon concentration measurement tag.

This tag instance provides access to real-time radon concentration readings
from the AlphaTRACER sensor. The live reading updates approximately every
10 minutes and represents the most current measurement available.

Attributes
----------
unit : str
    "Bq/m³" (Becquerels per cubic meter)
description : str
    "Live radon concentration"
precision : int
    0 (integer values only)
source : str
    Modbus register 20 (32-bit Long, BYTEORDER_BIG)

Examples
--------
Read live radon concentration:

>>> from atmospyre.sensors.alphatracer import AlphaTRACER, RADON_LIVE
>>> sensor = AlphaTRACER(port='COM4', slave_address=1)
>>> result = sensor.read([RADON_LIVE])
>>> print(result[RADON_LIVE])
165

Notes
-----
The live reading is the most responsive but also the most variable
measurement. For more stable readings, consider using RADON_24H or
RADON_LONG_TERM.

See Also
--------
RADON_24H : 24-hour average measurement
RADON_LONG_TERM : Long-term average measurement
RadonLiveTag : Tag class for this measurement
"""

RADON_24H = Radon24hTag(ReadTagMetadata(
    unit="Bq/m³",
    description="24-hour average radon concentration",
    precision=0,
    source="AlphaTRACER Manual, Register 22 (Long, BYTEORDER_BIG)"
))
"""24-hour average radon concentration measurement tag.

This tag instance provides access to 24-hour rolling average radon
concentration readings from the AlphaTRACER sensor. This measurement
is more stable than the live reading and is suitable for daily monitoring.

Attributes
----------
unit : str
    "Bq/m³" (Becquerels per cubic meter)
description : str
    "24-hour average radon concentration"
precision : int
    0 (integer values only)
source : str
    Modbus register 22 (32-bit Long, BYTEORDER_BIG)

Examples
--------
Read 24-hour average radon concentration:

>>> from atmospyre.sensors.alphatracer import AlphaTRACER, RADON_24H
>>> sensor = AlphaTRACER(port='COM4', slave_address=1)
>>> result = sensor.read([RADON_24H])
>>> print(result[RADON_24H])
180

Notes
-----
The 24-hour average provides a more stable measurement by smoothing out
short-term fluctuations. This is the recommended measurement for daily
monitoring and trend analysis.

See Also
--------
RADON_LIVE : Real-time measurement
RADON_LONG_TERM : Long-term average measurement
Radon24hTag : Tag class for this measurement
"""

RADON_LONG_TERM = RadonLongTermTag(ReadTagMetadata(
    unit="Bq/m³",
    description="Long-term average radon concentration",
    precision=0,
    source="AlphaTRACER Manual, Register 24 (Long, BYTEORDER_BIG)"
))
"""Long-term average radon concentration measurement tag.

This tag instance provides access to long-term rolling average radon
concentration readings from the AlphaTRACER sensor. This measurement
provides the most stable reading and is suitable for compliance reporting
and long-term trend analysis.

Attributes
----------
unit : str
    "Bq/m³" (Becquerels per cubic meter)
description : str
    "Long-term average radon concentration"
precision : int
    0 (integer values only)
source : str
    Modbus register 24 (32-bit Long, BYTEORDER_BIG)

Examples
--------
Read long-term average radon concentration:

>>> from atmospyre.sensors.alphatracer import AlphaTRACER, RADON_LONG_TERM
>>> sensor = AlphaTRACER(port='COM4', slave_address=1)
>>> result = sensor.read([RADON_LONG_TERM])
>>> print(result[RADON_LONG_TERM])
175

Notes
-----
The long-term average is the most stable measurement, making it ideal for:

- Compliance reporting and regulatory requirements
- Long-term trend analysis
- Baseline radon level determination

Allow at least 24 hours of continuous operation before relying on this
value for important decisions.

See Also
--------
RADON_LIVE : Real-time measurement
RADON_24H : 24-hour average measurement
RadonLongTermTag : Tag class for this measurement
"""

# ============================================================================
# Dispatch namespace for AlphaTRACER read functions
# ============================================================================


alphatracer_namespace = {}


# ============================================================================
# AlphaTRACER Read function implementations using dispatch decorator
# ============================================================================

@dispatch(object, RadonLiveTag, namespace=alphatracer_namespace)
def _read(instrument: Instrument, tag: RadonLiveTag) -> int:
    """Read live radon concentration from register 20.

    This function reads the current radon concentration from Modbus
    register 20 using a 32-bit long integer format with big-endian
    byte ordering.

    Parameters
    ----------
    instrument : Instrument
        minimalmodbus Instrument instance for Modbus communication
    tag : RadonLiveTag
        Tag instance identifying this measurement type

    Returns
    -------
    int
        Current radon concentration in Bq/m³

    Notes
    -----
    The live reading updates approximately every 10 minutes. Reading
    more frequently will not provide new data.

    Uses BYTEORDER_BIG for Modbus long register reading as specified
    in the AlphaTRACER communication protocol.

    See Also
    --------
    RADON_LIVE : Tag instance for this measurement
    RadonLiveTag : Tag class definition
    """
    return instrument.read_long(20, byteorder=BYTEORDER_BIG)


@dispatch(object, Radon24hTag, namespace=alphatracer_namespace)
def _read(instrument: Instrument, tag: Radon24hTag) -> int:
    """Read 24-hour average radon concentration from register 22.

    This function reads the 24-hour rolling average radon concentration
    from Modbus register 22 using a 32-bit long integer format with
    big-endian byte ordering.

    Parameters
    ----------
    instrument : Instrument
        minimalmodbus Instrument instance for Modbus communication
    tag : Radon24hTag
        Tag instance identifying this measurement type

    Returns
    -------
    int
        24-hour rolling average radon concentration in Bq/m³

    Notes
    -----
    This value is more stable than the live reading and is recommended
    for daily monitoring and trend analysis.

    Uses BYTEORDER_BIG for Modbus long register reading as specified
    in the AlphaTRACER communication protocol.

    See Also
    --------
    RADON_24H : Tag instance for this measurement
    Radon24hTag : Tag class definition
    """
    return instrument.read_long(22, byteorder=BYTEORDER_BIG)


@dispatch(object, RadonLongTermTag, namespace=alphatracer_namespace)
def _read(instrument: Instrument, tag: RadonLongTermTag) -> int:
    """Read long-term average radon concentration from register 24.

    This function reads the long-term rolling average radon concentration
    from Modbus register 24 using a 32-bit long integer format with
    big-endian byte ordering.

    Parameters
    ----------
    instrument : Instrument
        minimalmodbus Instrument instance for Modbus communication
    tag : RadonLongTermTag
        Tag instance identifying this measurement type

    Returns
    -------
    int
        Long-term rolling average radon concentration in Bq/m³

    Notes
    -----
    This provides the most stable measurement over extended periods and
    is suitable for compliance reporting and baseline determination.

    Uses BYTEORDER_BIG for Modbus long register reading as specified
    in the AlphaTRACER communication protocol.

    See Also
    --------
    RADON_LONG_TERM : Tag instance for this measurement
    RadonLongTermTag : Tag class definition
    """
    return instrument.read_long(24, byteorder=BYTEORDER_BIG)


# ============================================================================
# AlphaTRACER Sensor Class
# ============================================================================


class AlphaTRACER(Sensor):
    """RadonTech AlphaTRACER radon sensor with Modbus RTU communication.

    The AlphaTRACER is a professional radon measurement device that
    communicates via Modbus RTU protocol. It provides three types of
    radon concentration measurements: live, 24-hour average, and
    long-term average.

    Parameters
    ----------
    port : str
        Serial port name (e.g., 'COM4' on Windows, '/dev/ttyUSB0' on Linux)
    slave_address : int, optional
        Modbus slave address, by default 1
    baudrate : int, optional
        Serial communication speed in baud, by default 19200
    stopbits : int, optional
        Number of stop bits, by default 2
    bytesize : int, optional
        Number of data bits per byte, by default 8
    parity : str, optional
        Parity checking method ('N' for None, 'E' for Even, 'O' for Odd),
        by default 'N'
    timeout : float, optional
        Read timeout in seconds, by default 0.5

    Attributes
    ----------
    port : str
        Serial port name
    slave_address : int
        Modbus slave address
    valid_tags : list[ReadTag]
        List of valid measurement tags for this sensor

    Raises
    ------
    SerialException
        If the serial port cannot be opened or configured
    ModbusException
        If Modbus communication fails

    Examples
    --------
    Basic initialization and single tag reading:

    Hint: use the module import if you plan to use multiple sensors.

    >>> from atmospyre.sensors.implementations.radon import alphatracer
    >>> sensor = alphatracer.AlphaTRACER(port='COM4', slave_address=1)
    >>> result = sensor.read([alphatracer.RADON_LIVE])
    >>> print(result[alphatracer.RADON_LIVE])
    165

    Read multiple measurements:

    Hint: directly import if you plan to use only one sensors.

    >>> from atmospyre.sensors.implementations.radon.radontec.alphatracer import (
    ...     AlphaTRACER, RADON_LIVE, RADON_24H, RADON_LONG_TERM
    ... )
    >>> sensor = AlphaTRACER(port='/dev/ttyUSB0')
    >>> result = sensor.read([RADON_LIVE, RADON_24H, RADON_LONG_TERM])
    >>> print(f"Live: {result[RADON_LIVE]} Bq/m³")
    Live: 165 Bq/m³
    >>> print(f"24h avg: {result[RADON_24H]} Bq/m³")
    24h avg: 180 Bq/m³
    >>> print(f"Long-term: {result[RADON_LONG_TERM]} Bq/m³")
    Long-term: 175 Bq/m³

    Custom serial configuration:

    >>> sensor = AlphaTRACER(
    ...     port='COM4',
    ...     slave_address=2,
    ...     baudrate=9600,
    ...     timeout=1.0
    ... )

    Use with context manager:

    >>> with AlphaTRACER(port='COM4') as sensor:
    ...     result = sensor.read([RADON_24H])
    ...     print(f"24h average: {result[RADON_24H]} Bq/m³")
    24h average: 180 Bq/m³
    """

    def __init__(
        self,
        port: str,
        slave_address: int = 1,
        baudrate: int = 19200,
        stopbits: int = 2,
        bytesize: int = 8,
        parity: str = 'N',
        timeout: float = 0.5
    ):
        """Initialize AlphaTRACER sensor with serial communication parameters.

        Parameters
        ----------
        port : str
            Serial port name (e.g., 'COM4' on Windows, '/dev/ttyUSB0' on Linux)
        slave_address : int, optional
            Modbus slave address, by default 1
        baudrate : int, optional
            Serial communication speed in baud, by default 19200
        stopbits : int, optional
            Number of stop bits, by default 2
        bytesize : int, optional
            Number of data bits per byte, by default 8
        parity : str, optional
            Parity checking method ('N', 'E', 'O'), by default 'N'
        timeout : float, optional
            Read timeout in seconds, by default 0.5
        """
        super().__init__(
            port=port,
            valid_tags=[RADON_LIVE, RADON_24H, RADON_LONG_TERM],
            namespace=alphatracer_namespace,
            slave_address=slave_address,
            baudrate=baudrate,
            stopbits=stopbits,
            bytesize=bytesize,
            parity=parity,
            timeout=timeout
        )