import logging
from typing import List

import httpx
from sqlalchemy import select
from sqlalchemy.ext.asyncio import AsyncSession

from app.core.config import settings
from app.models import User, Participant, Marathon

logger = logging.getLogger(__name__)


class TelegramNotifier:
    """Service for sending Telegram notifications."""

    def __init__(self):
        self.bot_token = settings.TELEGRAM_BOT_TOKEN
        self.api_url = f"https://api.telegram.org/bot{self.bot_token}"

    async def send_message(
        self,
        chat_id: int,
        text: str,
        parse_mode: str = "HTML",
        reply_markup: dict | None = None
    ) -> bool:
        """Send a message to a Telegram chat."""
        if not self.bot_token:
            logger.warning("Telegram bot token not configured")
            return False

        try:
            async with httpx.AsyncClient() as client:
                payload = {
                    "chat_id": chat_id,
                    "text": text,
                    "parse_mode": parse_mode
                }
                if reply_markup:
                    payload["reply_markup"] = reply_markup

                response = await client.post(
                    f"{self.api_url}/sendMessage",
                    json=payload,
                    timeout=10.0
                )
                if response.status_code == 200:
                    return True
                else:
                    logger.error(f"Failed to send message: {response.text}")
                    return False
        except Exception as e:
            logger.error(f"Error sending Telegram message: {e}")
            return False

    async def notify_user(
        self,
        db: AsyncSession,
        user_id: int,
        message: str,
        reply_markup: dict | None = None
    ) -> bool:
        """Send notification to a user by user_id."""
        result = await db.execute(
            select(User).where(User.id == user_id)
        )
        user = result.scalar_one_or_none()

        if not user:
            logger.warning(f"[Notify] User {user_id} not found")
            return False

        if not user.telegram_id:
            logger.warning(f"[Notify] User {user_id} ({user.nickname}) has no telegram_id")
            return False

        logger.info(f"[Notify] Sending to user {user.nickname} (telegram_id={user.telegram_id})")
        return await self.send_message(user.telegram_id, message, reply_markup=reply_markup)

    async def notify_marathon_participants(
        self,
        db: AsyncSession,
        marathon_id: int,
        message: str,
        exclude_user_id: int | None = None
    ) -> int:
        """Send notification to all marathon participants with linked Telegram."""
        result = await db.execute(
            select(User)
            .join(Participant, Participant.user_id == User.id)
            .where(
                Participant.marathon_id == marathon_id,
                User.telegram_id.isnot(None)
            )
        )
        users = result.scalars().all()

        sent_count = 0
        for user in users:
            if exclude_user_id and user.id == exclude_user_id:
                continue
            if await self.send_message(user.telegram_id, message):
                sent_count += 1

        return sent_count

    # Notification templates
    async def notify_event_start(
        self,
        db: AsyncSession,
        marathon_id: int,
        event_type: str,
        marathon_title: str
    ) -> int:
        """Notify participants about event start."""
        event_messages = {
            "golden_hour": f"🌟 <b>Начался Golden Hour</b> в «{marathon_title}»!\n\nВсе очки x1.5 в течение часа!",
            "jackpot": f"🎰 <b>JACKPOT</b> в «{marathon_title}»!\n\nОчки x3 за следующий сложный челлендж!",
            "double_risk": f"⚡ <b>Double Risk</b> в «{marathon_title}»!\n\nПоловина очков, но дропы бесплатны!",
            "common_enemy": f"👥 <b>Common Enemy</b> в «{marathon_title}»!\n\nВсе получают одинаковый челлендж. Первые 3 — бонус!",
            "swap": f"🔄 <b>Swap</b> в «{marathon_title}»!\n\nМожно поменяться заданием с другим участником!",
            "game_choice": f"🎲 <b>Выбор игры</b> в «{marathon_title}»!\n\nВыбери игру и один из 3 челленджей!"
        }

        message = event_messages.get(
            event_type,
            f"📌 Новое событие в «{marathon_title}»!"
        )

        return await self.notify_marathon_participants(db, marathon_id, message)

    async def notify_event_end(
        self,
        db: AsyncSession,
        marathon_id: int,
        event_type: str,
        marathon_title: str
    ) -> int:
        """Notify participants about event end."""
        event_names = {
            "golden_hour": "Golden Hour",
            "jackpot": "Jackpot",
            "double_risk": "Double Risk",
            "common_enemy": "Common Enemy",
            "swap": "Swap",
            "game_choice": "Выбор игры"
        }

        event_name = event_names.get(event_type, "Событие")
        message = f"⏰ <b>{event_name}</b> в «{marathon_title}» завершён"

        return await self.notify_marathon_participants(db, marathon_id, message)

    async def notify_marathon_start(
        self,
        db: AsyncSession,
        marathon_id: int,
        marathon_title: str
    ) -> int:
        """Notify participants about marathon start."""
        message = (
            f"🚀 <b>Марафон «{marathon_title}» начался!</b>\n\n"
            f"Время крутить колесо и получить первое задание!"
        )
        return await self.notify_marathon_participants(db, marathon_id, message)

    async def notify_marathon_finish(
        self,
        db: AsyncSession,
        marathon_id: int,
        marathon_title: str
    ) -> int:
        """Notify participants about marathon finish."""
        message = (
            f"🏆 <b>Марафон «{marathon_title}» завершён!</b>\n\n"
            f"Зайди на сайт, чтобы увидеть итоговую таблицу!"
        )
        return await self.notify_marathon_participants(db, marathon_id, message)

    async def notify_dispute_raised(
        self,
        db: AsyncSession,
        user_id: int,
        marathon_title: str,
        challenge_title: str,
        assignment_id: int
    ) -> bool:
        """Notify user about dispute raised on their assignment."""
        logger.info(f"[Dispute] Sending notification to user_id={user_id} for assignment_id={assignment_id}")

        dispute_url = f"{settings.FRONTEND_URL}/assignments/{assignment_id}"
        logger.info(f"[Dispute] URL: {dispute_url}")

        # Telegram requires HTTPS for inline keyboard URLs
        use_inline_button = dispute_url.startswith("https://")

        if use_inline_button:
            message = (
                f"⚠️ <b>На твоё задание подан спор</b>\n\n"
                f"Марафон: {marathon_title}\n"
                f"Задание: {challenge_title}"
            )
            reply_markup = {
                "inline_keyboard": [[
                    {"text": "Открыть спор", "url": dispute_url}
                ]]
            }
        else:
            message = (
                f"⚠️ <b>На твоё задание подан спор</b>\n\n"
                f"Марафон: {marathon_title}\n"
                f"Задание: {challenge_title}\n\n"
                f"🔗 {dispute_url}"
            )
            reply_markup = None

        result = await self.notify_user(db, user_id, message, reply_markup=reply_markup)
        logger.info(f"[Dispute] Notification result: {result}")
        return result

    async def notify_dispute_resolved(
        self,
        db: AsyncSession,
        user_id: int,
        marathon_title: str,
        challenge_title: str,
        is_valid: bool
    ) -> bool:
        """Notify user about dispute resolution."""
        if is_valid:
            message = (
                f"❌ <b>Спор признан обоснованным</b>\n\n"
                f"Марафон: {marathon_title}\n"
                f"Задание: {challenge_title}\n\n"
                f"Задание возвращено. Выполни его заново."
            )
        else:
            message = (
                f"✅ <b>Спор отклонён</b>\n\n"
                f"Марафон: {marathon_title}\n"
                f"Задание: {challenge_title}\n\n"
                f"Твоё выполнение засчитано!"
            )
        return await self.notify_user(db, user_id, message)

    async def notify_game_approved(
        self,
        db: AsyncSession,
        user_id: int,
        marathon_title: str,
        game_title: str
    ) -> bool:
        """Notify user that their proposed game was approved."""
        message = (
            f"✅ <b>Твоя игра одобрена!</b>\n\n"
            f"Марафон: {marathon_title}\n"
            f"Игра: {game_title}\n\n"
            f"Теперь она доступна для всех участников."
        )
        return await self.notify_user(db, user_id, message)

    async def notify_game_rejected(
        self,
        db: AsyncSession,
        user_id: int,
        marathon_title: str,
        game_title: str
    ) -> bool:
        """Notify user that their proposed game was rejected."""
        message = (
            f"❌ <b>Твоя игра отклонена</b>\n\n"
            f"Марафон: {marathon_title}\n"
            f"Игра: {game_title}\n\n"
            f"Ты можешь предложить другую игру."
        )
        return await self.notify_user(db, user_id, message)

    async def notify_challenge_approved(
        self,
        db: AsyncSession,
        user_id: int,
        marathon_title: str,
        game_title: str,
        challenge_title: str
    ) -> bool:
        """Notify user that their proposed challenge was approved."""
        message = (
            f"✅ <b>Твой челлендж одобрен!</b>\n\n"
            f"Марафон: {marathon_title}\n"
            f"Игра: {game_title}\n"
            f"Задание: {challenge_title}\n\n"
            f"Теперь оно доступно для всех участников."
        )
        return await self.notify_user(db, user_id, message)

    async def notify_challenge_rejected(
        self,
        db: AsyncSession,
        user_id: int,
        marathon_title: str,
        game_title: str,
        challenge_title: str
    ) -> bool:
        """Notify user that their proposed challenge was rejected."""
        message = (
            f"❌ <b>Твой челлендж отклонён</b>\n\n"
            f"Марафон: {marathon_title}\n"
            f"Игра: {game_title}\n"
            f"Задание: {challenge_title}\n\n"
            f"Ты можешь предложить другой челлендж."
        )
        return await self.notify_user(db, user_id, message)


# Global instance
telegram_notifier = TelegramNotifier()
