"""
Standardized Residual Sum of Squares (STRESS) Index
===================================================

Define the *Kruskal's Standardized Residual Sum of Squares (:math:`STRESS`)*
index:

-   :func:`colour.index_stress_Garcia2007`: :math:`STRESS` index computation
    according to *García, Huertas, Melgosa and Cui (2007)* method.
-   :func:`colour.index_stress`: *lightness* :math:`STRESS` index computation
    using the specified method.

References
----------
-   :cite:`Garcia2007` : García, P. A., Huertas, R., Melgosa, M., & Cui, G.
    (2007). Measurement of the relationship between perceived and computed
    color differences. Journal of the Optical Society of America A, 24(7),
    1823. doi:10.1364/JOSAA.24.001823
"""

from __future__ import annotations

import typing

import numpy as np

from colour.algebra import sdiv, sdiv_mode

if typing.TYPE_CHECKING:
    from colour.hints import ArrayLike, Literal, NDArrayFloat

from colour.utilities import CanonicalMapping, as_float, as_float_array, validate_method

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

__all__ = [
    "index_stress_Garcia2007",
    "INDEX_STRESS_METHODS",
    "index_stress",
]


def index_stress_Garcia2007(d_E: ArrayLike, d_V: ArrayLike) -> NDArrayFloat:
    """
    Compute the *Kruskal's Standardized Residual Sum of Squares
    (:math:`STRESS`)* index according to the *García, Huertas, Melgosa and
    Cui (2007)* method.

    Parameters
    ----------
    d_E
        Computed colour difference array :math:`\\Delta E`.
    d_V
        Computed colour difference array :math:`\\Delta V`.

    Returns
    -------
    :class:`numpy.ndarray`
        :math:`STRESS` index.

    References
    ----------
    :cite:`Garcia2007`

    Examples
    --------
    >>> d_E = np.array([2.0425, 2.8615, 3.4412])
    >>> d_V = np.array([1.2644, 1.2630, 1.8731])
    >>> index_stress_Garcia2007(d_E, d_V)  # doctest: +ELLIPSIS
    0.1211709...
    """

    d_E = as_float_array(d_E)
    d_V = as_float_array(d_V)

    with sdiv_mode():
        F_1 = sdiv(np.sum(d_E**2), np.sum(d_E * d_V))

        stress = np.sqrt(sdiv(np.sum((d_E - F_1 * d_V) ** 2), np.sum(F_1**2 * d_V**2)))

    return as_float(stress)


INDEX_STRESS_METHODS: CanonicalMapping = CanonicalMapping(
    {
        "Garcia 2007": index_stress_Garcia2007,
    }
)
INDEX_STRESS_METHODS.__doc__ = """
Supported *Standardized Residual Sum of Squares* (*STRESS*) index
computation methods.

References
----------
:cite:`Garcia2007`
"""


def index_stress(
    d_E: ArrayLike,
    d_V: ArrayLike,
    method: Literal["Garcia 2007"] | str = "Garcia 2007",
) -> NDArrayFloat:
    """
    Compute *Kruskal's Standardized Residual Sum of Squares*
    (:math:`STRESS`) index using the specified method

    Parameters
    ----------
    d_E
        Computed colour difference array :math:`\\Delta E`.
    d_V
        Computed colour difference array :math:`\\Delta V`.
    method
        Computation method.

    Returns
    -------
    :class:`numpy.ndarray`
        :math:`STRESS` index.

    References
    ----------
    :cite:`Garcia2007`

    Examples
    --------
    >>> d_E = np.array([2.0425, 2.8615, 3.4412])
    >>> d_V = np.array([1.2644, 1.2630, 1.8731])
    >>> index_stress(d_E, d_V)  # doctest: +ELLIPSIS
    0.1211709...
    """

    method = validate_method(method, tuple(INDEX_STRESS_METHODS))

    function = INDEX_STRESS_METHODS[method]

    return function(d_E, d_V)
