"""VLed (Visible Light LED) access point class."""

import numpy as np
import math as m
from .access_point import AccessPoint


class VLed(AccessPoint):
    """Visible Light LED (VLed) access point for VLC communication.

    VLed represents a LED-based access point that transmits data using visible light.
    It extends AccessPoint with optical transmission parameters including LED array
    configuration, optical power, and beam characteristics.

    The class automatically calculates derived parameters such as total power and
    Lambertian emission order based on the LED configuration.

    Class Attributes:
        numberOfVLeds (int): Counter tracking total number of VLed instances created

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

        VLed-specific:
            nLedsX (int): Number of LEDs in X direction (rows)
            nLedsY (int): Number of LEDs in Y direction (columns)
            ledPower (float): Power per LED in milliwatts
            theta (float): Semi-angle at half illumination in degrees
            numberOfLeds (int): Total LEDs in array (read-only)
            totalPower (float): Total optical power in milliwatts
            ml (float): Lambertian emission order (read-only)

    Example:
        Creating a VLed access point::

            # Create 2x2 LED array at ceiling center
            # Position: (5m, 5m, 3m)
            # Each LED: 20mW power
            # Beam angle: 60 degrees semi-angle
            vled = VLed(x=5.0, y=5.0, z=3.0,
                       nLedsX=2, nLedsY=2,
                       ledPower=20, theta=60)

            # Configure TDM parameters
            vled.sliceTime = 0.1  # 100ms per slice
            vled.slicesInFrame = 10  # 10 slices per frame
            vled.B = 5e5  # 500 kHz bandwidth

            # Total power is automatically calculated
            print(f\"Total power: {vled.totalPower}mW\")  # 80mW (4 LEDs * 20mW)
            print(f\"Lambertian order: {vled.ml}\")

    Note:
        - ID is automatically assigned incrementally starting from 0
        - Lambertian emission order ml is calculated as -log10(2)/log10(cos(theta))
        - totalPower equals nLedsX * nLedsY * ledPower
        - Typical theta values range from 30-70 degrees for indoor VLC
    """

    numberOfVLeds = 0

    def __init__(
        self,
        x: float,
        y: float,
        z: float,
        nLedsX: int,
        nLedsY: int,
        ledPower: float,
        theta: float,
    ) -> None:
        """Initialize a VLed access point with optical parameters.

        Creates a VLed with specified position and LED array configuration.
        Automatically calculates total power and Lambertian emission order.

        Args:
            x: X-coordinate position in meters
            y: Y-coordinate position in meters
            z: Z-coordinate position in meters (typically ceiling height)
            nLedsX: Number of LEDs in X direction (rows in the array)
            nLedsY: Number of LEDs in Y direction (columns in the array)
            ledPower: Optical power per LED in milliwatts (mW)
            theta: Semi-angle at half illumination in degrees

        Example::

            # Create 4x4 LED panel at room center ceiling
            vled = VLed(x=5.0, y=5.0, z=3.0,
                       nLedsX=4, nLedsY=4,
                       ledPower=50, theta=60)

        Note:
            - Total LEDs = nLedsX * nLedsY
            - Total power = numberOfLeds * ledPower
            - Lambertian order ml = -log10(2)/log10(cos(theta))
            - VLed ID is auto-assigned from numberOfVLeds class counter
        """
        AccessPoint.__init__(self, x, y, z)
        self.__nLedsX = nLedsX
        self.__nLedsY = nLedsY
        self.__ledPower = ledPower
        self.__theta = theta
        self._state = AccessPoint.stateap.IDLE

        self.__numberOfLeds = self.__nLedsX * self.__nLedsY
        self.__totalPower = self.__numberOfLeds * self.__ledPower
        self.__ml = -m.log10(2) / m.log10(m.cos(m.radians(theta)))

        self._ID = VLed.numberOfVLeds
        VLed.numberOfVLeds += 1
        self._position = np.array([x, y, z])

    @property
    def nLedsX(self) -> int:
        """Get the number of LEDs in X direction (rows).

        Returns:
            int: Number of LED rows in the array
        """
        return self.__nLedsX

    @nLedsX.setter
    def nLedsX(self, value: int) -> None:
        """Set the number of LEDs in X direction (rows).

        Args:
            value: Number of LED rows
        """
        self.__nLedsX = value

    @property
    def nLedsY(self) -> int:
        """Get the number of LEDs in Y direction (columns).

        Returns:
            int: Number of LED columns in the array
        """
        return self.__nLedsY

    @nLedsY.setter
    def nLedsY(self, value: int) -> None:
        """Set the number of LEDs in Y direction (columns).

        Args:
            value: Number of LED columns
        """
        self.__nLedsY = value

    @property
    def ledPower(self) -> float:
        """Get the optical power per individual LED.

        Returns:
            float: Power per LED in milliwatts (mW)
        """
        return self.__ledPower

    @ledPower.setter
    def ledPower(self, value: float) -> None:
        """Set the optical power per individual LED.

        Args:
            value: Power per LED in milliwatts (mW)
        """
        self.__ledPower = value

    @property
    def theta(self) -> float:
        """Get the semi-angle at half illumination.

        Theta defines the beam width of the LED. It is the angle from the optical axis
        at which the luminous intensity drops to half of its maximum value.

        Returns:
            float: Semi-angle in degrees

        Note:
            Typical values for indoor VLC range from 30-70 degrees.
            Smaller angles create more focused beams with higher intensity at center.
        """
        return self.__theta

    @theta.setter
    def theta(self, value: float) -> None:
        """Set the semi-angle at half illumination.

        Args:
            value: Semi-angle in degrees
        """
        self.__theta = value

    @property
    def numberOfLeds(self) -> int:
        """Get the total number of LEDs in this VLed array.

        Calculated as nLedsX * nLedsY.

        Returns:
            int: Total number of LEDs in the array
        """
        return self.__numberOfLeds

    @property
    def totalPower(self) -> float:
        """Get the total optical power of this VLed array.

        Calculated as numberOfLeds * ledPower.

        Returns:
            float: Total optical power in milliwatts (mW)

        Example::

            vled = VLed(5, 5, 3, nLedsX=4, nLedsY=4, ledPower=50, theta=60)
            # totalPower = 4 * 4 * 50 = 800 mW
        """
        return self.__totalPower

    @totalPower.setter
    def totalPower(self, value: float):
        """Set the total optical power of this VLed array.

        Args:
            value: Total optical power in milliwatts (mW)
        """
        self.__totalPower = value

    @property
    def ml(self) -> float:
        """Get the Lambertian emission order.

        The Lambertian order characterizes the directionality of the LED emission pattern.
        Higher values indicate more directional (focused) emission.

        The formula is:

        .. math::
            ml = -\\frac{\\log_{10} 2}{\\log_{10} (\\cos(\\theta))}

        Returns:
            float: Lambertian emission order (dimensionless)

        Note:
            - theta=60° → ml ≈ 1 (wide beam)
            - theta=30° → ml ≈ 3.3 (narrow beam)
            - Higher ml means more concentrated light at center
        """
        return self.__ml
