"""Bobi v9.0 — Main entry point."""
from __future__ import annotations

import asyncio
import datetime
import io
import logging
import os
import sys
from pathlib import Path

if sys.platform == "win32":
    try:
        sys.stdout = io.TextIOWrapper(sys.stdout.buffer, encoding="utf-8", errors="replace")
        sys.stderr = io.TextIOWrapper(sys.stderr.buffer, encoding="utf-8", errors="replace")
    except Exception:
        pass

import aiosqlite
from telegram import Update
from telegram.error import TelegramError
from telegram.ext import Application, ApplicationBuilder, ApplicationHandlerStop, CallbackQueryHandler, CommandHandler, ContextTypes, MessageHandler, filters

from bot.persian_router import dispatch as persian_dispatch
from bot import __version__, audit as audit_mod
from bot.config import BOT_TOKEN, DB_PATH, LOG_LEVEL, PROXY_URL, WEBHOOK_URL
from bot.db import init_db
from bot.handlers import learning, downloader, panel, moderation, utility, broadcast

LOG_DIR = Path("logs")
LOG_DIR.mkdir(exist_ok=True)

from logging.handlers import RotatingFileHandler
logging.basicConfig(
    format="%(asctime)s - %(name)s - %(levelname)s - %(message)s",
    level=getattr(logging, LOG_LEVEL, logging.INFO),
    handlers=[
        logging.StreamHandler(sys.stdout),
        RotatingFileHandler(LOG_DIR / "bobi.log", encoding="utf-8", maxBytes=5*1024*1024, backupCount=5),
    ],
)
logging.getLogger("httpx").setLevel(logging.WARNING)
logging.getLogger("telegram").setLevel(logging.WARNING)

logger = logging.getLogger("bobi")


async def error_handler(update: object, context: ContextTypes.DEFAULT_TYPE) -> None:
    err = context.error
    if isinstance(err, TelegramError):
        if "not modified" in str(err).lower() or "message to delete not found" in str(err).lower():
            return
    logger.error("Exception:", exc_info=err)
    if isinstance(update, Update) and update.effective_message:
        try:
            await update.effective_message.reply_text("⚠️ خطایی رخ داد.")
        except TelegramError:
            pass


async def post_init(application: Application) -> None:
    try:
        me = await application.bot.get_me()
    except Exception as e:
        logger.critical("post_init: get_me failed: %s", e)
        raise
    logger.info("=" * 50)
    logger.info(f"🤖 Bobi v{__version__} started as @{me.username} (id={me.id})")
    logger.info(f"📁 Database: {DB_PATH}")
    logger.info("=" * 50)

    # Bot commands
    try:
        from telegram import BotCommand, BotCommandScopeAllPrivateChats, BotCommandScopeAllGroupChats
        private = [BotCommand("start", "شروع"), BotCommand("help", "راهنما")]
        group = private + [
            BotCommand("settings", "تنظیمات"), BotCommand("info", "اطلاعات"),
            BotCommand("rules", "قوانین"), BotCommand("report", "گزارش"),
            BotCommand("panel", "پنل"), BotCommand("id", "آیدی"),
        ]
        admin_cmds = group + [
            BotCommand("ban", "بن"), BotCommand("mute", "سکوت"),
            BotCommand("warn", "اخطار"), BotCommand("purge", "پاکسازی"),
            BotCommand("pin", "سنجاق"), BotCommand("lock", "قفل"),
        ]
        await application.bot.set_my_commands(private, scope=BotCommandScopeAllPrivateChats())
        await application.bot.set_my_commands(admin_cmds, scope=BotCommandScopeAllGroupChats())
    except Exception as e:
        logger.warning(f"Could not set commands: {e}")

    broadcast.register_jobs(application)
    await broadcast.restore_scheduled_jobs(application)


async def post_shutdown(application: Application) -> None:
    from bot.db import close_conn
    await close_conn()
    logger.info("Database closed.")


def _register_handlers(app: Application) -> None:
    from bot import middleware
    middleware.register(app)

    # Downloaders (group -2)
    downloader.register(app)

    # Persian dispatcher (group -1)
    async def _persian_wrapper(update: Update, context: ContextTypes.DEFAULT_TYPE) -> None:
        if await persian_dispatch(update, context):
            raise ApplicationHandlerStop
    app.add_handler(MessageHandler(filters.TEXT, _persian_wrapper), group=-1)

    # Command handlers (group 0)
    learning.register(app)
    panel.register(app)
    moderation.register(app)
    utility.register(app)
    broadcast.register(app)

    # Listener (group 99)
    from bot import listener
    app.add_handler(MessageHandler(filters.ALL & ~filters.COMMAND, listener.on_message), group=99)

    # New members (group 100)
    app.add_handler(MessageHandler(filters.StatusUpdate.NEW_CHAT_MEMBERS, listener.on_new_members), group=100)
    app.add_handler(MessageHandler(filters.StatusUpdate.LEFT_CHAT_MEMBER, listener.on_left_member), group=100)
    app.add_handler(MessageHandler(filters.UpdateType.EDITED_MESSAGE, listener.on_edited), group=100)

    # Rules accept callback
    asyncio.get_event_loop().run_until_complete(listener.register_callbacks(app))

    app.add_error_handler(error_handler)


def main() -> None:
    logger.info("Initializing database...")
    init_db()

    logger.info("Building application...")
    builder = ApplicationBuilder().token(BOT_TOKEN).post_init(post_init)

    if PROXY_URL:
        logger.info("Using proxy: %s", PROXY_URL)
        os.environ["HTTPS_PROXY"] = PROXY_URL
        os.environ["HTTP_PROXY"] = PROXY_URL
        builder = builder.proxy(PROXY_URL)

    application = builder.build()
    _register_handlers(application)

    logger.info("Starting bot...")
    try:
        if WEBHOOK_URL:
            from bot.config import WEBHOOK_PORT, WEBHOOK_LISTEN
            logger.info(f"Webhook mode on {WEBHOOK_LISTEN}:{WEBHOOK_PORT}")
            application.run_webhook(listen=WEBHOOK_LISTEN, port=WEBHOOK_PORT, url_path=BOT_TOKEN, webhook_url=f"{WEBHOOK_URL}/{BOT_TOKEN}")
        else:
            logger.info("Running in polling mode")
            loop = asyncio.new_event_loop()
            asyncio.set_event_loop(loop)
            application.run_polling(allowed_updates=Update.ALL_TYPES, drop_pending_updates=True)
    except KeyboardInterrupt:
        logger.info("👋 Bobi stopped.")
    except Exception as e:
        logger.critical(f"Fatal: {e}", exc_info=True)
    finally:
        try:
            if hasattr(application, "shutdown"):
                application.shutdown()
        except Exception:
            pass


if __name__ == "__main__":
    main()
