"""
core/notifications.py — Уведомления о завершении задач + loop-режим (авто-повтор).
"""
import asyncio
import time
from collections import defaultdict
from typing import Optional, List, Dict

from bot_ui.logger_setup import logger

# ── Хранилище уведомлений (для мини-аппа) ─────────────────────────────────
# {user_id: [{"ts": float, "type": str, "title": str, "body": str, "read": bool}]}
_notifications: Dict[int, List[dict]] = defaultdict(list)
_MAX_PER_USER = 50


def add_notification(user_id: int, ntype: str, title: str, body: str):
    """Добавляет уведомление для пользователя (для мини-аппа)."""
    _notifications[user_id].append({
        "ts": time.time(),
        "type": ntype,  # "join", "spam", "multi_join", "multi_spam"
        "title": title,
        "body": body,
        "read": False,
    })
    # Обрезаем старые
    if len(_notifications[user_id]) > _MAX_PER_USER:
        _notifications[user_id] = _notifications[user_id][-_MAX_PER_USER:]


def get_notifications(user_id: int, unread_only: bool = False) -> list:
    """Возвращает уведомления пользователя."""
    items = _notifications.get(user_id, [])
    if unread_only:
        return [n for n in items if not n["read"]]
    return items[-20:]


def mark_read(user_id: int):
    """Помечает все уведомления как прочитанные."""
    for n in _notifications.get(user_id, []):
        n["read"] = True


def unread_count(user_id: int) -> int:
    return sum(1 for n in _notifications.get(user_id, []) if not n["read"])


# ── Отправка уведомления в бот ─────────────────────────────────────────────

async def notify_task_finished(
    bot,  # legacy: оставлен для совместимости signature, не используется
    user_id: int,
    task_type: str,
    phone: str,
    counts: dict,
    status: str,
    extra: str = "",
):
    """Сохраняет уведомление о завершении задачи в общий стек уведомлений
    приложения. UI читает их через /api/notifications. Раньше также слал
    сообщение в Telegram-бот — в standalone не нужно."""
    labels = {
        "join": "Подписка",
        "spam": "Рассылка",
        "multi_join": "Мульти-подписка",
        "multi_spam": "Мульти-рассылка",
    }
    label = labels.get(task_type, task_type)

    # Формируем краткую статистику
    if task_type in ("join", "multi_join"):
        stats_line = (
            f"✅ {counts.get('joined', 0)} вступил | "
            f"⏭️ {counts.get('already', 0)} уже | "
            f"📨 {counts.get('request', 0)} заявок | "
            f"❌ {counts.get('failed', 0)} ошибок"
        )
    else:
        stats_line = (
            f"✅ {counts.get('sent', 0)} отправлено | "
            f"🚫 {counts.get('spamfilter', 0)} спам | "
            f"⏱ {counts.get('flood', 0)} flood | "
            f"❌ {counts.get('failed', 0)} ошибок"
        )

    title = f"{label} завершена"
    body = stats_line + (f" | {extra}" if extra else "")
    add_notification(user_id, task_type, title, body)


# ── Loop-режим: авто-повтор задачи ────────────────────────────────────────

async def maybe_loop_join(user_id: int, restart_coro_factory):
    """
    Loop для подписок — проверяет loop_mode, ждёт interval, перезапускает.
    Подписка всегда берёт СВЕЖИЕ ссылки из контексту.
    """
    try:
        from bot_ui.ui import get_ctx
        ctx = get_ctx(user_id)
        if not ctx.user_settings.get("loop_mode", False):
            return False
        interval = ctx.user_settings.get("loop_interval_min", 5)
        return await _wait_and_restart(user_id, "подписка", interval, restart_coro_factory)
    except Exception as e:
        logger.error("[loop] maybe_loop_join error: %s", e)
        return False


async def maybe_loop_spam(user_id: int, restart_coro_factory, current_round: int = 1):
    """
    Loop для рассылки — повторяет N кругів (spam_rounds).
    current_round: текущий круг (1-based).
    """
    try:
        from bot_ui.ui import get_ctx
        ctx = get_ctx(user_id)
        if not ctx.user_settings.get("loop_mode", False):
            return False
        max_rounds = ctx.user_settings.get("spam_rounds", 1)
        if max_rounds <= 1:
            return False
        if current_round >= max_rounds:
            # Все круги пройдены — фиксируем в стеке уведомлений приложения.
            add_notification(user_id, "spam", "Рассылка завершена",
                             f"Прошли все {max_rounds} кругов")
            return False
        interval = ctx.user_settings.get("loop_interval_min", 5)
        label = f"розсилка (круг {current_round + 1}/{max_rounds})"
        return await _wait_and_restart(user_id, label, interval, restart_coro_factory)
    except Exception as e:
        logger.error("[loop] maybe_loop_spam error: %s", e)
        return False


async def _wait_and_restart(user_id: int, label: str, interval: int, restart_coro_factory):
    """Общая логика ожидания + перезапуска."""
    from bot_ui.ui import get_ctx

    logger.info("[loop] %s для uid=%s — повтор через %d мин.", label, user_id, interval)
    add_notification(user_id, "loop",
                     f"Повтор: {label}",
                     f"Перезапустится через {interval} мин.")

    wait_sec = interval * 60
    elapsed = 0
    while elapsed < wait_sec:
        await asyncio.sleep(min(10, wait_sec - elapsed))
        elapsed += 10
        ctx = get_ctx(user_id)
        if not ctx.user_settings.get("loop_mode", False):
            logger.info("[loop] %s для uid=%s — повтор отменён.", label, user_id)
            return False

    logger.info("[loop] %s для uid=%s — перезапуск!", label, user_id)
    try:
        await restart_coro_factory()
    except Exception as e:
        logger.error("[loop] Ошибка перезапуска %s uid=%s: %s", label, user_id, e)

    return True
