import asyncio
import logging
from typing import Optional, Any
from nonebot.adapters.onebot.v11 import Bot, Message

from .config import Config

logger = logging.getLogger("horse_racing.message_service")


class MessageService:
    def __init__(self, config: Config):
        self.config = config
        self.pending_recalls: dict[str, list[asyncio.Task]] = {}
        self.last_messages: dict[str, dict[str, str]] = {}  # scope -> {message_type -> message_id}

    async def send_with_recall(
        self,
        bot: Bot,
        scope: str,
        message_type: str,
        message: str | Message,
    ) -> Optional[str]:
        """Send message and schedule recall if configured. 
        If it's a 'race_update', recall the previous one first."""
        try:
            # For race_update, recall the previous one in the same scope
            if message_type == "race_update":
                await self.recall_previous_of_type(bot, scope, "race_update")

            # Send the message
            is_group = scope.startswith("group_")
            result = await bot.send_msg(
                message_type="group" if is_group else "private",
                group_id=int(scope.split("_", 1)[1]) if is_group else None,
                user_id=int(scope.split("_", 1)[1]) if not is_group else None,
                message=message,
            )
            
            message_id = result.get("message_id") if isinstance(result, dict) else None
            if not message_id:
                return None

            # Track the last message of this type
            if scope not in self.last_messages:
                self.last_messages[scope] = {}
            self.last_messages[scope][message_type] = message_id

            # Schedule auto-recall if configured
            recall_delay = self.config.MESSAGE_RECALL.get(message_type, 0)
            if recall_delay > 0:
                task = asyncio.create_task(
                    self._schedule_recall(bot, scope, message_id, recall_delay)
                )
                if scope not in self.pending_recalls:
                    self.pending_recalls[scope] = []
                self.pending_recalls[scope].append(task)

            return message_id
        except Exception as e:
            return None

    async def recall_previous_of_type(self, bot: Bot, scope: str, message_type: str):
        """Recall the previous message of a specific type in a scope."""
        if scope in self.last_messages and message_type in self.last_messages[scope]:
            old_message_id = self.last_messages[scope][message_type]
            try:
                await bot.delete_msg(message_id=old_message_id)
            except Exception:
                logger.debug("recall_previous_of_type: failed to delete msg %s", old_message_id, exc_info=True)
            del self.last_messages[scope][message_type]

    async def _schedule_recall(
        self,
        bot: Bot,
        scope: str,
        message_id: str,
        delay: int,
    ):
        """Schedule message recall after a delay."""
        try:
            await asyncio.sleep(delay)
            await bot.delete_msg(message_id=message_id)
        except Exception:
            logger.debug("_schedule_recall: failed to delete msg %s after %ds delay", message_id, delay, exc_info=True)

    def clear_pending_recalls(self, scope: str):
        """Cancel all pending recall tasks for a scope and clear last messages."""
        if scope in self.pending_recalls:
            for task in self.pending_recalls[scope]:
                if not task.done():
                    task.cancel()
            del self.pending_recalls[scope]
        
        if scope in self.last_messages:
            del self.last_messages[scope]

    def clear_all_recalls(self):
        """Cancel all pending recall tasks."""
        for scope in list(self.pending_recalls.keys()):
            self.clear_pending_recalls(scope)
