import unittest
from datetime import date

import message
from parsers import DayRow, FoodTotals, Workout

STAGE = {"cardio_min": 100, "strength_days": 2}
TODAY = date(2026, 8, 1)
YESTERDAY = date(2026, 7, 31)

DAYS = {
    date(2026, 7, 27): DayRow(day=date(2026, 7, 27), exercise_min=10, weight=63.6),
    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),
    date(2026, 7, 31): DayRow(
        day=YESTERDAY, steps=8081, exercise_min=14, sleep_h=8.6,
        hrv=43.1, resting_hr=67, meds="Fe, D, I", weight=63.9, fat_pct=35.1,
    ),
}
WORKOUTS = [Workout(date(2026, 7, 29), "Функциональный силовой тренинг", 28)]
FOOD = {YESTERDAY: FoodTotals(day=YESTERDAY, kcal=1874, protein=122.2, fat=74.2, carbs=195.2)}


def build(**overrides):
    kwargs = dict(
        today=TODAY, days=DAYS, workouts=WORKOUTS, food=FOOD,
        stage=STAGE, freshness=YESTERDAY,
    )
    kwargs.update(overrides)
    return message.build_daily(**kwargs)


class WeightRuleTest(unittest.TestCase):
    def test_weight_always_comes_with_seven_day_average(self):
        text = build()

        self.assertIn("63.9", text)
        self.assertIn("среднее за 7 дней", text)

    def test_body_composition_never_appears(self):
        text = build()

        self.assertNotIn("35.1", text)
        self.assertNotIn("жир", text.lower())

    def test_stale_weigh_in_is_shown_with_its_date(self):
        # вчера не взвешивалась — показываем последний замер и его дату
        days = dict(DAYS)
        days[YESTERDAY] = DayRow(day=YESTERDAY, steps=100, weight=None)

        text = build(days=days)

        self.assertIn("63.6", text)
        self.assertIn("(27.07)", text)


class FoodRuleTest(unittest.TestCase):
    def test_shows_plain_numbers(self):
        text = build()

        self.assertIn("1874 ккал", text)
        self.assertIn("Б 122", text)

    def test_no_norms_and_no_remainders(self):
        text = build()

        self.assertNotIn("из 1800", text)
        self.assertNotIn("осталось ккал", text)
        self.assertNotIn("110", text)

    def test_missing_entry_asks_to_record(self):
        text = build(food={})

        self.assertIn("не записано", text)


class WeekBlockTest(unittest.TestCase):
    def test_shows_cardio_against_stage(self):
        text = build()

        self.assertIn("73", text)
        self.assertIn("100", text)

    def test_shows_strength_days(self):
        text = build()

        self.assertIn("1 / 2", text)


class FreshnessTest(unittest.TestCase):
    def test_fresh_data_has_no_warning(self):
        self.assertNotIn("⚠️", build())

    def test_stale_data_is_flagged(self):
        text = build(freshness=date(2026, 7, 29))

        self.assertIn("⚠️", text)
        self.assertIn("29.07", text)


class RobustnessTest(unittest.TestCase):
    def test_empty_data_still_produces_a_message(self):
        text = build(days={}, workouts=[], food={}, freshness=None)

        self.assertIn("НЕДЕЛЯ", text)
        self.assertTrue(len(text) > 50)


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