"""Application entry point: build bot Application, run HTTP server + polling."""

import asyncio
import json
import logging
import sys
import threading
import time
import urllib.request

from telegram.ext import ApplicationBuilder

from duty_teller import config
from duty_teller.config import require_bot_token
from duty_teller.handlers import group_duty_pin, register_handlers
from duty_teller.utils.http_client import safe_urlopen

# Seconds to wait for HTTP server to bind before health check.
_HTTP_STARTUP_WAIT_SEC = 3


async def _resolve_bot_username(application) -> None:
    """If BOT_USERNAME is not set from env, resolve it via get_me()."""
    if not config.BOT_USERNAME:
        me = await application.bot.get_me()
        config.BOT_USERNAME = (me.username or "").lower()
        logger.info("Resolved BOT_USERNAME from API: %s", config.BOT_USERNAME)


logging.basicConfig(
    format="%(asctime)s - %(name)s - %(levelname)s - %(message)s",
    level=config.LOG_LEVEL,
)
logger = logging.getLogger(__name__)


def _set_default_menu_button_webapp() -> None:
    if not (config.MINI_APP_BASE_URL and config.BOT_TOKEN):
        return
    menu_url = (config.MINI_APP_BASE_URL.rstrip("/") + "/app/").strip()
    if not menu_url.startswith("https://"):
        return
    payload = {
        "menu_button": {
            "type": "web_app",
            "text": "Calendar",
            "web_app": {"url": menu_url},
        }
    }
    req = urllib.request.Request(
        f"https://api.telegram.org/bot{config.BOT_TOKEN}/setChatMenuButton",
        data=json.dumps(payload).encode(),
        headers={"Content-Type": "application/json"},
        method="POST",
    )
    try:
        with safe_urlopen(req, timeout=10) as resp:
            if resp.status == 200:
                logger.info("Default menu button set to Web App: %s", menu_url)
            else:
                logger.warning("setChatMenuButton returned %s", resp.status)
    except Exception as e:
        logger.warning("Could not set menu button: %s", e)


def _run_uvicorn(web_app, port: int) -> None:
    import uvicorn

    loop = asyncio.new_event_loop()
    asyncio.set_event_loop(loop)
    server = uvicorn.Server(
        uvicorn.Config(web_app, host=config.HTTP_HOST, port=port, log_level="info"),
    )
    loop.run_until_complete(server.serve())


def _wait_for_http_ready(port: int) -> bool:
    """Return True if /health responds successfully within _HTTP_STARTUP_WAIT_SEC."""
    host = config.HTTP_HOST
    if host not in config.LOOPBACK_HTTP_HOSTS:
        host = "127.0.0.1"
    url = f"http://{host}:{port}/health"
    deadline = time.monotonic() + _HTTP_STARTUP_WAIT_SEC
    while time.monotonic() < deadline:
        try:
            req = urllib.request.Request(url)
            with safe_urlopen(req, timeout=2) as resp:
                if resp.status == 200:
                    return True
        except Exception as e:
            logger.debug("Health check not ready yet: %s", e)
        time.sleep(0.5)
    return False


def main() -> None:
    """Build the bot and FastAPI, start uvicorn in a thread, run polling."""
    require_bot_token()
    # Optional: set bot menu button to open the Miniapp. Uncomment to enable:
    # _set_default_menu_button_webapp()
    app = (
        ApplicationBuilder()
        .token(config.BOT_TOKEN)
        .post_init(group_duty_pin.restore_group_pin_jobs)
        .post_init(_resolve_bot_username)
        .build()
    )
    register_handlers(app)

    from duty_teller.api.app import app as web_app

    if config.MINI_APP_SKIP_AUTH:
        logger.warning(
            "MINI_APP_SKIP_AUTH is set — API auth disabled (insecure); use only for dev"
        )
        if config.HTTP_HOST not in config.LOOPBACK_HTTP_HOSTS:
            print(
                "ERROR: MINI_APP_SKIP_AUTH must not be used in production (non-localhost).",
                file=sys.stderr,
            )
            sys.exit(1)

    t = threading.Thread(
        target=_run_uvicorn,
        args=(web_app, config.HTTP_PORT),
        daemon=False,
    )
    t.start()

    if not _wait_for_http_ready(config.HTTP_PORT):
        logger.error(
            "HTTP server did not become ready on port %s within %s s; check port and permissions.",
            config.HTTP_PORT,
            _HTTP_STARTUP_WAIT_SEC,
        )
        sys.exit(1)
    logger.info("Bot starting (polling)... HTTP API on port %s", config.HTTP_PORT)
    app.run_polling(allowed_updates=["message", "my_chat_member"])
