"""
Date utilities — month-end-safe arithmetic using dateutil.relativedelta.

Convention (documented here and enforced everywhere in this codebase):
  Jan 31 + 1 month = Feb 28 (or Feb 29 in a leap year) — NOT Mar 3.
  This uses dateutil.relativedelta which naturally clamps to month-end.

All budget cycles, bill recurrence, and amortization projections MUST use
these helpers. No per-module date arithmetic.
"""
from __future__ import annotations

from datetime import date

from dateutil.relativedelta import relativedelta


def add_months(dt: date, months: int) -> date:
    """
    Add (or subtract) a whole number of months to a date, clamping to month-end.

    Examples:
        add_months(date(2026, 1, 31), 1)  -> date(2026, 2, 28)
        add_months(date(2026, 3, 31), -1) -> date(2026, 2, 28)
        add_months(date(2026, 2, 28), 1)  -> date(2026, 3, 28)
    """
    return dt + relativedelta(months=months)


def month_start(dt: date) -> date:
    """Return the first day of the month containing `dt`."""
    return dt.replace(day=1)


def month_end(dt: date) -> date:
    """Return the last day of the month containing `dt`."""
    return dt + relativedelta(day=31)
