import asyncio import aiosqlite from datetime import datetime from logging import getLogger from aiogram import Dispatcher, Bot from config import Config from models.state import BotState from utils.antispam import save_message logger = getLogger(__name__) def register_handlers(dp: Dispatcher, state: BotState, bot: Bot) -> int: async def init_db(): async with aiosqlite.connect(Config.DAYS_TO_DB_PATH) as db: await db.execute(""" CREATE TABLE IF NOT EXISTS days_to_new_year ( user_id INTEGER PRIMARY KEY, days INTEGER NOT NULL, timestamp TEXT NOT NULL ) """) await db.commit() logger.info("База данных инициализирована") async def save_days_to_db(user_id: int, days: int): logger.debug(f"Сохраняем user_id={user_id}, days={days}") async with aiosqlite.connect(Config.DAYS_TO_DB_PATH) as db: await db.execute(""" INSERT OR REPLACE INTO days_to_new_year (user_id, days, timestamp) VALUES (?, ?, ?) """, (int(user_id), int(days), datetime.now().strftime("%Y-%m-%d %H:%M:%S"))) await db.commit() logger.info(f"Запись сохранена: user_id={user_id}, days={days}") async def get_last_days(user_id: int) -> int | None: async with aiosqlite.connect(Config.DAYS_TO_DB_PATH) as db: async with db.execute( "SELECT days FROM days_to_new_year WHERE user_id = ?", (int(user_id),) ) as cursor: row = await cursor.fetchone() return row[0] if row else None async def days_to_new_years() -> int: now = datetime.now() new_year = datetime(now.year + 1, 1, 1) delta = (new_year - now).days logger.debug(f"До Нового года осталось {delta} дней") return delta async def days_to_summer() -> int: """Считает дни до 1 июня текущего года (или следующего, если уже лето прошло).""" now = datetime.now() summer = datetime(now.year, 6, 1) if now >= summer: summer = datetime(now.year + 1, 6, 1) delta = (summer - now).days logger.debug(f"До лета осталось {delta} дней") return delta async def days_to_session() -> int: """Считает дни до 1 июня текущего года (или следующего, если уже лето прошло).""" now = datetime.now() summer = datetime(2026, 7, 6) if now >= summer: logger.warning("days_to_session") delta = (summer - now).days logger.debug(f"До Сессии осталось {delta} дней") return delta async def send_days_to_new_years(user_id: int): days_ny = await days_to_new_years() days_summer = await days_to_summer() days_session = await days_to_session() last_days = await get_last_days(user_id) if last_days == days_ny: logger.info(f"user_id={user_id}: запись уже есть ({days_ny} дней), пропускаем") return await save_days_to_db(user_id, days_ny) events = [ ("🌞 До лета", days_summer), ("📚 До конца сессии", days_session), ("🎄 До Нового года", days_ny), ] # сортировка по числу дней (от меньшего к большему) events_sorted = sorted(events, key=lambda x: x[1]) message_text = "\n".join([f"{emoji} осталось {days} дней!" for emoji, days in events_sorted]) for chat_id in Config.CHAT_IDS: try: logger.info(f"Отправляем сообщение в чат {chat_id} для user_id={user_id}") await bot.send_message(chat_id, message_text) except Exception as e: logger.error(f"Ошибка при отправке в чат {chat_id}: {e}") async def periodic_task(): await init_db() while True: logger.info("Запуск цикла periodic_task") for uid in Config.CHAT_IDS: try: msg = await send_days_to_new_years(int(uid)) if msg: save_message(msg.chat.id, msg.message_id) except Exception as e: logger.exception(f"Ошибка при обработке uid={uid}: {e}") logger.info("Завершён цикл periodic_task, спим 6 часов") await asyncio.sleep(21600) # каждые 6 часов asyncio.create_task(periodic_task()) return 0