from youtube_autonomous.elements.builder.element_builder import ElementBuilder
from youtube_autonomous.elements.validator.element_parameter_validator import ElementParameterValidator
from youtube_autonomous.elements.builder.enums import Premade
from yta_general_utils.programming.parameter_validator import PythonValidator
from yta_general_utils.programming.parameter_obtainer import ParameterObtainer
from moviepy import VideoFileClip
from typing import Union


class PremadeElementBuilder(ElementBuilder):
    
    @classmethod
    def premade_name_to_class(cls, premade_name: str):
        """
        Returns the corresponding premade class according to the
        provided 'premade_name'. If no premade class found, the
        return will be None.
        """
        valid_name = Premade.get_valid_name(premade_name)

        if not valid_name:
            raise Exception(f'The provided premade name "{premade_name}" is not valid. The valid ones are: {Premade.get_all_names_as_str()}')
        
        return Premade[valid_name].value
    
    @classmethod
    def _build(
        cls,
        element: dict
    ) -> Union[VideoFileClip, None]:
        premade_name = element.keywords
        premade_class = cls.premade_name_to_class(premade_name)

        parameters = cls.get_parameters_from_method(
            method = premade_class().generate,
            element = element,
            parameters_strictly_from_element = ['duration']
        )

        generated = premade_class().generate(**parameters)

        return (
            # If the premade is generated with manim we will only
            # get the filename as return, so we need it as a clip
            VideoFileClip(generated)
            if PythonValidator.is_string(generated) else
            None
        )

    @classmethod
    def build_from_enhancement(
        cls,
        enhancement: dict
    ):
        return cls._build(enhancement)

    @classmethod
    def build_from_segment(
        cls,
        segment: dict
    ):
        return cls._build(segment)

    # TODO: This has been replaced by a new method in ElementBuilder
    # @classmethod
    # def get_building_parameters(
    #     cls,
    #     element: dict,
    #     parameters_to_ignore: list[str],
    #     parameters_not_from_extra: list[str]
    # ):
    #     """
    #     This method extracts the parameters needed for building the text
    #     premade that exist in the 'extra_params' field of the provided
    #     'element' dict, replaces the ones in 'not_extra_parameters' with
    #     the ones in the main 'element' dict and, finally, keeps the only
    #     parameters needed to build the effect and returns them. This means
    #     that only the 'mandatory' or 'optional' parameters to build the
    #     effect, if existing, will be returned extracted from where it was
    #     specified.
    #     """
    #     premade_name = element.keywords
        
    #     ElementParameterValidator.validate_premade_name(premade_name)

    #     premade_class = cls.premade_name_to_class(premade_name)
    #     parameters = ElementBuilder.extract_extra_params(element, premade_class.generate, parameters_to_ignore)

    #     # TODO: What if not extra parameter does not exist in main (?)
    #     for parameter_not_from_extra in parameters_not_from_extra:
    #         parameters[parameter_not_from_extra] = getattr(element, parameter_not_from_extra)
        
    #     actual_parameters = ParameterObtainer.get_parameters_from_method(premade_class.generate)

    #     # We keep only 'mandatory' or 'optional' parameters removing useless
    #     return {
    #         key: value
    #         for key, value in parameters.items()
    #         if (
    #             key in actual_parameters.mandatory_parameters or
    #             key in actual_parameters.optional_parameters
    #         )
    #     }