"""
Luminous Efficiency Functions Spectral Distributions
====================================================

Defines the luminous efficiency functions computation related objects.

References
----------
-   :cite:`Wikipedia2005d` : Wikipedia. (2005). Mesopic weighting function.
    Retrieved June 20, 2014, from
    http://en.wikipedia.org/wiki/Mesopic_vision#Mesopic_weighting_function
"""

from __future__ import annotations

from colour.colorimetry import (
    SDS_LEFS_PHOTOPIC,
    SDS_LEFS_SCOTOPIC,
    SpectralDistribution,
    SpectralShape,
)
from colour.colorimetry.datasets.lefs import DATA_MESOPIC_X
from colour.hints import (
    Floating,
    FloatingOrArrayLike,
    FloatingOrNDArray,
    Literal,
    Optional,
    Union,
    cast,
)
from colour.utilities import closest, optional, validate_method

__author__ = "Colour Developers"
__copyright__ = "Copyright 2013 Colour Developers"
__license__ = "New BSD License - https://opensource.org/licenses/BSD-3-Clause"
__maintainer__ = "Colour Developers"
__email__ = "colour-developers@colour-science.org"
__status__ = "Production"

__all__ = [
    "mesopic_weighting_function",
    "sd_mesopic_luminous_efficiency_function",
]


def mesopic_weighting_function(
    wavelength: FloatingOrArrayLike,
    L_p: Floating,
    source: Union[Literal["Blue Heavy", "Red Heavy"], str] = "Blue Heavy",
    method: Union[Literal["MOVE", "LRC"], str] = "MOVE",
    photopic_lef: Optional[SpectralDistribution] = None,
    scotopic_lef: Optional[SpectralDistribution] = None,
) -> FloatingOrNDArray:
    """
    Calculate the mesopic weighting function factor :math:`V_m` at given
    wavelength :math:`\\lambda` using the photopic luminance :math:`L_p`.

    Parameters
    ----------
    wavelength
        Wavelength :math:`\\lambda` to calculate the mesopic weighting function
        factor.
    L_p
        Photopic luminance :math:`L_p`.
    source
        Light source colour temperature.
    method
        Method to calculate the weighting factor.
    photopic_lef
        :math:`V(\\lambda)` photopic luminous efficiency function, default to
        the *CIE 1924 Photopic Standard Observer*.
    scotopic_lef
        :math:`V^\\prime(\\lambda)` scotopic luminous efficiency function,
        default to the *CIE 1951 Scotopic Standard Observer*.

    Returns
    -------
    :class:`numpy.floating` or :class:`numpy.ndarray`
        Mesopic weighting function factor :math:`V_m`.

    References
    ----------
    :cite:`Wikipedia2005d`

    Examples
    --------
    >>> mesopic_weighting_function(500, 0.2)  # doctest: +ELLIPSIS
    0.7052200...
    """

    photopic_lef = cast(
        SpectralDistribution,
        optional(
            photopic_lef,
            SDS_LEFS_PHOTOPIC["CIE 1924 Photopic Standard Observer"],
        ),
    )

    scotopic_lef = cast(
        SpectralDistribution,
        optional(
            scotopic_lef,
            SDS_LEFS_SCOTOPIC["CIE 1951 Scotopic Standard Observer"],
        ),
    )

    source = validate_method(
        source,
        ["Blue Heavy", "Red Heavy"],
        '"{0}" light source colour temperature is invalid, '
        "it must be one of {1}!",
    )
    method = validate_method(method, ["MOVE", "LRC"])

    mesopic_x_luminance_values = sorted(DATA_MESOPIC_X.keys())
    index = mesopic_x_luminance_values.index(
        closest(mesopic_x_luminance_values, L_p)
    )
    x = DATA_MESOPIC_X[mesopic_x_luminance_values[index]][source][method]

    V_m = (1 - x) * scotopic_lef[wavelength] + x * photopic_lef[wavelength]

    return V_m


def sd_mesopic_luminous_efficiency_function(
    L_p: Floating,
    source: Union[Literal["Blue Heavy", "Red Heavy"], str] = "Blue Heavy",
    method: Union[Literal["MOVE", "LRC"], str] = "MOVE",
    photopic_lef: Optional[SpectralDistribution] = None,
    scotopic_lef: Optional[SpectralDistribution] = None,
) -> SpectralDistribution:
    """
    Return the mesopic luminous efficiency function :math:`V_m(\\lambda)` for
    given photopic luminance :math:`L_p`.

    Parameters
    ----------
    L_p
        Photopic luminance :math:`L_p`.
    source
        Light source colour temperature.
    method
        Method to calculate the weighting factor.
    photopic_lef
        :math:`V(\\lambda)` photopic luminous efficiency function, default to
        the *CIE 1924 Photopic Standard Observer*.
    scotopic_lef
        :math:`V^\\prime(\\lambda)` scotopic luminous efficiency function,
        default to the *CIE 1951 Scotopic Standard Observer*.

    Returns
    -------
    :class:`colour.SpectralDistribution`
        Mesopic luminous efficiency function :math:`V_m(\\lambda)`.

    References
    ----------
    :cite:`Wikipedia2005d`

    Examples
    --------
    >>> from colour.utilities import numpy_print_options
    >>> with numpy_print_options(suppress=True):
    ...     sd_mesopic_luminous_efficiency_function(0.2)  # doctest: +ELLIPSIS
    SpectralDistribution([[ 380.        ,    0.000424 ...],
                          [ 381.        ,    0.0004781...],
                          [ 382.        ,    0.0005399...],
                          [ 383.        ,    0.0006122...],
                          [ 384.        ,    0.0006961...],
              
            [ 385.        ,    0.0007929...],
                          [
 386.        ,    0.000907 ...],
                          [ 387.        ,    0.0010389...],
                          [ 388.        ,    0.0011923...],
                          [ 389.        ,    0.0013703...],
                          [ 390.        ,    0.0015771...],
                          [ 391.        ,    0.0018167...],
                          [ 392.        ,    0.0020942...],
                          [ 393.        ,    0.0024160...],
                          [ 394.        ,    0.0027888...],
                          [ 395.        ,    0.0032196...],
                          [ 396.        ,    0.0037222...],
                          [ 397.        ,    0.0042957...],
                          [ 398.        ,    0.0049531...],
                          [ 399.        ,    0.0057143...],
                          [ 400.        ,    0.0065784...],
                          [ 401.        ,    0.0075658...],
                          [ 402.        ,    0.0086912...],
                          [ 403.        ,    0.0099638...],
                          [ 404.        ,    0.0114058...],
                          [ 405.        ,    0.0130401...],
                          [ 406.        ,    0.0148750...],
                          [ 407.        ,    0.0169310...],
                          [ 408.        ,    0.0192211...],
                          [ 409.        ,    0.0217511...],
                          [ 410.        ,    0.0245342...],
                          [ 411.        ,    0.0275773...],
                          [ 412.        ,    0.0309172...],
                          [ 413.        ,    0.0345149...],
                          [ 414.        ,    0.0383998...],
                          [ 415.        ,    0.0425744...],
                          [ 416.        ,    0.0471074...],
                          [ 417.        ,    0.0519322...],
                          [ 418.        ,    0.0570541...],
                          [ 419.        ,    0.0625466...],
                          [ 420.        ,    0.0683463...],
                          [ 421.        ,    0.0745255...],
                          [ 422.        ,    0.0809440...],
                          [ 423.        ,    0.0877344...],
                          [ 424.        ,    0.0948915...],
                          [ 425.        ,    0.1022731...],
                          [ 426.        ,    0.109877 ...],
                          [ 427.        ,    0.1178421...],
                          [ 428.        ,    0.1260316...],
                          [ 429.        ,    0.1343772...],
                          [ 430.        ,    0.143017 ...],
                          [ 431.        ,    0.1518128...],
                          [ 432.        ,    0.1608328...],
                          [ 433.        ,    0.1700088...],
         