from yta_editor.tracks.items.abstract import _TrackItem
from yta_time_interval import TIME_INTERVAL_SYSTEM_LIMITS
from quicktions import Fraction
from typing import Union


# TODO: This is reapeated and not used everywhere
Number = Union[int, float, Fraction]
"""
Numeric type we accept as parameter.
"""
# TODO: What about the inheritance (?)
# TODO: Replace the 'empty' video and audio logic with
# this class
class GapTrackItem(_TrackItem):
    """
    A simple class to replace the logic related to 'empty'
    video track items and be more simple and understandable.

    This item will be placed when there is a gap in between
    2 real clips.
    """

    @property
    def _is_last_gap(
        self
    ) -> bool:
        """
        *For internal use only*

        Flag to indicate that the gap instance is the last one
        in the track, which means that the 't_end' is the system's
        limit of
        `yta_video_frame_time.interva.TIME_INTERVAL_SYSTEM_LIMITS`.
        """
        return self.t_end == TIME_INTERVAL_SYSTEM_LIMITS[1]

    @property
    def copy(
        self
    ) -> 'GapTrackItem':
        """
        A copy of the current gap instance.
        """
        return GapTrackItem(
            track = self._track,
            t_start = self.t_start,
            duration = self.duration,
            item_in = self.item_in,
            item_out = self.item_out
        )

    def __init__(
        self,
        track: 'Track',
        t_start: float,
        duration: float,
        item_in: Union['_AudioTrackItem', '_VideoTrackItem', '_TransitionTrackItem', 'GapTrackItem', None] = None,
        item_out: Union['_AudioTrackItem', '_VideoTrackItem', '_TransitionTrackItem', 'GapTrackItem', None] = None
    ):
        # TODO: Maybe use the **kwargs (?)
        super().__init__(
            track = track,
            t_start = t_start,
            duration = duration,
            item_in = item_in,
            item_out = item_out,
            transition_in = None,
            transition_out = None
        )

    """
    The gap track item is special because it can be the
    last item of the track and have an t_end that is the
    system's t_end value and that 't_end' value must be kept
    as it is, so when manipulating the time interval we
    have to do it carefully and in an special way using
    the internal `_is_last_gap` flag.
    """

    def _shift_by(
        self,
        delta: Number
    ) -> '_TrackItem':
        """
        Move the `t_start` and `t_end` value of this item the amount
        of time defined by the `delta` provided parameter, that
        can be positive or negative (and will be truncated to be
        a multiple of `1/fps`).
        """
        if self._is_last_gap:
            return self.shift_start_by(delta)
        
        self._time_interval.shift_by(delta)
        
        return self
    
    def shift_to(
        self,
        t_track: Number
    ) -> '_TrackItem':
        """
        Move the `t_start` and `t_end` value of this item to the time
        moment defined by the `t_track` parameter provided. The
        change will not modify the duration of the item.
        """
        if self._is_last_gap:
            return self.shift_start_to(t_track)
        
        self._time_interval.shift_by(
            delta = t_track - self.t_start
        )
        
        return self
    
    def shift_start_by(
        self,
        delta: Number
    ) -> '_TrackItem':
        """
        Update the `t_start` value by adding the `delta` provided
        (that can be positive to make it start later or negative
        to make it start earlier).
        """
        self._time_interval.shift_start_by(delta)

        return self
    
    def shift_start_to(
        self,
        t_track: Number
    ) -> '_TrackItem':
        """
        Update the `t_start` value to the one provided as `t_track`
        (that can be before or after the current one).
        """
        return self.shift_start_by(
            delta = t_track - self.t_start
        )
    
    def shift_end_by(
        self,
        delta: Number
    ) -> '_TrackItem':
        """
        Update the `t_end` value by adding the `delta` provided
        (that can be positive to make it start later or negative
        to make it start earlier).
        """
        if self._is_last_gap:
            return self
        
        self._time_interval.shift_end_by(delta)

        return self
    
    def shift_end_to(
        self,
        t_track: Number
    ) -> '_TrackItem':
        """
        Update the `t_end` value to the one provided as `t_track`
        (that can be before or after the current one).
        """
        if self._is_last_gap:
            return self
        
        return self.shift_end_by(
            delta = t_track - self.t_end
        )

    # TODO: Create 'get_audio_frames_at' method that returns silent
    # audio frames
    # TODO: Create 'get_frame_at' method that returns empty frame