"""Запуск прогона: токены, клиенты, рендер архивов, алерты в телеграм.

Обычный запуск (расписание на Pi или руками):
    python cli.py
"""
from __future__ import annotations

import os
import sys
from datetime import datetime, timezone
from pathlib import Path

import api
import auth
import db
import pull
import render
import telegram

PLATFORMS = ("instagram", "threads")

# Архивы лежат рядом с TGStat-архивом канала и, как он, без даты в имени:
# это постоянно перезаписываемые файлы, а не снапшоты.
CHANNEL_DIR = Path("projects") / "channel"
ARCHIVE_NAMES = {
    "instagram": "{channel} {source} Instagram архив постов.md",
    "threads": "{channel} {source} Threads архив постов.md",
}

CLIENTS = {"instagram": api.InstagramClient, "threads": api.ThreadsClient}


def archive_path(vault_root, platform: str) -> Path:
    return Path(vault_root) / CHANNEL_DIR / ARCHIVE_NAMES[platform]


def default_db_path() -> Path:
    env_path = os.environ.get("META_DB_PATH")
    if env_path:
        return Path(env_path)
    return Path.home() / "Library" / "Application Support" / "meta-puller" / "meta.db"


def build_clients(db_path, now: str):
    """Готовит клиентов с живыми токенами. Платформа без токена просто пропускается."""
    clients, warnings = {}, []
    for platform in PLATFORMS:
        try:
            token, warning = auth.ensure_token(db_path, platform, now=now)
        except auth.NoTokenError as exc:
            warnings.append(str(exc))
            continue
        if warning:
            warnings.append(warning)
        clients[platform] = CLIENTS[platform](token=token)
    return clients, warnings


def execute(db_path, clients: dict, vault_root, now: str, notify, warnings) -> str:
    """Прогон + рендер + алерты. Возвращает статус прогона."""
    status, errors = pull.run(db_path, clients, now=now)

    for platform in clients:
        if platform in errors:
            # Платформа упала — рендерить нечего: пустой или устаревший архив
            # планёрка прочтёт как «постов не было», а это неправда.
            continue
        username = db.account_state(db_path, platform, today=now[:10])["username"]
        render.render_archive(db_path, platform, archive_path(vault_root, platform),
                              now=now, username=username or platform)

    messages = list(warnings)
    if db.should_alert(db_path):
        messages.append("meta-puller: три прогона подряд упали — {}".format(
            "; ".join("{}: {}".format(p, e) for p, e in errors.items()) or "см. лог"))
    for message in messages:
        notify(message)

    return status


def main(argv=None) -> int:
    from dotenv import load_dotenv

    load_dotenv(Path(__file__).resolve().parent / ".env")
    now = datetime.now(timezone.utc).strftime("%Y-%m-%dT%H:%M:%SZ")

    vault_root = os.environ.get("META_VAULT_ROOT")
    if not vault_root:
        print("в .env нет META_VAULT_ROOT — некуда писать архивы", file=sys.stderr)
        return 2

    db_path = default_db_path()
    db.init_db(db_path)

    notify = telegram.notifier(
        os.environ.get("TELEGRAM_BOT_TOKEN"), os.environ.get("TELEGRAM_CHAT_ID"))

    clients, warnings = build_clients(db_path, now)
    if not clients:
        for warning in warnings:
            notify(warning)
        print("нет ни одной платформы с токеном", file=sys.stderr)
        return 1

    status = execute(db_path, clients, vault_root, now, notify, warnings)
    print("прогон: {}".format(status))
    return 0 if status != "failed" else 1


if __name__ == "__main__":
    sys.exit(main())
