"""
P3.1-T3: kb_rot_cleaner 月度排程時機計算測試
=============================================
驗證 _run_kb_rot_cleaner_loop 的 next_run 計算邏輯正確：
- 月初 3 點前 → 當月 1 號 03:00
- 其他時間 → 下月 1 號 03:00
- 12 月 → 翌年 1 月 1 號 03:00

2026-04-27 P3.1-T3 by Claude
"""
from __future__ import annotations

from datetime import datetime

import pytest


# ─────────────────────────────────────────────────────────────────────────────
# 複製 main.py 中的 next_run 計算邏輯（純函式萃取，方便測試）
# ─────────────────────────────────────────────────────────────────────────────

def _calc_next_run(now: datetime) -> datetime:
    """
    計算下次 kb_rot_cleaner 執行時間（月初 03:00 台北時間）

    同 main.py lifespan 中 _run_kb_rot_cleaner_loop 的邏輯。
    """
    if now.day == 1 and now.hour < 3:
        return now.replace(hour=3, minute=0, second=0, microsecond=0)
    elif now.month == 12:
        return now.replace(
            year=now.year + 1, month=1, day=1,
            hour=3, minute=0, second=0, microsecond=0,
        )
    else:
        return now.replace(
            month=now.month + 1, day=1,
            hour=3, minute=0, second=0, microsecond=0,
        )


# ─────────────────────────────────────────────────────────────────────────────
# Tests
# ─────────────────────────────────────────────────────────────────────────────

class TestKbRotCleanerSchedule:
    """月度排程時機計算測試"""

    def test_day1_before_3am_returns_same_day_3am(self):
        """月初 02:59 → 同日 03:00"""
        now = datetime(2026, 5, 1, 2, 59, 0)
        result = _calc_next_run(now)
        assert result == datetime(2026, 5, 1, 3, 0, 0)

    def test_day1_exactly_midnight_returns_same_day_3am(self):
        """月初 00:00 → 同日 03:00"""
        now = datetime(2026, 5, 1, 0, 0, 0)
        result = _calc_next_run(now)
        assert result == datetime(2026, 5, 1, 3, 0, 0)

    def test_day1_after_3am_returns_next_month(self):
        """月初 03:01 → 下月 1 號 03:00"""
        now = datetime(2026, 5, 1, 3, 1, 0)
        result = _calc_next_run(now)
        assert result == datetime(2026, 6, 1, 3, 0, 0)

    def test_mid_month_returns_next_month(self):
        """月中 → 下月 1 號 03:00"""
        now = datetime(2026, 5, 15, 12, 0, 0)
        result = _calc_next_run(now)
        assert result == datetime(2026, 6, 1, 3, 0, 0)

    def test_december_rolls_over_to_january(self):
        """12 月 → 翌年 1 月 1 號 03:00"""
        now = datetime(2026, 12, 15, 12, 0, 0)
        result = _calc_next_run(now)
        assert result == datetime(2027, 1, 1, 3, 0, 0)

    def test_december_day1_before_3am_stays_december(self):
        """12 月 1 日 02:00 → 同日 03:00（不跨年）"""
        now = datetime(2026, 12, 1, 2, 0, 0)
        result = _calc_next_run(now)
        assert result == datetime(2026, 12, 1, 3, 0, 0)

    def test_sleep_seconds_positive(self):
        """sleep_sec 必須為正數"""
        now = datetime(2026, 5, 15, 12, 0, 0)
        next_run = _calc_next_run(now)
        sleep_sec = (next_run - now).total_seconds()
        assert sleep_sec > 0

    def test_next_run_always_at_hour_3(self):
        """所有情況下 next_run 的 hour 必須是 3"""
        test_cases = [
            datetime(2026, 1, 1, 2, 59, 59),
            datetime(2026, 3, 15, 8, 0, 0),
            datetime(2026, 12, 31, 23, 59, 59),
            datetime(2026, 6, 1, 3, 30, 0),
        ]
        for now in test_cases:
            result = _calc_next_run(now)
            assert result.hour == 3, f"Expected hour=3 for now={now}, got {result}"
            assert result.minute == 0
            assert result.second == 0
            assert result.microsecond == 0

    def test_next_run_always_day1(self):
        """所有情況下 next_run 的 day 必須是 1"""
        test_cases = [
            datetime(2026, 1, 15, 12, 0, 0),
            datetime(2026, 5, 2, 0, 0, 0),
            datetime(2026, 12, 20, 6, 0, 0),
        ]
        for now in test_cases:
            result = _calc_next_run(now)
            assert result.day == 1, f"Expected day=1 for now={now}, got {result}"


if __name__ == "__main__":
    pytest.main([__file__, "-v"])
