from yta_validation.parameter import ParameterValidator

import numpy as np


class _NodeCPU:
    """
    *For internal use only*
    
    *Abstract class*

    An abstract class to handle the mandatory and
    optional parameters that can be used in the node.
    """

    mandatory_inputs: list[str] = None
    """
    The name of the inputs that are mandatory to be able
    to use the node.
    """
    optional_inputs: list[str] = None
    """
    The name of the inputs that will be used in the node
    if provided but are not mandatory to make the node
    work properly.
    """

    # Make the children validate that the mandatory and
    # optional parameters are defined
    def __init_subclass__(
        cls,
        **kwargs
    ):
        super().__init_subclass__(**kwargs)

        if (
            cls.mandatory_inputs is None or
            cls.optional_inputs is None
        ):
            raise Exception('The mandatory and optional inputs are not defined or maybe only one is defined.')

        ParameterValidator.validate_mandatory_list_of_string('cls.mandatory_inputs', cls.mandatory_inputs)
        ParameterValidator.validate_mandatory_list_of_string('cls.optional_inputs', cls.optional_inputs)

        overlap = set(cls.mandatory_inputs) & set(cls.optional_inputs)
        if overlap:
            raise Exception('Same key defined twice for both mandatory and optional parameters.')
        
    def _validate_inputs(
        self,
        inputs: dict[str, np.ndarray]
    ) -> None:
        """
        *For internal use only*

        Validate the `inputs` provided and check if all the
        mandatory ones are provided and if the optionals,
        if also provided, are valid.

        This method will raise an exception if some inputs
        are invalid or missing. An optional input is accepted
        if its key doesn't exist or if the value is None.
        """
        # 1. Mandatory exist and are valid
        for name in self.mandatory_inputs:
            if name not in inputs:
                raise Exception(f"The mandatory input '{name}' was not provided.")
            
            ParameterValidator.validate_mandatory_instance_of(name, inputs[name], np.ndarray)

        # 2. Optional, if existing, are valid or None
        for name in self.optional_inputs:
            if name not in inputs:
                continue

            ParameterValidator.validate_instance_of(name, inputs[name], np.ndarray)