from datetime import datetime, timedelta

from ._calendar import start_of_month, start_of_week, start_of_year
from ._parser import CalendarBound, DeltaBound

_UNIT_TO_KWARG = {"d": "days", "h": "hours", "m": "minutes"}


def resolve_to_datetime(
    bound: "DeltaBound | CalendarBound",
    reference_dt: datetime,
    week_start: int,
) -> datetime:
    if isinstance(bound, DeltaBound):
        delta = timedelta(**{_UNIT_TO_KWARG[bound.unit]: bound.amount})
        return reference_dt + bound.sign * delta

    if isinstance(bound, CalendarBound):
        if bound.period == "M":
            return start_of_month(reference_dt, bound.offset)
        if bound.period == "W":
            return start_of_week(reference_dt, bound.offset, week_start)
        if bound.period == "Y":
            return start_of_year(reference_dt, bound.offset)
        raise ValueError(f"Unknown calendar period: {bound.period!r}")

    raise TypeError(f"Expected DeltaBound or CalendarBound, got {type(bound)!r}")
