"""Golden tests for backend/services/time_utils.py.

These pin the day-count week→month split. A wrong split silently misallocates
revenue/qty between calendar months, which is hard to spot downstream.
"""
from datetime import date

import pytest

from backend.services.time_utils import (
    days_in_calendar_month,
    iso_week_first_monday,
    split_iso_week_across_months,
)


def test_first_monday_is_a_monday_and_in_the_right_iso_week():
    # CW18 2026 starts Mon Apr 27 (per module docstring example).
    mon = iso_week_first_monday(2026, 18)
    assert mon == date(2026, 4, 27)
    assert mon.isoweekday() == 1
    assert mon.isocalendar()[:2] == (2026, 18)


def test_first_monday_handles_iso_week_1_spanning_year_boundary():
    # ISO week 1 of 2026 begins Mon Dec 29 2025 (Jan 1 2026 is a Thursday).
    assert iso_week_first_monday(2026, 1) == date(2025, 12, 29)


def test_split_straddling_week_by_day_count():
    # CW18 2026 = Apr 27-May 3 → 4 days April, 3 days May.
    parts = split_iso_week_across_months(2026, 18)
    assert parts == [
        (2026, 4, pytest.approx(4 / 7)),
        (2026, 5, pytest.approx(3 / 7)),
    ]
    assert sum(p[2] for p in parts) == pytest.approx(1.0)


def test_split_single_month_week_returns_one_bucket():
    # CW20 2026 (week starting May 11) sits entirely inside May.
    parts = split_iso_week_across_months(2026, 20)
    assert parts == [(2026, 5, pytest.approx(1.0))]


def test_split_fractions_always_sum_to_one():
    for week in (1, 9, 18, 31, 44, 52):
        parts = split_iso_week_across_months(2026, week)
        assert sum(p[2] for p in parts) == pytest.approx(1.0)
        assert len(parts) in (1, 2)


def test_days_in_calendar_month():
    assert days_in_calendar_month(2026, 2) == 28   # 2026 not a leap year
    assert days_in_calendar_month(2024, 2) == 29   # leap year
    assert days_in_calendar_month(2026, 4) == 30
    assert days_in_calendar_month(2026, 1) == 31
