from youtube_autonomous.segments.enums import ShortcodeStart, ShortcodeDuration, ShortcodeField, ShortcodeType, ShortcodeMode
from youtube_autonomous.experimental.enhancement.enhancement_element import EnhancementElement
from youtube_autonomous.elements.validator.element_validator import ElementValidator
from youtube_autonomous.config import Configuration
from youtube_autonomous.experimental.shortcodes.consts import FILE_DURATION
from yta_shortcodes.tag_type import ShortcodeTagType
from yta_audio.voice.transcription.objects import AudioTranscription
from yta_general_utils.programming.parameter_validator import PythonValidator, NumberValidator
from typing import Union

from yta_shortcodes.shortcode import YTAShortcode as BaseShortcode

LOWER_INDEX = -1
UPPER_INDEX = 99999

# TODO: Maybe inherit from YTAShortcode and
# refactor to implement the new things
class Shortcode(BaseShortcode):
    """
    Class that represent a shortcode detected in a text, containing 
    its attributes and values and also the content if block-scoped.
    """
    
    tag: ShortcodeType
    """
    The shortcode tag that represents and identifies
    it, determining the way it will be built and
    applied.
    """
    type: ShortcodeTagType
    """
    The type of the shortcode, that identifies it
    as a simple or a block shortcode.
    """
    _start: float
    _duration: float
    _keywords: str
    _filename: str
    _url: str
    _mode: ShortcodeMode
    context: any # TODO: Do I really need this (?)
    content: Union[str, None]
    """
    The text that is between the shortcode open and
    end tag and can include shortcodes. This
    parameter makes sense if the shortcode is a
    block-scoped shortcode and will be None if it is
    a simple-scoped one.
    """
    start_previous_word_index: Union[int, None]
    """
    The index of the word that is inmediately before
    the start tag of this shortcode. Could be None if
    the shortcode is just at the begining. This index
    is considered within the text empty of shortcodes.
    """
    end_previous_word_index: Union[int, None]
    """
    The index of the word that is inmediately before
    the end tag of this shortcode. It is None if the
    shortcode is a simple one. This index is 
    considered within the text empty of shortcodes.
    """

    def __init__(
        self,
        tag: ShortcodeType,
        type: ShortcodeTagType,
        context,
        content: Union[str, None],
        attributes: dict,
        start_previous_word_index: Union[int, None] = None,
        end_previous_word_index: Union[int, None] = None
    ):
        """
        The shortcode has a 'type' and could include some 'attributes' that
        are the parameters inside the brackets, that could also be simple or
        include an associated value. If it is a block-scoped shortcode, it
        will have some 'content' inside of it.
        """
        tag = ShortcodeType.to_enum(tag)
        type = ShortcodeTagType.to_enum(type)

        self.tag = tag
        self.type = type
        self.context = context
        self.content = content
        self.start_previous_word_index = start_previous_word_index
        self.end_previous_word_index = end_previous_word_index

        # Now the more special attributes
        # TODO: This was '.config_as_shortcode' previously
        self.config = Configuration.get_configuration_by_type(self.tag)._config_as_shortcode
        
        self.start = attributes.get(ShortcodeField.START.value, None)
        self.duration = attributes.get(ShortcodeField.DURATION.value, None)
        self.keywords = attributes.get(ShortcodeField.KEYWORDS.value, '')
        self.filename = attributes.get(ShortcodeField.FILENAME.value, '')
        self.url = attributes.get(ShortcodeField.URL.value, '')
        self.mode = attributes.get(ShortcodeField.MODE.value, None)

        # TODO: Should I treat these shortcodes as Enhancement so I need
        # to make the same checks (more specific that these ones below) (?)

        if not self.keywords and not self.filename and not self.url:
            raise Exception('No "keywords" nor "filename" nor "url" sources available.')

    @property
    def start(self):
        """
        The time moment of the current segment in which this element is
        expected to be applied.
        """
        return self._start
    
    @start.setter
    def start(self, start: Union[ShortcodeStart, int, float, None]):
        if start is None:
            start = {
                ShortcodeTagType.SIMPLE: ShortcodeStart.BETWEEN_WORDS,
                ShortcodeTagType.BLOCK: ShortcodeStart.START_OF_FIRST_SHORTCODE_CONTENT_WORD
            }[self.type]

        self._start = ElementValidator.validate_shortcode_start_field(start)

    @property
    def duration(self):
        """
        The duration of the shortcode, that it is calculated according to the
        field or to its content.
        """
        return self._duration
    
    @duration.setter
    def duration(self, duration: Union[ShortcodeDuration, int, float, None]):
        if duration is None:
            duration = {
                ShortcodeTagType.SIMPLE: ShortcodeDuration.FILE_DURATION,
                ShortcodeTagType.BLOCK: ShortcodeDuration.SHORTCODE_CONTENT
            }[self.type]

        # TODO: I'm setting "file_duration" but checking if it is 99998 value
        # so it is failing. Should I put the numeric value here (?)
        self._duration = ElementValidator.validate_shortcode_duration_field(duration.name)

    @property
    def mode(self):
        return self._mode
    
    @mode.setter
    def mode(self, mode: Union[ShortcodeMode, str]):
        mode = ShortcodeMode.to_enum(mode)

        if mode not in self.config.modes:
            raise Exception(f'The provided "{mode.value}" is not a valid mode for this shortcode type "{self.type.value}" and tag "{self.tag.value}".')

        self._mode = mode
    
    def to_enhancement_element(self, transcription: AudioTranscription):
        """
        Turns the current shortcode to an EnhancementElement by using
        the provided 'transcription' and using its words to set the
        actual 'start' and 'duration' fields according the narration.

        The provided 'transcription' could be not needed if the segment
        is not narrated and 'start' and 'duration' fields are manually
        set by the user in the shortcode.
        """
        if (
            self.type == ShortcodeTagType.SIMPLE and
            self.start_previous_word_index is None
        ):
            raise Exception(f'Found {ShortcodeTagType.SIMPLE.value} shortcode without "start_previous_word_index".')
        
        if (
            self.type == ShortcodeTagType.BLOCK and
            (self.start_previous_word_index is None or self.end_previous_word_index is None)
        ):
            raise Exception(f'Found {ShortcodeTagType.BLOCK.value} shortcode without "start_previous_word_index" or "end_previous_word_index".')
        
        self.calculate_start_and_duration(transcription)

        # TODO: Build it
        enhancement_element = EnhancementElement.get_class_from_type(self.tag)(self.tag, self.start, self.duration, self.keywords, self.url, self.filename, self.mode)

        # TODO: Remove this below if the code above is working
        # if self.tag == ShortcodeType.MEME:
        #     enhancement_element = MemeEnhancementElement(self.tag, self.start, self.duration, self.keywords, self.url, self.filename, self.mode)
        # elif self.tag == ShortcodeType.SOUND:
        #     enhancement_element = SoundEnhancementElement(self.tag, self.start, self.duration, self.keywords, self.url, self.filename, self.mode)
        # elif self.tag == ShortcodeType.IMAGE:
        #     enhancement_element = ImageEnhancementElement(self.tag, self.start, self.duration, self.keywords, self.url, self.filename, self.mode)
        # elif self.tag == ShortcodeType.STICKER:
        #     enhancement_element = StickerEnhancementElement(self.tag, self.start, self.duration, self.keywords, self.url, self.filename, self.mode)
        # elif self.tag == ShortcodeType.GREEN_SCREEN:
        #     enhancement_element = GreenscreenEnhancementElement(self.tag, self.start, self.duration, self.keywords, self.url, self.filename, self.mode)
        # elif self.tag == ShortcodeType.EFFECT:
        #     enhancement_element = EffectEnhancementElement(self.tag, self.start, self.duration, self.keywords, self.url, self.filename, self.mode)
        # else:
        #     raise Exception(f'No valid shortcode "{self.tag}" type provided.')
        #     # TODO: Implement the other EnhancementElements
        #     enhancement_element = EnhancementElement(self.tag, self.start, self.duration, self.keywords, self.url, self.filename, self.mode)

        return enhancement_element