"""
Demonstrate contrast sensitivity computations.

This module demonstrates contrast sensitivity function computations using
*Barten (1999)* method, including spatial frequency optimization and minimum
detectable contrast calculations for various viewing conditions.
"""

from pprint import pprint

import numpy as np

import colour
from colour.hints import ArrayLike, NDArrayFloat
from colour.plotting import colour_style, plot_single_function
from colour.utilities import as_float, as_float_array, message_box

message_box("Contrast Sensitivity Computations")

colour_style()

message_box(
    'Compute the contrast sensitivity for a spatial frequency "u" of 4, an '
    'angular size "X_0" of 60 and a retinal illuminance "E" of 65 using '
    '"Barten (1999)" method.'
)
pprint(colour.contrast_sensitivity_function(u=4, X_0=60, E=65))
pprint(colour.contrast.contrast_sensitivity_function_Barten1999(u=4, X_0=60, E=65))

print("\n")

message_box(
    "Compute the minimum detectable contrast with the assumed conditions "
    'for UHDTV applications as given in the "ITU-R BT.2246-4" "Figure 31" and '
    'using "Barten (1999)" method.'
)

settings_BT2246 = {
    "k": 3.0,
    "T": 0.1,
    "X_max": 12,
    "N_max": 15,
    "n": 0.03,
    "p": 1.2274 * 10**6,
    "phi_0": 3 * 10**-8,
    "u_0": 7,
}


def maximise_spatial_frequency(L: ArrayLike) -> NDArrayFloat:
    """
    Maximise the spatial frequency :math:`u` for given luminance value.

    Parameters
    ----------
    L
        Luminance value at which to maximize the spatial frequency :math:`u`.

    Returns
    -------
    :class:`np.float` or :class:`numpy.ndarray`
        Maximised spatial frequency :math:`u`.
    """

    from scipy.optimize import fmin  # noqa: PLC0415

    L = as_float_array(L)

    maximised_spatial_frequency = []
    X_0 = 60
    for L_v in L:
        d = colour.contrast.pupil_diameter_Barten1999(L_v, X_0)
        sigma = colour.contrast.sigma_Barten1999(0.5 / 60, 0.08 / 60, d)
        E = colour.contrast.retinal_illuminance_Barten1999(L_v, d, True)
        maximised_spatial_frequency.append(
            fmin(
                lambda x: (
                    -colour.contrast.contrast_sensitivity_function_Barten1999(
                        u=x,
                        sigma=sigma,  # noqa: B023
                        X_0=X_0,
                        E=E,  # noqa: B023
                        **settings_BT2246,
                    )
                ).item(),
                [0],
                disp=False,
            )[0]
        )

    return as_float(maximised_spatial_frequency)


L = np.logspace(np.log10(0.01), np.log10(100), 100)
X_0 = Y_0 = 60
d = colour.contrast.barten1999.pupil_diameter_Barten1999(L, X_0, Y_0)
sigma = colour.contrast.barten1999.sigma_Barten1999(0.5 / 60, 0.08 / 60, d)
E = colour.contrast.barten1999.retinal_illuminance_Barten1999(L, d)
u = maximise_spatial_frequency(L)

pprint(
    1
    / colour.contrast_sensitivity_function(
        u=u, sigma=sigma, E=E, X_0=X_0, Y_0=Y_0, **settings_BT2246
    )
    * 2
    * (1 / 1.27)
)
pprint(
    1
    / colour.contrast.contrast_sensitivity_function_Barten1999(
        u=u, sigma=sigma, E=E, X_0=X_0, Y_0=Y_0, **settings_BT2246
    )
    * 2
    * (1 / 1.27)
)

plot_single_function(
    lambda x: (  # noqa: ARG005
        1
        / colour.contrast.contrast_sensitivity_function_Barten1999(
            u=u, sigma=sigma, E=E, X_0=X_0, Y_0=Y_0, **settings_BT2246
        )
        * 2
        * (1 / 1.27)
    ),
    samples=L,
    log_x=10,
    **{  # pyright: ignore
        "title": "Examples of HVS Minimum Detectable Contrast Characteristics",
        "x_label": "Luminance ($cd/m^2$)",
        "y_label": "Minimum Detectable Contrast",
        "axes.grid.which": "both",
    },
)
