"""
This module is under development and still not in
use.
"""
from typing import Union


class FrameAdapter:
    """
    The adapter.
    """

    def __init__(
        self,
        frame: 'Frame',
        # # TODO: Maybe 'RenderContext' instead (?)
        # opengl_context: 'moderngl.Context'
    ):
        self.frame: 'Frame' = frame
        """
        The frame to be adapted.
        """
        # self.opengl_context: 'moderngl.Context' = opengl_context
        # """
        # The context itself.
        # """

    """
    Operations here below
    """
    def resize_with_padding(
        self,
        size: tuple[int, int]
    ) -> 'FrameAdapter':
        self.frame.pending_operations.append(ResizeWithPaddingOperation(size))

        return self

    def to_gpu(
        self,
        render_context: 'RenderContext'
    ):
        return self._resolve(
            backend = 'gpu',
            render_context = render_context
        )

    def to_cpu(
        self
    ):
        return self._resolve(
            backend = 'cpu'
        )

    def _resolve(
        self,
        # TODO: This 'backend' should be more strict
        backend: str,
        render_context: Union['RenderContext', None]
    ):
        if backend not in ['cpu', 'gpu']:
            raise Exception('The "backend" provided is not valid.')
        
        resource = self.frame.resource

        from yta_editor_frame.frame.resource.identifier import FrameResourceIdentifier

        if (
            backend == 'gpu' and
            (
                FrameResourceIdentifier.is_gpu_render_target(self.frame.resource) or
                FrameResourceIdentifier.is_gpu(self.frame.resource)
            )
        ):
            texture = (
                self.frame.resource.frame.texture
                if FrameResourceIdentifier.is_gpu_render_target(self.frame.resource) else
                self.frame.resource.frame
            )
        elif backend == 'gpu':
            # 1. Get texture from pool
            texture = render_context._render_resources.texture.acquire(
                width = self.frame.width,
                height = self.frame.height,
                number_of_components = 4,
                dtype = 'f1'
            )
            # 2. Get the numpy array from frame
            numpy_array = (
                self.frame.resource.frame
                if FrameResourceIdentifier.is_cpu(self.frame.resource) else
                self.frame.resource.frame.to_ndarray(format = 'rgba')
            )
            # 3. Write numpy array into texture
            texture.write(numpy_array)
        elif (
            backend == 'cpu' and
            (
                FrameResourceIdentifier.is_cpu_av_videoframe(self.frame.resource) or
                FrameResourceIdentifier.is_cpu(self.frame.resource)
            )
        ):
            numpy_array = (
                self.frame.resource.frame
                if FrameResourceIdentifier.is_cpu(self.frame.resource) else
                self.frame.resource.frame.to_ndarray(format = 'rgba')
            )
        else:
            # 1. Get texture
            texture = (
                self.frame.resource.frame
                if FrameResourceIdentifier.is_gpu(self.frame.resource) else
                self.frame.resource.frame.texture
            )
            # 2. Read as numpy array
            numpy_array = texture.read()

        # aplicar pipeline
        for pending_operation in self.frame.pending_operations:
            if backend == 'gpu':
                texture = pending_operation.apply_gpu(
                    frame = texture,
                    render_context = render_context
                )
            else:
                numpy_array = pending_operation.apply_cpu(
                    frame = numpy_array
                )

        return (
            texture
            if backend == 'gpu' else
            numpy_array
        )

class FrameToBeAdapted:
    """
    Class to wrap the functionality that adapts the
    frames.
    """

    def __init__(
        self,
        frame: 'Frame'
    ):
        self.frame: 'Frame' = frame
        """
        The frame to be adapted.
        """
        self.operations_pending = []
        """
        The operations that are pending to be done.
        """