import asyncio
import logging
import os
import sys
import json
from aiohttp import web
from dotenv import load_dotenv

load_dotenv()

WEBHOOK_PATH = "/webhook"
WEBHOOK_SECRET = os.getenv("WEBHOOK_SECRET", "")
BOT_TOKEN = os.getenv("BOT_TOKEN", "")

# Allow overriding via env or CLI arg
WEBHOOK_URL = os.getenv("WEBHOOK_URL", "")
WEBHOOK_PORT = int(os.getenv("WEBHOOK_PORT", "5000"))


async def on_startup(app: web.Application):
    """Register webhook with Telegram on startup."""
    from aiogram import Bot
    from aiogram.client.default import DefaultBotProperties
    from aiogram.enums import ParseMode

    from config import BOT_TOKEN as CFG_TOKEN
    token = CFG_TOKEN or BOT_TOKEN
    if not token:
        logging.error("BOT_TOKEN not set!")
        return

    bot = Bot(token=token, default=DefaultBotProperties(parse_mode=ParseMode.HTML))

    webhook_url = WEBHOOK_URL.rstrip("/") + WEBHOOK_PATH
    logging.info("Setting webhook to: %s", webhook_url)

    await bot.set_webhook(
        url=webhook_url,
        secret_token=WEBHOOK_SECRET or None,
        drop_pending_updates=True,
    )
    await bot.session.close()
    logging.info("Webhook set successfully!")


async def on_shutdown(app: web.Application):
    """Remove webhook on shutdown."""
    from aiogram import Bot
    from aiogram.client.default import DefaultBotProperties
    from aiogram.enums import ParseMode

    from config import BOT_TOKEN as CFG_TOKEN
    token = CFG_TOKEN or BOT_TOKEN
    if not token:
        return

    bot = Bot(token=token, default=DefaultBotProperties(parse_mode=ParseMode.HTML))
    await bot.delete_webhook(drop_pending_updates=True)
    await bot.session.close()
    logging.info("Webhook removed.")


async def webhook_handler(request: web.Request):
    """Handle incoming Telegram updates via webhook."""
    if WEBHOOK_SECRET:
        secret = request.headers.get("X-Telegram-Bot-Api-Secret-Token", "")
        if secret != WEBHOOK_SECRET:
            return web.Response(status=403)

    from config import BOT_TOKEN as CFG_TOKEN
    token = CFG_TOKEN or BOT_TOKEN
    if not token:
        return web.Response(status=500)

    from aiogram import Bot, Dispatcher
    from aiogram.client.default import DefaultBotProperties
    from aiogram.enums import ParseMode
    from database import init_db
    from handlers.user import router as user_router
    from handlers.wallet import router as wallet_router
    from handlers.admin import router as admin_router
    from handlers.callback import router as callback_router
    from middlewares import AdminMiddleware, BanCheckMiddleware, RateLimitMiddleware
    from api import panel_api
    import state as bot_state

    # Reuse or create bot/dispatcher (cached in app)
    if "bot" not in request.app:
        await init_db()
        panel_api.reload_config()

        bot = Bot(token=token, default=DefaultBotProperties(parse_mode=ParseMode.HTML))
        bot_state.bot_instance = bot
        bot_state.loop_instance = asyncio.get_running_loop()

        dp = Dispatcher()
        dp.message.middleware(BanCheckMiddleware())
        dp.callback_query.middleware(BanCheckMiddleware())
        dp.callback_query.middleware(RateLimitMiddleware())

        dp.include_router(user_router)
        dp.include_router(wallet_router)
        dp.include_router(admin_router)
        dp.include_router(callback_router)

        request.app["bot"] = bot
        request.app["dp"] = dp

        # Start scheduler in background
        from scheduler import scheduler_loop
        request.app["scheduler_task"] = asyncio.create_task(scheduler_loop(bot))

        logging.info("Bot initialized (webhook mode)")

    dp = request.app["dp"]
    bot = request.app["bot"]

    try:
        update = json.loads(await request.text())
        from aiogram.types import Update
        telegram_update = Update.model_validate(update)
        await dp.feed_update(bot, telegram_update)
    except Exception as e:
        logging.error("Webhook processing error: %s", e)

    return web.Response(status=200)


async def health_check(request: web.Request):
    """Health check endpoint."""
    return web.json_response({"status": "ok"})


def create_app() -> web.Application:
    app = web.Application()

    app.on_startup.append(on_startup)
    app.on_shutdown.append(on_shutdown)

    app.router.add_post(WEBHOOK_PATH, webhook_handler)
    app.router.add_get("/health", health_check)

    return app


if __name__ == "__main__":
    logging.basicConfig(
        level=logging.INFO,
        format="%(asctime)s - %(name)s - %(levelname)s - %(message)s",
    )

    if not WEBHOOK_URL:
        logging.error(
            "WEBHOOK_URL not set! Set it in .env or pass as argument.\n"
            "Example: WEBHOOK_URL=https://yourdomain.com python run_webhook.py"
        )
        sys.exit(1)

    app = create_app()
    logging.info("Starting webhook server on port %d", WEBHOOK_PORT)
    web.run_app(app, host="0.0.0.0", port=WEBHOOK_PORT)
