import re

_match_duration = re.compile(r"^(-?\d+\.?\d*)(s|ms)$").match


class DurationError(Exception):
    """
    Exception indicating a general issue with a CSS duration.
    """


class DurationParseError(DurationError):
    """
    Indicates a malformed duration string that could not be parsed.
    """


def _duration_as_seconds(duration: str) -> float:
    """
    Args:
        duration: A string of the form `"2s"` or `"300ms"`, representing 2 seconds and
            300 milliseconds respectively. If no unit is supplied, e.g. `"2"`, then the duration is
            assumed to be in seconds.
    Raises:
        DurationParseError: If the argument `duration` is not a valid duration string.
    Returns:
        The duration in seconds.
    """
    match = _match_duration(duration)

    if match:
        value, unit_name = match.groups()
        value = float(value)
        if unit_name == "ms":
            duration_secs = value / 1000
        else:
            duration_secs = value
    else:
        try:
            duration_secs = float(duration)
        except ValueError:
            raise DurationParseError(f"{duration!r} is not a valid duration.") from None

    return duration_secs
