"""Сборка утреннего сообщения.

Правила формата закреплены тестами и не меняются без правки спеки:
  1. Вес показывается только рядом со средним за 7 дней.
  2. Состав тела (%жира, мышцы) в ежедневный не попадает — только в недельный разбор.
  3. По еде — цифры без норм, остатков и оценок.
"""

from datetime import timedelta

import week

WEEKDAYS = ["понедельник", "вторник", "среда", "четверг", "пятница", "суббота", "воскресенье"]
MONTHS_GEN = [
    "января", "февраля", "марта", "апреля", "мая", "июня",
    "июля", "августа", "сентября", "октября", "ноября", "декабря",
]


def _human_date(day):
    return f"{day.day} {MONTHS_GEN[day.month - 1]}"


def _short_date(day):
    return day.strftime("%d.%m")


def _num(value, suffix=""):
    if value is None:
        return None
    text = f"{value:g}"
    return f"{text}{suffix}"


def _join(parts, sep=" · "):
    return sep.join(p for p in parts if p)


def build_daily(today, days, workouts, food, stage, freshness):
    yesterday = today - timedelta(days=1)
    cardio = week.cardio_minutes(days, today)
    strength = week.strength_days(workouts, today)

    lines = [
        f"🌅 {_human_date(today)}, {WEEKDAYS[today.weekday()]} · день {week.day_index(today)} недели",
        "",
        "СЕГОДНЯ",
        week.suggestion(stage, cardio, strength, today),
        "",
        "НЕДЕЛЯ (пн–вс)",
        f"Кардио   {cardio} / ~{stage['cardio_min']} мин" + _cardio_tail(stage, cardio),
        f"Силовые   {strength} / {stage['strength_days']} дня" + _strength_tail(stage, strength),
        "",
    ]

    lines += _yesterday_block(days.get(yesterday))
    lines += _food_block(food.get(yesterday))
    lines += _weight_block(days, today)

    warning = _freshness_warning(freshness, yesterday)
    if warning:
        lines += ["", warning]

    return "\n".join(lines).strip()


def _cardio_tail(stage, cardio):
    gap = stage["cardio_min"] - cardio
    return f"   осталось {gap}" if gap > 0 else "   ✓"


def _strength_tail(stage, strength):
    gap = stage["strength_days"] - strength
    if gap <= 0:
        return "   ✓"
    return "   осталась одна" if gap == 1 else f"   осталось {gap}"


def _yesterday_block(row):
    if row is None:
        return ["ВЧЕРА", "данных нет", ""]

    first = _join([
        f"шаги {row.steps:,}".replace(",", " ") if row.steps is not None else None,
        f"{row.exercise_min:g} мин упражнений" if row.exercise_min is not None else None,
        f"{row.sleep_h:g} ч сна" if row.sleep_h is not None else None,
    ])
    second = _join([
        f"HRV {row.hrv:g}" if row.hrv is not None else None,
        f"пульс {row.resting_hr:g}" if row.resting_hr is not None else None,
        f"препараты ✓ {len(row.meds.split(','))}/3" if row.meds else None,
    ])
    body = [line for line in (first, second) if line] or ["данных нет"]
    return ["ВЧЕРА"] + body + [""]


def _food_block(totals):
    if totals is None or totals.kcal is None:
        return ["ЕДА ВЧЕРА", "не записано — внеси, пока помнится", ""]

    numbers = _join([
        _num(totals.kcal, " ккал"),
        _num(totals.protein) and f"Б {totals.protein:g}",
        _num(totals.fat) and f"Ж {totals.fat:g}",
        _num(totals.carbs) and f"У {totals.carbs:g}",
    ])
    return ["ЕДА ВЧЕРА", numbers, ""]


def _weight_block(days, today):
    """Вес никогда не показывается одиночной цифрой — всегда рядом со средним."""
    average = week.rolling_weight(days, today)
    latest = week.last_weigh_in(days)

    if latest is None:
        return ["ВЕС", "замеров нет — встань на весы"]

    day, value = latest
    stamp = "" if day == today - timedelta(days=1) or day == today else f" ({_short_date(day)})"
    average_text = f" · среднее за 7 дней {average:g}" if average is not None else ""
    return ["ВЕС", f"{value:g}{stamp}{average_text}"]


def _freshness_warning(freshness, yesterday):
    if freshness is None:
        return "⚠️ данные не читаются — проверь health-sync"
    if freshness < yesterday:
        return f"⚠️ данные только до {_short_date(freshness)} — Мак не досчитал вчерашний день"
    return None
