from yta_editor_nodes.complex.base import _NodeComplex
from yta_editor_parameters.specifications import ParameterSpecification
from typing import Union


class DisplayOverAtNodeComplex(_NodeComplex):
    """
    The `overlay_input` is positioned in the given `position`,
    with the `rotation` and `size` provided, and then put as
    an overlay of the also given `base_input`.

    Information:
    - The scene size is `(1920, 1080)`, so provide the
    `position` parameter according to it. Giving a `(0, 0)`
    means that the center of the `overlay_input` will be in
    that position.
    - The `rotation` is in degrees, where `rotation=90`
    means rotating 90 degrees to the right.
    - The `size` parameter must be provided according to
    the previously mentioned scene size `(1920, 1080)`.

    TODO: This has no inheritance, is special and we need
    to be able to identify it as a valid one.

    Mandatory inputs:
    - `base_input`
    - `overlay_input`

    Optional inputs:
    - `None`

    Parameters:
    - `*x`
    - `*y`
    - `*width`
    - `*height`
    - `*rotation`

    The parameters above are the accepted by this
    node, where `*` means that the parameter is
    mandatory.
    """

    mandatory_inputs = ['base_input', 'overlay_input']
    optional_inputs = []
    parameters_specifications = [
        # TODO: Check if these limits below are ok
        ParameterSpecification(
            name = 'x',
            type = int,
            is_required = True,
            default = int(1920 / 2),
            min = -9999,
            max = 9999
        ),
        ParameterSpecification(
            name = 'y',
            type = int,
            is_required = True,
            default = int(1080 / 2),
            min = -9999,
            max = 9999
        ),
        ParameterSpecification(
            name = 'width',
            type = int,
            is_required = True,
            default = int(1920 / 2),
            min = -9999,
            max = 9999
        ),
        ParameterSpecification(
            name = 'height',
            type = int,
            is_required = True,
            default = int(1080 / 2),
            min = -9999,
            max = 9999
        ),
        ParameterSpecification(
            name = 'rotation',
            type = int,
            is_required = True,
            default = 45,
            min = -360 * 10,
            max = 360 * 10
        )
    ]

    def _instantiate_cpu_and_gpu_processors(
        self,
        opengl_context: Union['moderngl.Context', None]
    ):
        """
        *For internal use only*

        Instantiate the CPU and GPU blenders and return 
        them in that order.

        This method must be implemented by each class.
        """
        from yta_editor_nodes_cpu.complex.display_over_at import DisplayOverAtNodeComplexCPU
        from yta_editor_nodes_gpu.complex.display_over_at import DisplayOverAtNodeComplexGPU

        node_cpu = DisplayOverAtNodeComplexCPU()
        node_gpu = DisplayOverAtNodeComplexGPU(
            opengl_context = opengl_context
        )

        return node_cpu, node_gpu
    
    def _format_parameters(
        self,
        parameters: dict[str, any]
    ) -> dict[str, any]:
        # The 'x' and 'y' exist always
        parameters['position'] = (parameters.pop('x'), parameters.pop('y'))
        # The 'width' and 'height' exist always
        parameters['size'] = (parameters.pop('width'), parameters.pop('height'))
        
        return parameters
    
    """
    I maintain this code below because of the way
    we are handling the optional 'base_input'. I'm
    trying to refactor and simplify everything, but
    I'll keep this code until I confirm this node
    is working perfectly after the refactor.
    """
    # def process(
    #     self,
    #     inputs: Union['np.ndarray', 'moderngl.Texture'],
    #     evaluation_context: EvaluationContext,
    #     output_size: Union[tuple[int, int], None] = None,
    #     do_use_gpu: bool = True,
    #     position: tuple[int, int] = (1920 / 2, 1080 / 2),
    #     size: tuple[int, int] = (1920 / 2, 1080 / 2),
    #     rotation: int = 0
    # ) -> Union['np.ndarray', 'moderngl.Texture']:
    #     """
    #     Put the `overlapy_input` over the `base_input` in
    #     the `position` given and with the `size` and
    #     `rotation` also provided.
    #     """
    #     base_input = inputs['base_input']
    #     overlay_input = inputs['overlay_input']

    #     output_size = (
    #         get_input_size(base_input)
    #         if output_size is None else
    #         output_size
    #     )

    #     processor = self._get_processor(
    #         do_use_gpu = do_use_gpu
    #     )

    #     return processor.process(
    #         inputs = {
    #             'base_input': self._prepare_input(
    #                 input = base_input,
    #                 do_use_gpu = do_use_gpu
    #             ),
    #             'overlay_input': self._prepare_input(
    #                 input = overlay_input,
    #                 do_use_gpu = do_use_gpu
    #             ),
    #         },
    #         evaluation_context = evaluation_context,
    #         output_size = output_size,
    #         position = position,
    #         size = size,
    #         rotation = rotation
    #     )