"""
OpenColorIO Processing
======================

Defines the object for *OpenColorIO* processing:

-   :func:`colour.io.process_image_OpenColorIO`
"""

from __future__ import annotations

import numpy as np

from colour.io import as_3_channels_image
from colour.hints import Any, ArrayLike, FloatingOrNDArray
from colour.utilities import as_float_array, as_float_scalar, required

__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__ = [
    "process_image_OpenColorIO",
]


# TODO: Reinstate coverage and doctests when "Pypi" wheel compatible with "ARM"
#  on "macOS" is released.


@required("OpenColorIO")
def process_image_OpenColorIO(
    a: ArrayLike, *args: Any, **kwargs: Any
) -> FloatingOrNDArray:  # pragma: no cover
    """
    Process given image data with *OpenColorIO*.

    Parameters
    ----------
    a
        Image data to process with *OpenColorIO*.

    Other Parameters
    ----------------
    config
        *OpenColorIO* config to use for processing. If not defined, the
        *OpenColorIO* set defined by the ``$OCIO`` environment variable is
        used.
    args
        Arguments for `Config.getProcessor` method.
        See https://opencolorio.readthedocs.io/en/latest/api/config.html for
        more information.

    Returns
    -------
    :class:`numpy.ndarray`
        Processed image data.

    Examples
    --------
    >>> import os
    >>> import PyOpenColorIO as ocio  # doctest: +SKIP
    >>> from colour.utilities import full
    >>> config = os.path.join(
    ...     os.path.dirname(__file__),
    ...     "tests",
    ...     "resources",
    ...     "config-aces-reference.ocio.yaml",
    ... )
    >>> a = 0.18
    >>> process_image_OpenColorIO(  # doctest: +SKIP
    ...     a, "ACES - ACES2065-1", "ACES - ACEScct", config=config
    ... )
    0.4135884...
    >>> a = np.array([0.18])
    >>> process_image_OpenColorIO(  # doctest: +SKIP
    ...     a, "ACES - ACES2065-1", "ACES - ACEScct", config=config
    ... )
    array([ 0.4135884...])
    >>> a = np.array([0.18, 0.18, 0.18])
    >>> process_image_OpenColorIO(  # doctest: +SKIP
    ...     a, "ACES - ACES2065-1", "ACES - ACEScct", config=config
    ... )
    array([ 0.4135884...,  0.4135884...,  0.4135884...])
    >>> a = np.array([[0.18, 0.18, 0.18]])
    >>> process_image_OpenColorIO(  # doctest: +SKIP
    ...     a, "ACES - ACES2065-1", "ACES - ACEScct", config=config
    ... )
    array([[ 0.4135884...,  0.4135884...,  0.4135884...]])
    >>> a = np.array([[[0.18, 0.18, 0.18]]])
    >>> process_image_OpenColorIO(  # doctest: +SKIP
    ...     a, "ACES - ACES2065-1", "ACES - ACEScct", config=config
    ... )
    array([[[ 0.4135884...,  0.4135884...,  0.4135884...]]])
    >>> a = full([4, 2, 3], 0.18)
    >>> process_image_OpenColorIO(  # doctest: +SKIP
    ...     a, "ACES - ACES2065-1", "ACES - ACEScct", config=config
    ... )
    array([[[ 0.4135884...,  0.4135884...,  0.4135884...],
            [ 0.4135884...,  0.4135884...,  0.4135884...]],
    <BLANKLINE>
           [[ 0.4135884...,  0.4135884...,  0.4135884...],
            [ 0.4135884...,  0.4135884...,  0.4135884...]],
    <BLANKLINE>
           [[ 0.4135884...,  0.4135884...,  0.4135884...],
            [ 0.4135884...,  0.4135884...,  0.4135884...]],
    <BLANKLINE>
           [[ 0.4135884...,  0.4135884...,  0.4135884...],
            [ 0.4135884...,  0.4135884...,  0.4135884...]]])
    >>> process_image_OpenColorIO(  # doctest: +SKIP
    ...     a,
    ...     "ACES - ACES2065-1",
    ...     "Display - sRGB",
    ...     "Output - SDR Video - ACES 1.0",
    ...     ocio.TRANSFORM_DIR_FORWARD,
    ...     config=config,
    ... )
    array([[[ 0.3559542...,  0.3559542...,  0.3559542...],
            [ 0.3559542...,  0.3559542...,  0.3559542...]],
    <BLANKLINE>
           [[ 0.3559542...,  0.3559542...,  0.3559542...],
            [ 0.3559542...,  0.3559542...,  0.3559542...]],
    <BLANKLINE>
           [[ 0.3559542...,  0.3559542...,  0.3559542...],
            [ 0.3559542...,  0.3559542...,  0.3559542...]],
    <BLANKLINE>
           [[ 0.3559542...,  0.3559542...,  0.3559542...],
            [ 0.3559542...,  0.3559542...,  0.3559542...]]])
    """

    import PyOpenColorIO as ocio

    config = kwargs.get("config")
    config = (
        ocio.Config.CreateFromEnv()
        if config is None
        else ocio.Config.CreateFromFile(config)
    )

    a = as_float_array(a)
    shape, dtype = a.shape, a.dtype
    a = as_3_channels_image(a).astype(np.float32)

    height, width, channels = a.shape

    processor = config.getProcessor(*args).getDefaultCPUProcessor()

    image_desc = ocio.PackedImageDesc(a, width, height, channels)

    processor.apply(image_desc)

    b = image_desc.getData().reshape([height, width, channels]).astype(dtype)

    if len(shape) == 0:
        return as_float_scalar(np.squeeze(b)[0])
    elif shape[-1] == 1:
        return np.reshape(b[..., 0], shape)
    else:
        return np.reshape(b, shape)
