"""RF (Radio Frequency) access point class."""

import math as m
from .access_point import AccessPoint


class RF(AccessPoint):
    """Radio Frequency (RF) access point for fallback communication.

    RF represents a wireless access point that provides fallback connectivity when VLC
    is unavailable or congested. It implements a femtocell-based RF communication system
    with configurable transmission power, bandwidth, and channel characteristics.

    RF access points are typically used in hybrid VLC/RF systems to ensure continuous
    connectivity, especially when LOS (Line of Sight) to VLed is blocked.

    Class Attributes:
        numberOfRFs (int): Counter tracking total number of RF instances created

    Properties:
        Inherited from AccessPoint:
            x, y, z, position, state, ID, B, sliceTime, slicesInFrame

        RF-specific:
            bf (float): Femtocell bandwidth in Hz
            pf (float): Transmission power in dBm
            BERf (float): Target Bit Error Rate
            Af (float): Pathloss constant (dimensionless)
            Ef (float): Pathloss exponent (dimensionless)
            R_awgn (float): Normalized AWGN noise power
            pif (float): SNR discrepancy at target BER (read-only)
            N_rf (int): Number of cells using this femtocell
            nFactor_rf (float): RF constant factor
            A (float): Rayleigh distributed channel gain

    Example:
        Creating an RF access point for fallback::

            # Basic RF at room center, 1m height
            rf = RF(x=5.0, y=5.0, z=1.0)

            # RF with custom parameters
            rf = RF(x=5.0, y=5.0, z=1.0,
                   bf=5e6,      # 5 MHz bandwidth
                   pf=40,       # 40 dBm transmission power
                   BERf=1e-5)   # Target BER of 10^-5

            # Configure TDM parameters
            rf.sliceTime = 0.1
            rf.slicesInFrame = 10

    Note:
        - Automatically calculates pif based on BERf
        - Default values suitable for indoor femtocell deployment
        - ID is auto-assigned incrementally starting from 0
        - Typically positioned at lower heights than VLeds
    """

    numberOfRFs = 0

    def __init__(
        self,
        x: float,
        y: float,
        z: float,
        bf: float = 5e6,
        pf: float = 40,
        BERf: float = 10e-5,
        Af: float = 10.0,
        Ef: float = 1.0,
        R_awgn: float = 1 * 10 ** (-174 / 10),
        N_rf: int = 10,
        nFactor_rf: float = 1.0,
        A: float = 0.1e6,
    ) -> None:
        """Initialize an RF access point with wireless communication parameters.

        Creates an RF access point with specified position and radio parameters.
        Automatically calculates SNR discrepancy (pif) based on target BER.

        Args:
            x: X-coordinate position in meters
            y: Y-coordinate position in meters
            z: Z-coordinate position in meters (typically lower than VLeds)
            bf: Femtocell bandwidth in Hz (default: 5 MHz)
            pf: Transmission power in dBm (default: 40 dBm)
            BERf: Target Bit Error Rate (default: 10^-4)
            Af: Pathloss constant, dimensionless (default: 10.0)
            Ef: Pathloss exponent, dimensionless (default: 1.0)
            R_awgn: Normalized AWGN noise power in watts (default: 10^(-17.4))
            N_rf: Number of cells using this femtocell (default: 10)
            nFactor_rf: RF constant factor (default: 1.0)
            A: Rayleigh distributed channel gain (default: 0.1 MHz)

        Example::

            # Basic RF with defaults
            rf = RF(x=10.0, y=10.0, z=1.0)

            # RF with custom bandwidth and power
            rf = RF(x=10.0, y=10.0, z=1.0,
                   bf=10e6,     # 10 MHz
                   pf=43,       # 43 dBm
                   BERf=1e-6)   # Lower BER target

        Note:
            - pif is automatically calculated as -1.5 / ln(5 * BERf)
            - RF ID is auto-assigned from numberOfRFs class counter
            - Default parameters suitable for indoor femtocell
        """
        AccessPoint.__init__(self, x, y, z)
        self.__bf = bf
        self.__pf = pf
        self.__BERf = BERf
        self.__Af = Af
        self.__Ef = Ef
        self.__R_awgn = R_awgn
        self.__N_rf = N_rf
        self.__nFactor_rf = nFactor_rf
        self.__A = A
        self._state = AccessPoint.stateap.IDLE

        self.__pif = -1.5 / m.log(5 * self.__BERf)
        self._ID = RF.numberOfRFs
        RF.numberOfRFs += 1

    @property
    def bf(self) -> float:
        """Get the femtocell bandwidth.

        Returns:
            float: Bandwidth in Hz (default: 5 MHz)
        """
        return self.__bf

    @bf.setter
    def bf(self, value: float) -> None:
        """Set the femtocell bandwidth.

        Args:
            value: Bandwidth in Hz
        """
        self.__bf = value

    @property
    def pf(self) -> float:
        """Get the femtobase transmission power.

        Returns:
            float: Transmission power in dBm (default: 40 dBm)
        """
        return self.__pf

    @pf.setter
    def pf(self, value: float) -> None:
        """Set the femtobase transmission power.

        Args:
            value: Transmission power in dBm
        """
        self.__pf = value

    @property
    def BERf(self) -> float:
        """Get the target Bit Error Rate for the femtocell network.

        Returns:
            float: Target BER (default: 10^-4)
        """
        return self.__BERf

    @BERf.setter
    def BERf(self, value: float) -> None:
        """Set the target Bit Error Rate for the femtocell network.

        Args:
            value: Target BER value
        """
        self.__BERf = value

    @property
    def Af(self) -> float:
        """Get the pathloss constant.

        Returns:
            float: Pathloss constant (dimensionless, default: 10.0)
        """
        return self.__Af

    @Af.setter
    def Af(self, value: float) -> None:
        """Set the pathloss constant.

        Args:
            value: Pathloss constant value
        """
        self.__Af = value

    @property
    def Ef(self) -> float:
        """Get the pathloss exponent.

        Returns:
            float: Pathloss exponent (dimensionless, default: 3.0)
        """
        return self.__Ef

    @Ef.setter
    def Ef(self, value: float) -> None:
        """Set the pathloss exponent.

        Args:
            value: Pathloss exponent value
        """
        self.__Ef = value

    @property
    def R_awgn(self) -> float:
        """Get the normalized AWGN noise power.

        Returns:
            float: Normalized AWGN noise power in dBm (default: -203.975 dBm)
        """
        return self.__R_awgn

    @R_awgn.setter
    def R_awgn(self, value: float) -> None:
        """Set the normalized AWGN noise power.

        Args:
            value: AWGN noise power value in dBm
        """
        self.__R_awgn = value

    @property
    def pif(self) -> float:
        """Get the received SNR discrepancy.

        The SNR discrepancy from the continuous input memoryless channel's capacity
        at the target BER, calculated as:

        .. math::
            pif = -1.5 \\log_2^{-1}(5 \\cdot BERf)

        Returns:
            float: SNR discrepancy value

        Note:
            This value is automatically calculated from the target BER.
        """
        return self.__pif

    @pif.setter
    def pif(self, value: float) -> None:
        """Set the SNR discrepancy value.

        Args:
            value: SNR discrepancy value
        """
        self.__pif = value

    @property
    def N_rf(self) -> int:
        """Get the number of cells using this femtocell.

        Returns:
            int: Number of RF cells (default: 1)
        """
        return self.__N_rf

    @N_rf.setter
    def N_rf(self, value: int) -> None:
        """Set the number of cells using this femtocell.

        Args:
            value: Number of RF cells
        """
        self.__N_rf = value

    @property
    def nFactor_rf(self) -> float:
        """Get the RF constant.

        Returns:
            float: RF constant value (dimensionless, default: 0.5)
        """
        return self.__nFactor_rf

    @nFactor_rf.setter
    def nFactor_rf(self, value: float) -> None:
        """Set the RF constant.

        Args:
            value: RF constant value
        """
        self.__nFactor_rf = value

    @property
    def A(self) -> float:
        """Get the Rayleigh distributed channel gain.

        Returns:
            float: Rayleigh channel gain (dimensionless, default: 1.0)
        """
        return self.__A

    @A.setter
    def A(self, value: float) -> None:
        """Set the Rayleigh distributed channel gain.

        Args:
            value: Channel gain value
        """
        self.__A = value
