"""Background loop for daily todo digest and reminders."""
from __future__ import annotations

import asyncio
import logging
from datetime import UTC, datetime

logger = logging.getLogger(__name__)


async def todo_digest_loop(stop_event: asyncio.Event, store, slack_notifier) -> None:
    """Background loop that posts a daily todo digest and checks for due items."""
    # Check every 15 minutes for due/overdue items; daily digest at 9 AM UTC
    last_digest_date: str | None = None
    while not stop_event.is_set():
        try:
            await asyncio.sleep(900)  # 15 minutes
            if store is None:
                continue

            now = datetime.now(UTC)

            # Daily digest: once per day at or after 9 AM UTC
            today_str = now.strftime("%Y-%m-%d")
            if now.hour >= 9 and last_digest_date != today_str:
                last_digest_date = today_str
                await post_todo_digest(store, slack_notifier)

            # Check for items due today or overdue and post reminders
            await check_todo_reminders(store, slack_notifier, now)

        except asyncio.CancelledError:
            return
        except Exception as exc:
            logger.warning("Todo digest loop error: %s", exc)


async def post_todo_digest(store, slack_notifier) -> None:
    """Post daily digest of open todos to Slack."""
    if slack_notifier is None or store is None:
        return

    todos = await store.list_todos(status="open")
    if not todos:
        return

    # Group by project
    by_project: dict[str, list] = {}
    for t in todos:
        proj = t.project or "(no project)"
        by_project.setdefault(proj, []).append(t)

    lines = [":clipboard: *Daily Todo Digest*\n"]
    now = datetime.now(UTC)
    for proj, items in sorted(by_project.items()):
        lines.append(f"*{proj}*")
        for t in items:
            due_str = ""
            if t.due_date:
                if t.due_date.date() < now.date():
                    due_str = f" :warning: *OVERDUE* (was {t.due_date.strftime('%b %d')})"
                elif t.due_date.date() == now.date():
                    due_str = " :bell: *Due today*"
                else:
                    due_str = f" (due {t.due_date.strftime('%b %d')})"

            p_emoji = {
                "urgent": ":rotating_light:", "high": ":red_circle:",
                "normal": "", "low": ":white_circle:",
            }.get(t.priority.value, "")
            lines.append(f"  {p_emoji} {t.description[:80]}{due_str}")
        lines.append("")

    text = "\n".join(lines)

    try:
        blocks = [
            {"type": "section", "text": {"type": "mrkdwn", "text": text}},
        ]
        await slack_notifier._post(blocks=blocks, channel=slack_notifier._report_channel)
    except Exception as exc:
        logger.warning("Failed to post todo digest: %s", exc)


async def check_todo_reminders(store, slack_notifier, now: datetime) -> None:
    """Post reminders for todos due today or overdue."""
    if slack_notifier is None or store is None:
        return

    # Find todos due today or earlier
    end_of_today = now.replace(hour=23, minute=59, second=59).isoformat()
    due_todos = await store.list_todos(status="open", due_date_before=end_of_today)

    if not due_todos:
        return

    overdue = [t for t in due_todos if t.due_date and t.due_date.date() < now.date()]
    due_today = [t for t in due_todos if t.due_date and t.due_date.date() == now.date()]

    # Only post reminders at specific hours (9, 14, 17 UTC) to avoid spam
    if now.hour not in (9, 14, 17):
        return

    lines = []
    if overdue:
        lines.append(":warning: *Overdue:*")
        for t in overdue:
            lines.append(
                f"  \u2022 {t.description[:80]} ({t.project or 'no project'})"
                f" \u2014 was due {t.due_date.strftime('%b %d')}"
            )
    if due_today:
        lines.append(":bell: *Due today:*")
        for t in due_today:
            lines.append(f"  \u2022 {t.description[:80]} ({t.project or 'no project'})")

    if lines:
        text = "\n".join(lines)
        try:
            blocks = [{"type": "section", "text": {"type": "mrkdwn", "text": text}}]
            await slack_notifier._post(blocks=blocks, channel=slack_notifier._report_channel)
        except Exception as exc:
            logger.warning("Failed to post todo reminder: %s", exc)
