from __future__ import annotations

import asyncio
import logging
from datetime import datetime, timedelta

from telegram import Bot
from telegram.error import TelegramError

from config import BOT_TOKEN
from database import db, fetchall, fetchone, get_setting, set_setting

logging.basicConfig(level=logging.INFO)
logger = logging.getLogger(__name__)


def can_send_now() -> bool:
    if get_setting("queue_status", "active") != "active":
        return False

    cooldown = int(get_setting("cooldown_minutes", "10"))
    last = get_setting("last_send_at", "")

    if not last:
        return True

    try:
        last_dt = datetime.fromisoformat(last)
    except ValueError:
        return True

    return datetime.now() >= last_dt + timedelta(minutes=cooldown)


def get_next_ad():
    return fetchone(
        """
        SELECT a.*, m.username
        FROM ads a
        JOIN models m ON m.id=a.model_id
        WHERE a.status='queued'
        ORDER BY a.id ASC
        LIMIT 1
        """
    )


def get_groups():
    return fetchall("SELECT * FROM target_groups WHERE status='approved' ORDER BY id ASC")


async def send_ad_to_groups(bot: Bot, ad: dict, groups: list[dict]):
    sent_any = False

    with db() as conn:
        with conn.cursor() as cur:
            cur.execute("UPDATE ads SET status='sending' WHERE id=%s", (ad["id"],))

    for group in groups:
        try:
            if ad["media_type"] == "photo":
                msg = await bot.send_photo(
                    chat_id=int(group["chat_id"]),
                    photo=ad["media_file_id"],
                    caption=ad["final_text"],
                )
            else:
                msg = await bot.send_video(
                    chat_id=int(group["chat_id"]),
                    video=ad["media_file_id"],
                    caption=ad["final_text"],
                    read_timeout=120,
                    write_timeout=120,
                    connect_timeout=60,
                )

            sent_any = True
            with db() as conn:
                with conn.cursor() as cur:
                    cur.execute(
                        "INSERT INTO ad_sends (ad_id, group_id, telegram_message_id, status) VALUES (%s,%s,%s,'sent')",
                        (ad["id"], group["id"], msg.message_id),
                    )

        except TelegramError as e:
            logger.exception("Erro ao enviar para grupo %s", group["chat_id"])
            with db() as conn:
                with conn.cursor() as cur:
                    cur.execute(
                        "INSERT INTO ad_sends (ad_id, group_id, status, error) VALUES (%s,%s,'failed',%s)",
                        (ad["id"], group["id"], str(e)),
                    )
                    cur.execute(
                        "UPDATE target_groups SET last_error=%s WHERE id=%s",
                        (str(e), group["id"]),
                    )

    with db() as conn:
        with conn.cursor() as cur:
            if sent_any:
                cur.execute("UPDATE ads SET status='sent', sent_at=NOW() WHERE id=%s", (ad["id"],))
                set_setting("last_send_at", datetime.now().replace(microsecond=0).isoformat())
            else:
                cur.execute("UPDATE ads SET status='failed' WHERE id=%s", (ad["id"],))


async def loop():
    if not BOT_TOKEN:
        raise RuntimeError("BOT_TOKEN não configurado.")

    bot = Bot(BOT_TOKEN)
    logger.info("Worker da fila iniciado.")

    while True:
        try:
            if can_send_now():
                ad = get_next_ad()
                groups = get_groups()
                if ad and groups:
                    logger.info("Enviando anúncio #%s para %s grupo(s)", ad["id"], len(groups))
                    await send_ad_to_groups(bot, ad, groups)
                elif ad and not groups:
                    logger.warning("Existe anúncio na fila, mas nenhum grupo aprovado.")
            await asyncio.sleep(30)
        except Exception:
            logger.exception("Erro no worker")
            await asyncio.sleep(30)


if __name__ == "__main__":
    asyncio.run(loop())
