"""
Context - Handler context object passed to every command/message handler.
"""

from typing import TYPE_CHECKING, Any, Dict, List, Optional

if TYPE_CHECKING:
    from zehnex.bot import ZentelBot


class Context:
    """
    Passed to every handler. Contains update data and helper methods.

    Example:
        @bot.command("start")
        async def start(ctx: Context):
            await ctx.reply(f"Salom, {ctx.first_name}!")
            await ctx.typing()
    """

    def __init__(self, update: Dict, bot: "ZentelBot"):
        self._update = update
        self.bot = bot

        self.message: Optional[Dict] = update.get("message")
        self.callback_query: Optional[Dict] = update.get("callback_query")
        self.inline_query: Optional[Dict] = update.get("inline_query")

        # Resolve message source
        _msg = self.message or (
            self.callback_query.get("message") if self.callback_query else None
        )

        self.chat_id: int = _msg["chat"]["id"] if _msg else 0
        self.message_id: int = _msg.get("message_id", 0) if _msg else 0
        self.text: str = (self.message or {}).get("text", "")
        self.data: str = (self.callback_query or {}).get("data", "")

        _user = (
            (self.message or {}).get("from")
            or (self.callback_query or {}).get("from")
            or {}
        )
        self.user_id: int = _user.get("id", 0)
        self.first_name: str = _user.get("first_name", "")
        self.last_name: str = _user.get("last_name", "")
        self.username: str = _user.get("username", "")
        self.is_bot: bool = _user.get("is_bot", False)

        self.args: List[str] = self.text.split()[1:] if self.text else []
        self.state: Dict[str, Any] = {}

    @property
    def full_name(self) -> str:
        return f"{self.first_name} {self.last_name}".strip()

    @property
    def mention(self) -> str:
        if self.username:
            return f"@{self.username}"
        return f'<a href="tg://user?id={self.user_id}">{self.first_name}</a>'

    async def reply(
        self,
        text: str,
        parse_mode: Optional[str] = None,
        keyboard=None,
        **kwargs,
    ) -> Dict:
        """Reply to current message."""
        return await self.bot.send_message(
            chat_id=self.chat_id,
            text=text,
            parse_mode=parse_mode,
            reply_to=self.message_id,
            keyboard=keyboard,
            **kwargs,
        )

    async def send(
        self,
        text: str,
        parse_mode: Optional[str] = None,
        keyboard=None,
        **kwargs,
    ) -> Dict:
        """Send message to current chat (without reply)."""
        return await self.bot.send_message(
            chat_id=self.chat_id,
            text=text,
            parse_mode=parse_mode,
            keyboard=keyboard,
            **kwargs,
        )

    async def typing(self):
        """Send 'typing...' action."""
        await self.bot.send_chat_action(self.chat_id, "typing")

    async def upload_document(self):
        """Send 'uploading document' action."""
        await self.bot.send_chat_action(self.chat_id, "upload_document")

    async def upload_video(self):
        """Send 'uploading video' action."""
        await self.bot.send_chat_action(self.chat_id, "upload_video")

    async def send_document(self, path: str, caption: Optional[str] = None, **kwargs):
        """Send a document file."""
        return await self.bot.send_document(
            chat_id=self.chat_id, document_path=path, caption=caption, **kwargs
        )

    async def send_video(self, path: str, caption: Optional[str] = None, **kwargs):
        """Send a video file."""
        return await self.bot.send_video(
            chat_id=self.chat_id, video_path=path, caption=caption, **kwargs
        )

    async def send_photo(self, path: str, caption: Optional[str] = None, **kwargs):
        """Send a photo."""
        return await self.bot.send_photo(
            chat_id=self.chat_id, photo_path=path, caption=caption, **kwargs
        )

    async def answer(self, text: Optional[str] = None, show_alert: bool = False):
        """Answer callback query."""
        if self.callback_query:
            await self.bot.answer_callback_query(
                self.callback_query["id"], text=text, show_alert=show_alert
            )

    async def delete(self):
        """Delete the current message."""
        await self.bot.delete_message(self.chat_id, self.message_id)

    def __repr__(self):
        return f"<Context user={self.user_id} chat={self.chat_id}>"
