"""Дневной отчёт и фоновая проверка часа отправки."""

from __future__ import annotations

import asyncio
import logging
from datetime import date

from sqlalchemy import select

from config import ADMIN_USER_IDS, DAILY_REPORT_HOUR, SMS_DAILY_LIMIT
from app.database.crud_static import get_sms_statistics
from app.database.engine import async_session
from app.database.models import filtersettings
from app.notify import notify_chat
from app.schedule_utils import now_in_bot_tz

_log = logging.getLogger(__name__)

_last_report_date: date | None = None
_report_task: asyncio.Task | None = None


async def build_daily_report_text() -> str:
    stats = await get_sms_statistics()
    today = stats.get("today") or {}
    all_time = stats.get("all_time") or {}
    limit = SMS_DAILY_LIMIT
    sent = int(today.get("sent") or 0)
    failed = int(today.get("failed") or 0)

    if limit > 0:
        limit_line = f"Лимит на сегодня: {sent}/{limit}"
        if sent >= limit:
            limit_line += " (достигнут)"
    else:
        limit_line = "Лимит SMS: выключен (0)"

    now = now_in_bot_tz()
    running = False
    owner = None
    try:
        from app.user import usermenu

        owner = getattr(usermenu, "_global_parsing_owner_id", None)
        task = getattr(usermenu, "_global_parsing_task", None)
        running = bool(task is not None and not task.done())
    except Exception:
        pass

    try:
        from app.database.crud_pending_sms import count_pending_sms

        pending = await count_pending_sms()
    except Exception:
        pending = 0

    return (
        f"📑 <b>Дневной отчёт</b> ({now.strftime('%d.%m.%Y %H:%M')})\n\n"
        f"✅ SMS успешно: <b>{sent}</b>\n"
        f"❌ SMS с ошибкой: <b>{failed}</b>\n"
        f"📦 Всего попыток сегодня: <b>{sent + failed}</b>\n"
        f"{limit_line}\n\n"
        f"📈 За всё время: ок {all_time.get('sent', 0)} / ошибки {all_time.get('failed', 0)}\n"
        f"👥 Уникальных номеров в базе: {stats.get('unique_phones', 0)}\n"
        f"⏳ В очереди SMS: {pending}\n"
        f"🌐 Парсинг сейчас: {'работает' if running else 'остановлен'}"
        + (f" (user {owner})" if running and owner else "")
    )


async def _recipient_user_ids() -> list[int]:
    ids: set[int] = set(ADMIN_USER_IDS)
    async with async_session() as session:
        result = await session.execute(select(filtersettings.user_id))
        for uid in result.scalars().all():
            if uid:
                ids.add(int(uid))
    return sorted(ids)


async def send_daily_report(*, force: bool = False, to_user_id: int | None = None) -> str:
    """
    Формирует и отправляет дневной отчёт.
    force=True — игнорировать «уже слали сегодня».
    to_user_id — слать только этому пользователю (кнопка «сейчас»).
    """
    global _last_report_date
    text = await build_daily_report_text()
    today = now_in_bot_tz().date()

    if to_user_id:
        await notify_chat(int(to_user_id), text)
        return text

    if not force and _last_report_date == today:
        _log.info("Daily report already sent for %s", today)
        return text

    recipients = await _recipient_user_ids()
    if not recipients and ADMIN_USER_IDS:
        recipients = sorted(ADMIN_USER_IDS)

    ok = 0
    for uid in recipients:
        if await notify_chat(uid, text):
            ok += 1
    _last_report_date = today
    _log.info("Daily report sent to %s/%s recipients", ok, len(recipients))
    return text


async def daily_report_loop() -> None:
    hour = int(DAILY_REPORT_HOUR)
    _log.info("Daily report loop started (hour=%s)", hour)
    await asyncio.sleep(8)
    while True:
        try:
            if hour >= 0:
                now = now_in_bot_tz()
                if now.hour == hour and now.minute < 2:
                    if _last_report_date != now.date():
                        await send_daily_report(force=False)
                        await asyncio.sleep(120)
        except asyncio.CancelledError:
            break
        except Exception:
            _log.exception("Daily report tick failed")
        try:
            await asyncio.sleep(30)
        except asyncio.CancelledError:
            break
    _log.info("Daily report loop stopped")


def start_daily_report_task() -> asyncio.Task:
    global _report_task
    if _report_task is not None and not _report_task.done():
        return _report_task
    _report_task = asyncio.create_task(daily_report_loop(), name="daily_report")
    return _report_task
