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

    
@dataclass(frozen = True)
class ProgressSpecification:
    """
    The part of the element that must be affected,
    defined by a progress from its start to its end
    as a normalized value in a `[0.0, 1.0]` range.

    Here you have some instructions about the
    different options you have, considering the
    progress as a value from `0.0` (start of the
    element) to `1.0` (end of the element):
    - Set `start_progress` and `end_progress` to
    apply the modification to that progress range.
    - Set `start_progress` and `duration` to start
    applying the modification at the `start_progress`
    moment and lasting the `duration` seconds
    provided.
    """

    start_progress: Union[ProgressValue, None]
    """
    The start of the progress that must be affected by
    this specification.
    """
    end_progress: Union[ProgressValue, None]
    """
    The end of the progress 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,
            SpecificationRequirement.DURATION
        }

    def __post_init__(
        self
    ):
        if (
            not PythonValidator.is_instance_of(self.start_progress, ProgressValue) and
            self.start_progress is not None
        ):
            object.__setattr__(self, 'start_progress', ProgressValue(self.start_progress))
        if (
            not PythonValidator.is_instance_of(self.end_progress, ProgressValue) and
            self.end_progress is not None
        ):
            object.__setattr__(self, 'end_progress', ProgressValue(self.end_progress))
        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_progress, self.end_progress, self.duration)
        )

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

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

        if (
            self.duration and
            self.duration.value == 0
        ):
            raise ValueError('duration must be > 0')
        
        # TODO: Maybe raise exception if 'start_progress' +
        # 'duration' > 1.0 (?)