from yta_editor_time.enum import SpecificationRequirement
from yta_editor_time.specifications.types import TimeMoment, TimeDuration
from yta_validation import PythonValidator
from dataclasses import dataclass
from typing import Union

    
@dataclass(frozen = True)
class TimeSpecification:
    """
    The time range of the element that must be affected
    according to this specification.

    TODO: Explain like the others
    """

    start_t: Union[TimeMoment, None]
    """
    The first time moment that must be affected by this
    specification.
    """
    end_t: Union[TimeMoment, None]
    """
    The last time moment that must be affected by this
    specification.
    """
    duration: Union[TimeDuration, None] = None
    """
    The total duration that this specification must
    last.
    """

    @property
    def requirements(
        self
    ) -> dict[SpecificationRequirement]:
        """
        The requirements of this specification that are
        needed to be able to resolve it.
        """
        return {
            SpecificationRequirement.FPS
        }

    def __post_init__(
        self
    ):
        if (
            not PythonValidator.is_instance_of(self.start_t, TimeMoment) and
            self.start_t is not None
        ):
            object.__setattr__(self, 'start_t', TimeMoment(self.start_t))
        if (
            not PythonValidator.is_instance_of(self.end_t, TimeMoment) and
            self.end_t is not None
        ):
            object.__setattr__(self, 'end_t', TimeMoment(self.end_t))
        if (
            not PythonValidator.is_instance_of(self.duration, TimeDuration) and
            self.duration is not None
        ):
            object.__setattr__(self, 'duration', TimeDuration(self.duration))

        # exactly two of three must be provided
        provided = sum(
            x is not None
            for x in (self.start_t, self.end_t, self.duration)
        )

        if provided != 2:
            raise ValueError(
                'Provide exactly two of: start_t, end_t, duration'
            )

        if (
            self.start_t and
            self.end_t
        ):
            if self.end_t.value < self.start_t.value:
                raise ValueError('end_t must be >= start_t')

        if (
            self.duration and
            self.duration.value == 0
        ):
            raise ValueError('duration must be > 0')