import unittest
from datetime import date

import week
from parsers import DayRow, Workout


class WeekBoundsTest(unittest.TestCase):
    def test_friday_belongs_to_monday_sunday_week(self):
        self.assertEqual(
            week.week_bounds(date(2026, 7, 31)),
            (date(2026, 7, 27), date(2026, 8, 2)),
        )

    def test_sunday_is_last_day_of_its_own_week(self):
        self.assertEqual(
            week.week_bounds(date(2026, 8, 2)),
            (date(2026, 7, 27), date(2026, 8, 2)),
        )

    def test_day_index_counts_from_monday(self):
        self.assertEqual(week.day_index(date(2026, 7, 27)), 1)
        self.assertEqual(week.day_index(date(2026, 7, 31)), 5)


class CardioTest(unittest.TestCase):
    def test_sums_exercise_minutes_inside_week_only(self):
        days = {
            date(2026, 7, 26): DayRow(day=date(2026, 7, 26), exercise_min=99),
            date(2026, 7, 27): DayRow(day=date(2026, 7, 27), exercise_min=10),
            date(2026, 7, 29): DayRow(day=date(2026, 7, 29), exercise_min=35),
            date(2026, 7, 30): DayRow(day=date(2026, 7, 30), exercise_min=14),
        }

        self.assertEqual(week.cardio_minutes(days, date(2026, 7, 31)), 59)

    def test_missing_values_do_not_break_sum(self):
        days = {
            date(2026, 7, 27): DayRow(day=date(2026, 7, 27), exercise_min=None),
            date(2026, 7, 28): DayRow(day=date(2026, 7, 28), exercise_min=20),
        }

        self.assertEqual(week.cardio_minutes(days, date(2026, 7, 31)), 20)


class StrengthTest(unittest.TestCase):
    def test_counts_distinct_days_not_sessions(self):
        workouts = [
            Workout(date(2026, 7, 27), "Функциональный силовой тренинг", 30),
            Workout(date(2026, 7, 27), "Классическая силовая тренировка", 20),
            Workout(date(2026, 7, 29), "Функциональный силовой тренинг", 28),
            Workout(date(2026, 7, 29), "На улице Ходьба", 51),
        ]

        self.assertEqual(week.strength_days(workouts, date(2026, 7, 31)), 2)

    def test_walking_alone_is_not_strength(self):
        workouts = [Workout(date(2026, 7, 28), "На улице Ходьба", 51)]

        self.assertEqual(week.strength_days(workouts, date(2026, 7, 31)), 0)


class RollingWeightTest(unittest.TestCase):
    def test_averages_measurements_in_last_seven_days(self):
        days = {
            date(2026, 7, 26): DayRow(day=date(2026, 7, 26), weight=63.2),
            date(2026, 7, 27): DayRow(day=date(2026, 7, 27), weight=63.6),
            date(2026, 7, 31): DayRow(day=date(2026, 7, 31), weight=63.9),
            date(2026, 8, 1): DayRow(day=date(2026, 8, 1), weight=64.1),
        }

        self.assertEqual(week.rolling_weight(days, date(2026, 8, 1)), 63.7)

    def test_older_measurements_fall_out_of_window(self):
        days = {
            date(2026, 7, 1): DayRow(day=date(2026, 7, 1), weight=50.0),
            date(2026, 8, 1): DayRow(day=date(2026, 8, 1), weight=64.0),
        }

        self.assertEqual(week.rolling_weight(days, date(2026, 8, 1)), 64.0)

    def test_no_measurements_gives_none(self):
        self.assertIsNone(week.rolling_weight({}, date(2026, 8, 1)))


class LastWeighInTest(unittest.TestCase):
    def test_returns_most_recent_measurement_with_its_date(self):
        days = {
            date(2026, 7, 26): DayRow(day=date(2026, 7, 26), weight=63.2),
            date(2026, 7, 31): DayRow(day=date(2026, 7, 31), weight=63.9),
            date(2026, 8, 1): DayRow(day=date(2026, 8, 1), weight=None),
        }

        self.assertEqual(week.last_weigh_in(days), (date(2026, 7, 31), 63.9))


class StageTest(unittest.TestCase):
    STAGES = [
        {"from": "2026-08-01", "cardio_min": 100, "strength_days": 2},
        {"from": "2026-09-01", "cardio_min": 150, "strength_days": 2},
    ]

    def test_picks_august_stage(self):
        self.assertEqual(week.stage_for(self.STAGES, date(2026, 8, 15))["cardio_min"], 100)

    def test_picks_september_stage_from_first_day(self):
        self.assertEqual(week.stage_for(self.STAGES, date(2026, 9, 1))["cardio_min"], 150)

    def test_before_first_stage_uses_earliest(self):
        self.assertEqual(week.stage_for(self.STAGES, date(2026, 7, 1))["cardio_min"], 100)


if __name__ == "__main__":
    unittest.main()
