"""
BIBIVIDI — Weekly savings digest
Computes the past 7 days of token savings and delivers via:
  • OS desktop notification (notify-py, optional — silent fallback if absent)
  • Slack webhook (BIBIVIDI_SLACK_WEBHOOK, optional)

Also exports ``digest_scheduler()``, an asyncio background loop that
fires every Monday at 09:00 local time and is started from the proxy lifespan.
"""
from __future__ import annotations

import asyncio
import logging
from datetime import datetime

logger = logging.getLogger(__name__)

_CO2_G_PER_TOKEN = 0.003   # gCO₂eq per token (GPT-4/Claude, literature estimate)


# ── Public API ────────────────────────────────────────────────────────────────

async def send_digest(*, force: bool = False) -> bool:
    """Compute and deliver the weekly digest.

    Returns ``True`` if the digest was sent, ``False`` if it was skipped
    (already sent today and ``force`` is False, or no data available).
    """
    from bvd.config import settings
    from bvd.engine.stats import stats_tracker

    # Idempotency: skip if already sent today (unless forced)
    stamp_file = settings.data_dir / "last_digest.txt"
    today = datetime.now().date().isoformat()
    if not force and stamp_file.exists() and stamp_file.read_text().strip() == today:
        logger.debug("Weekly digest already sent today — skipping")
        return False

    summary = await stats_tracker.weekly_summary()
    if summary["calls"] == 0 and not force:
        logger.debug("No executions this week — skipping digest")
        return False

    title = "BIBIVIDI Weekly Digest"
    body = _format_body(summary)

    _notify_desktop(title, body)
    await _notify_slack(title, summary, settings.slack_webhook)

    stamp_file.write_text(today)
    logger.info(
        "Weekly digest sent — %d tokens saved, %.1f gCO₂eq avoided",
        summary["tokens_saved"],
        summary["co2_grams"],
    )
    return True


def build_digest_text(summary: dict) -> str:
    """Return a human-readable digest string (used by CLI and tests)."""
    return _format_body(summary)


async def digest_scheduler() -> None:
    """Background loop: check every 30 minutes, send digest on Monday at 09:00."""
    while True:
        await asyncio.sleep(1800)  # 30-minute heartbeat
        now = datetime.now()
        if now.weekday() == 0 and now.hour == 9:   # Monday, 9 AM local time
            try:
                await send_digest()
            except Exception as exc:
                logger.warning("Digest scheduler error: %s", exc)


# ── Internal helpers ──────────────────────────────────────────────────────────

def _format_body(summary: dict) -> str:
    saved = summary["tokens_saved"]
    usd = summary["estimated_usd_saved"]
    co2 = summary["co2_grams"]
    calls = summary["calls"]
    top = summary.get("top_skill") or "—"
    return (
        f"Tokens saved   : {saved:,}\n"
        f"Est. cost saved: ${usd:.4f}\n"
        f"CO₂ avoided    : {co2:.1f} gCO₂eq\n"
        f"Executions     : {calls}\n"
        f"Top skill      : {top}"
    )


def _notify_desktop(title: str, body: str) -> None:
    """Send an OS desktop notification. Silent no-op if notify-py is absent."""
    try:
        from notifypy import Notify  # type: ignore[import-untyped]
        n = Notify()
        n.title = title
        n.message = body
        n.send(block=False)
    except Exception:
        # notify-py not installed, no display, or headless environment — log only
        logger.info("Digest (no desktop notification): %s | %s", title, body.replace("\n", " | "))


async def _notify_slack(title: str, summary: dict, webhook_url: str | None) -> None:
    """POST a formatted message to a Slack webhook URL. No-op if URL is absent."""
    if not webhook_url:
        return

    import httpx

    payload = {
        "text": f"*{title}*",
        "blocks": [
            {
                "type": "section",
                "text": {
                    "type": "mrkdwn",
                    "text": (
                        f"*{title}*\n"
                        f"Tokens saved: `{summary['tokens_saved']:,}`\n"
                        f"Est. cost saved: `${summary['estimated_usd_saved']:.4f}`\n"
                        f"CO₂ avoided: `{summary['co2_grams']:.1f} gCO₂eq`\n"
                        f"Executions: `{summary['calls']}`\n"
                        f"Top skill: `{summary.get('top_skill') or '—'}`"
                    ),
                },
            }
        ],
    }

    try:
        async with httpx.AsyncClient(timeout=10.0) as client:
            resp = await client.post(webhook_url, json=payload)
        if resp.status_code != 200:
            logger.warning("Slack webhook returned HTTP %d", resp.status_code)
    except Exception as exc:
        logger.warning("Slack webhook failed: %s", exc)
