from youtube_autonomous.segments.enums import EnhancementElementField, EnhancementElementType, EnhancementElementDuration, EnhancementElementStart, EnhancementElementMode
from yta_general_utils.checker.type import variable_is_positive_number
from typing import Union


class SegmentEnhancementValidator:
    """
    This class is to validate the Segment enhancement elements that
    are terms that the user register to enhance (to improve) the
    project video experience.

    These terms need to have a valid structure and that's what we
    check here.
    """
    def is_valid(enhancement_terms):
        """
        We will receive the content of a enhancement term and will raise an
        Exception if some structure element or value is not valid according
        to our rules.

        TODO: Write a little bit more about what we are receiving here.
        """
        # TODO: Maybe refactor the terms to simplify them
        for enhancement_term_key in enhancement_terms:
            enhancement_term = enhancement_terms[enhancement_term_key]
            for type in enhancement_term:
                content = enhancement_term[type]
                if not EnhancementElementType.is_valid(type):
                    raise Exception('Enhancement element type "' + type + '" not accepted.')

                # Lets check values
                keywords = content.get(EnhancementElementField.KEYWORDS.value)
                filename = content.get(EnhancementElementField.FILENAME.value)
                url = content.get(EnhancementElementField.URL.value)
                start = content.get(EnhancementElementField.START.value)
                mode = content.get(EnhancementElementField.MODE.value)
                duration = content.get(EnhancementElementField.DURATION.value)

                if not keywords and not filename and not url:
                    raise Exception('No "keywords" nor "filename" nor "url" provided.')
                
                # TODO: Search for the element with 'keywords' to check that it
                # doesn't exist (or it does)
                # TODO: Check that provided 'filename' is a valid file and the
                # type is appropriate for the type
                # TODO: Check that the provided 'url' is valid, available and
                # suitable for the type we want
                
                if type == EnhancementElementType.MEME.value and not keywords:
                    raise Exception(f'No "keywords" provided when necessary for the "{EnhancementElementType.MEME.value}" type.')

                start_values = EnhancementElementStart.get_all_values()
                if start and start not in start_values and not variable_is_positive_number(start):
                    
                    raise Exception(f'No valid "start" value provided. Must be one of these "{EnhancementElementStart.get_all_values_as_str()}" or a valid positive number (including 0).')

                duration_values = EnhancementElementDuration.get_all_values()
                if duration and duration not in duration_values and not variable_is_positive_number(duration):
                    raise Exception(f'No valid "duration" value provided. Must be one of these "{EnhancementElementDuration.get_all_values_as_str()}" or a valid positive number (including 0).')

                mode_values = EnhancementElementMode.get_all_values()
                if mode and mode not in mode_values:
                    raise Exception(f'No valid "mode" value provided. Must be one of these "{EnhancementElementMode.get_all_values_as_str()}".')
                
    @classmethod
    def validate_type(cls, type: Union[EnhancementElementType, str]):
        """
        This method validates if the provided 'type' parameter is an
        EnhancementElementType enum or if it is a valid string value 
        of a EnhancementElementType enum.

        This method will raise an Exception if any of the rules are 
        not fit.
        """
        if not type:
            raise Exception('No "type" provided.')
        
        if not isinstance(type, (EnhancementElementType, str)):
            raise Exception(f'The "type" parameter provided {type} is not an EnhancementElementType nor a string.')
        
        if isinstance(type, str):
            if not EnhancementElementType.is_valid(type):
                raise Exception(f'The "type" parameter provided {type} is not a valid EnhancementElementType value.')
            
            type = EnhancementElementType(type)

    @classmethod
    def validate_duration(cls, duration: Union[EnhancementElementDuration, int, float, str]):
        """
        This method validates if the provided 'duration' parameter is a valid
        and positive numeric value, if it is a EnhancementElementDuration
        enum or if it is a valid string value of a EnhancementElementDuration
        enum.

        This method will raise an Exception if any of the rules are not fit.
        """
        # 'duration' can be a EnhancementElementDuration enum, a positive
        # numeric value or a string that represents the string value of an
        # EnhancementElementDuration
        if not duration and duration != 0 and duration != 0.0:
            raise Exception('No "duration" provided.')
        
        if not isinstance(duration, EnhancementElementDuration):
            if isinstance(str, duration):
                if not EnhancementElementDuration.is_valid(duration):
                    raise Exception(f'The "duration" parameter provided {str(duration)} is not a valid EnhancementElementDuration value.')
            elif not variable_is_positive_number(duration):
                raise Exception(f'The "duration" parameter provided {str(duration)} is not a positive number.')
            
    @classmethod
    def validate_start(cls, start: Union[EnhancementElementStart, int, float, str]):
        """
        This method validates if the provided 'start' parameter is a valid
        and positive numeric value, if it is a EnhancementElementStart enum
        or if it is a valid string value of a EnhancementElementStart enum.

        This method will raise an Exception if any of the rules are not fit.
        """
        # 'start' can be a EnhancementElementStart enum, a positive
        # numeric value or a string that represents the string value
        # of an EnhancementElementStart
        if not start and start != 0 and start != 0.0:
            raise Exception('No "start" provided.')
        
        if not isinstance(start, EnhancementElementStart):
            if isinstance(start, str):
                if not EnhancementElementStart.is_valid(start):
                    raise Exception(f'The "start" parameter provided {str(start)} is not a valid EnhancementElementStart value.')
                elif not variable_is_positive_number(start):
                    raise Exception(f'The "start" parameter provided {str(start)} is not a positive number.')
                
                start = EnhancementElementStart(start)

        return start
                
    @classmethod
    def validate_mode(cls, mode: Union[EnhancementElementMode, str], valid_modes: Union[EnhancementElementMode, str] = []):
        """
        This method will check if the provided 'mode' is an
        EnhancementElementMode enum or if it is a valid string 
        value of a EnhancementElementMode enum. It will also
        check, if the 'valid_modes' parameter is provided, if
        the provided 'mode' is one of the provided 'valid_modes'.
        If you don't provide the 'valid_modes' this condition 
        will not be checked.

        This method will raise an Exception if any of the rules 
        are not fit.
        """
        if not mode:
            raise Exception('No "mode" provided.')
        
        if not isinstance(mode, (EnhancementElementMode, str)):
            raise Exception(f'The "mode" parameter provided {mode} is not a EnhancementElementMode nor a string.')
        
        if isinstance(mode, str):
            if not EnhancementElementMode.is_valid(mode):
                raise Exception(f'The "mode" provided string {mode} is not a valid EnhancementElementMode enum value.')
            
            mode = EnhancementElementMode(mode)

        if valid_modes and len(valid_modes) > 0:
            if isinstance(valid_modes[0], EnhancementElementMode):
                if not mode in valid_modes:
                    raise Exception(f'The "mode" parameter provided {str(mode)} is not a valid EnhancementElementMode enum.')
            elif isinstance(valid_modes[0], str):
                if not mode.value in valid_modes:
                    raise Exception(f'The "mode" parameter provided {str(mode)} is not a valid value of an EnhancementElement enum.')
            else:
                raise Exception('The provided "valid_modes" are not EnhancementElementMode nor string items.')