#!/usr/bin/env python3
"""Утренний пуш по здоровью. Чистая арифметика, без Claude.

  python3 digest.py --dry-run    печать в консоль, ничего не отправляя
  python3 digest.py              отправка в @natasha_health_bot
  python3 digest.py --date 2026-08-01   прогон на конкретную дату
  python3 digest.py --when-ready        режим таймера: слать, когда доехали данные
"""

import argparse
import json
import os
import pathlib
import sys
import urllib.error
import urllib.parse
import urllib.request
from datetime import date, datetime

import message
import parsers
import schedule
import week

ROOT = pathlib.Path(__file__).resolve().parent
# Отметка «за сегодня уже отправлено»: таймер тикает всё утро, а пуш нужен один.
STATE_PATH = pathlib.Path(
    os.environ.get("HEALTH_STATE", ROOT / "state" / "sent.json")
)


def load_config():
    with open(ROOT / "config.json", encoding="utf-8") as fh:
        config = json.load(fh)
    # на Pi волт лежит по другому пути — переопределяем через окружение
    config["vault"] = os.environ.get("HEALTH_VAULT", config["vault"])
    return config


def load_env():
    env = {}
    path = ROOT / ".env"
    if not path.exists():
        return env
    for line in path.read_text(encoding="utf-8").splitlines():
        key, _, value = line.partition("=")
        if key.strip() and not key.startswith("#"):
            env[key.strip()] = value.strip()
    return env


def read(vault, relative):
    path = vault / relative
    try:
        return path.read_text(encoding="utf-8")
    except OSError:
        print(f"не читается: {path}", file=sys.stderr)
        return ""


def load_sources(config):
    """Читает все четыре файла волта → (дни, тренировки, еда, замеры)."""
    vault = pathlib.Path(os.path.expanduser(config["vault"]))
    files = config["files"]

    measurements = parsers.parse_body_composition(read(vault, files["body_composition"]))
    # вес из замеров дополняет дневной ряд: health-sync кладёт его туда с задержкой
    days = parsers.merge_weights(
        parsers.parse_daily_series(read(vault, files["daily_series"])),
        measurements,
    )
    return (
        days,
        parsers.parse_workouts(read(vault, files["workouts"])),
        parsers.parse_food_diary(read(vault, files["food_diary"])),
        measurements,
    )


def build(config, today):
    vault = pathlib.Path(os.path.expanduser(config["vault"]))
    days, workouts, food, _ = load_sources(config)

    return message.build_daily(
        today=today,
        days=days,
        workouts=workouts,
        food=food,
        stage=week.stage_for(config["stages"], today),
        freshness=parsers.parse_freshness(read(vault, config["files"]["daily_series"])),
    )


def send(text, env):
    token = env.get("HEALTH_BOT_TOKEN")
    chat_id = env.get("TELEGRAM_OWNER_USER_ID")
    if not token or not chat_id:
        raise SystemExit("нет HEALTH_BOT_TOKEN или TELEGRAM_OWNER_USER_ID в .env")

    payload = urllib.parse.urlencode({"chat_id": chat_id, "text": text}).encode()
    url = f"https://api.telegram.org/bot{token}/sendMessage"
    try:
        with urllib.request.urlopen(urllib.request.Request(url, data=payload), timeout=30) as response:
            body = json.load(response)
    except urllib.error.HTTPError as error:
        description = json.load(error).get("description", "")
        if "chat not found" in description:
            raise SystemExit(
                "Telegram: chat not found — нажми /start у @natasha_health_bot, "
                "бот не может написать первым"
            )
        raise SystemExit(f"Telegram отказал ({error.code}): {description}")
    if not body.get("ok"):
        raise SystemExit(f"Telegram отказал: {body}")


def main():
    parser = argparse.ArgumentParser()
    parser.add_argument("--dry-run", action="store_true", help="печать без отправки")
    parser.add_argument("--date", help="дата прогона YYYY-MM-DD")
    parser.add_argument("--when-ready", action="store_true",
                        help="режим таймера: слать, когда доехали данные, и один раз в день")
    args = parser.parse_args()

    today = date.fromisoformat(args.date) if args.date else date.today()
    config = load_config()

    if args.when_ready:
        vault = pathlib.Path(os.path.expanduser(config["vault"]))
        freshness = parsers.parse_freshness(read(vault, config["files"]["daily_series"]))
        should_send, reason = schedule.decide(
            freshness=freshness,
            today=today,
            now=datetime.now(),
            last_sent=schedule.load_last_sent(STATE_PATH),
        )
        print(f"{datetime.now():%Y-%m-%d %H:%M} {reason}")
        if not should_send:
            return

    text = build(config, today)

    if args.dry_run:
        print(text)
        return
    send(text, load_env())
    if args.when_ready:
        schedule.save_last_sent(STATE_PATH, today)


if __name__ == "__main__":
    main()
