"""Telegram channel implementation using python-telegram-bot."""

from __future__ import annotations

import asyncio
import re

from loguru import logger
from telegram import BotCommand, ReactionTypeEmoji, ReplyParameters, Update
from telegram.ext import Application, CommandHandler, ContextTypes, MessageHandler, filters
from telegram.request import HTTPXRequest

from sarathy.bus.events import OutboundMessage
from sarathy.bus.queue import MessageBus
from sarathy.channels.base import BaseChannel
from sarathy.channels.utils import detect_and_convert_tables
from sarathy.config.schema import TelegramConfig


def _markdown_to_telegram_html(text: str) -> str:
    """
    Convert markdown to Telegram-safe HTML.
    """
    if not text:
        return ""

    text = detect_and_convert_tables(text)

    # 1. Extract and protect code blocks (preserve content from other processing)
    code_blocks: list[str] = []

    def save_code_block(m: re.Match) -> str:
        code_blocks.append(m.group(1))
        return f"\x00CB{len(code_blocks) - 1}\x00"

    text = re.sub(r"```[\w]*\n?([\s\S]*?)```", save_code_block, text)

    # 2. Extract and protect inline code
    inline_codes: list[str] = []

    def save_inline_code(m: re.Match) -> str:
        inline_codes.append(m.group(1))
        return f"\x00IC{len(inline_codes) - 1}\x00"

    text = re.sub(r"`([^`]+)`", save_inline_code, text)

    # 3. Headers # Title -> just the title text
    text = re.sub(r"^#{1,6}\s+(.+)$", r"\1", text, flags=re.MULTILINE)

    # 4. Blockquotes > text -> just the text (before HTML escaping)
    text = re.sub(r"^>\s*(.*)$", r"\1", text, flags=re.MULTILINE)

    # 5. Escape HTML special characters
    text = text.replace("&", "&amp;").replace("<", "&lt;").replace(">", "&gt;")

    # 6. Links [text](url) - must be before bold/italic to handle nested cases
    text = re.sub(r"\[([^\]]+)\]\(([^)]+)\)", r'<a href="\2">\1</a>', text)

    # 7. Bold **text** or __text__
    text = re.sub(r"\*\*(.+?)\*\*", r"<b>\1</b>", text)
    text = re.sub(r"__(.+?)__", r"<b>\1</b>", text)

    # 8. Italic _text_ (avoid matching inside words like some_var_name)
    text = re.sub(r"(?<![a-zA-Z0-9])_([^_]+)_(?![a-zA-Z0-9])", r"<i>\1</i>", text)

    # 9. Strikethrough ~~text~~
    text = re.sub(r"~~(.+?)~~", r"<s>\1</s>", text)

    # 10. Bullet lists - item -> • item
    text = re.sub(r"^[-*]\s+", "• ", text, flags=re.MULTILINE)

    # 11. Restore inline code with HTML tags
    for i, code in enumerate(inline_codes):
        # Escape HTML in code content
        escaped = code.replace("&", "&amp;").replace("<", "&lt;").replace(">", "&gt;")
        text = text.replace(f"\x00IC{i}\x00", f"<code>{escaped}</code>")

    # 12. Restore code blocks with HTML tags
    for i, code in enumerate(code_blocks):
        # Escape HTML in code content
        escaped = code.replace("&", "&amp;").replace("<", "&lt;").replace(">", "&gt;")
        text = text.replace(f"\x00CB{i}\x00", f"<pre><code>{escaped}</code></pre>")

    return text


def _split_message(content: str, max_len: int = 4000) -> list[str]:
    """Split content into chunks within max_len, preferring line breaks."""
    if len(content) <= max_len:
        return [content]
    chunks: list[str] = []
    while content:
        if len(content) <= max_len:
            chunks.append(content)
            break
        cut = content[:max_len]
        pos = cut.rfind("\n")
        if pos == -1:
            pos = cut.rfind(" ")
        if pos == -1:
            pos = max_len
        chunks.append(content[:pos])
        content = content[pos:].lstrip()
    return chunks


class TelegramChannel(BaseChannel):
    """
    Telegram channel using long polling.

    Simple and reliable - no webhook/public IP needed.
    """

    name = "telegram"

    # Default commands registered with Telegram's command menu
    # Only /start and /help are local; all others come from CommandManager
    DEFAULT_COMMANDS = [
        BotCommand("start", "Start the bot"),
        BotCommand("help", "Show available commands"),
        BotCommand("streaming", "Toggle streaming mode"),
    ]

    def __init__(
        self,
        config: TelegramConfig,
        bus: MessageBus,
        command_manager=None,
    ):
        super().__init__(config, bus)
        self.config: TelegramConfig = config
        self.command_manager = command_manager
        self._app: Application | None = None
        self._chat_ids: dict[str, int] = {}  # Map sender_id to chat_id for replies
        self._typing_tasks: dict[str, asyncio.Task] = {}  # chat_id -> typing loop task
        self._registered_skill_commands: set[str] = set()
        self._streaming_enabled_chats: set[int] = set()  # Per-chat streaming override
        self._active_drafts: dict[int, int] = {}  # chat_id -> draft_id for streaming
        self._last_draft_update: dict[int, float] = {}  # chat_id -> last update timestamp
        self._draft_throttle_ms: int = 500  # Throttle drafts to every 500ms
        self._active_message_count: dict[int, int] = {}  # chat_id -> count of active messages

    async def start(self) -> None:
        """Start the Telegram bot with long polling."""
        if not self.config.token:
            logger.error("Telegram bot token not configured")
            return

        self._running = True

        # Build the application with larger connection pool to avoid pool-timeout on long runs
        req = HTTPXRequest(
            connection_pool_size=16, pool_timeout=5.0, connect_timeout=30.0, read_timeout=30.0
        )
        builder = (
            Application.builder().token(self.config.token).request(req).get_updates_request(req)
        )
        if self.config.proxy:
            builder = builder.proxy(self.config.proxy).get_updates_proxy(self.config.proxy)
        self._app = builder.build()
        self._app.add_error_handler(self._on_error)

        # Add command handlers - only /start, /help, /streaming are local, rest go to agent loop
        self._app.add_handler(CommandHandler("start", self._on_start))
        self._app.add_handler(CommandHandler("help", self._on_help))
        self._app.add_handler(CommandHandler("streaming", self._on_streaming))

        # Forward all other commands to agent loop for unified handling
        self._app.add_handler(MessageHandler(filters.COMMAND, self._forward_all_commands))

        # Add message handler for text, photos, voice, documents
        self._app.add_handler(
            MessageHandler(
                (
                    filters.TEXT
                    | filters.PHOTO
                    | filters.VOICE
                    | filters.AUDIO
                    | filters.Document.ALL
                )
                & ~filters.COMMAND,
                self._on_message,
            )
        )

        logger.info("Starting Telegram bot (polling mode)...")

        # Initialize and start polling
        await self._app.initialize()
        await self._app.start()

        # Get bot info and register command menu
        bot_info = await self._app.bot.get_me()
        logger.info("Telegram bot @{} connected", bot_info.username)

        # Register commands (default + dynamic from skills)
        await self._register_commands()

        # Register callback for command updates if command_manager is available
        if self.command_manager:
            self.command_manager.on_update(self._on_commands_updated)

        # Start polling (this runs until stopped)
        await self._app.updater.start_polling(
            allowed_updates=["message"],
            drop_pending_updates=True,  # Ignore old messages on startup
        )

        # Keep running until stopped
        while self._running:
            await asyncio.sleep(1)

    async def _register_commands(self) -> None:
        """Register bot commands with Telegram."""
        commands = list(self.DEFAULT_COMMANDS)

        # Add dynamic commands from command_manager
        if self.command_manager:
            for cmd_info in self.command_manager.get_all_commands():
                # Telegram doesn't support hyphens in bot commands
                if "-" in cmd_info.name:
                    logger.debug(
                        "Skipping command '{}' for Telegram (hyphens not supported)", cmd_info.name
                    )
                    continue
                commands.append(BotCommand(cmd_info.name, cmd_info.description))

                # Add handler for skill command if not already registered
                if cmd_info.name not in self._registered_skill_commands:
                    self._app.add_handler(CommandHandler(cmd_info.name, self._handle_skill_command))
                    self._registered_skill_commands.add(cmd_info.name)

        try:
            await self._app.bot.set_my_commands(commands)
            logger.debug(f"Registered {len(commands)} bot commands")
        except Exception as e:
            logger.warning("Failed to register bot commands: {}", e)

    async def _on_commands_updated(self) -> None:
        """Handle command updates from command manager."""
        logger.info("Commands updated, re-registering...")
        await self._register_commands()

    async def _handle_skill_command(
        self, update: Update, context: ContextTypes.DEFAULT_TYPE
    ) -> None:
        """Handle skill-based slash commands."""
        if not update.message or not context.args is not None:
            return

        command_name = context.command

        # Show help if no arguments provided
        if not context.args:
            if self.command_manager:
                help_text = self.command_manager.get_command_help(command_name)
                if help_text:
                    await update.message.reply_text(help_text)
                else:
                    await update.message.reply_text(
                        f"Command /{command_name} is available but no help text is defined."
                    )
            return

        # Forward to agent for processing
        args_text = " ".join(context.args)
        await self._handle_message(
            sender_id=self._sender_id(update.effective_user),
            chat_id=str(update.message.chat_id),
            content=f"/{command_name} {args_text}",
        )

    async def stop(self) -> None:
        """Stop the Telegram bot."""
        self._running = False

        # Cancel all typing indicators
        for chat_id in list(self._typing_tasks):
            self._stop_typing(chat_id)

        if self._app:
            logger.info("Stopping Telegram bot...")
            await self._app.updater.stop()
            await self._app.stop()
            await self._app.shutdown()
            self._app = None

    @staticmethod
    def _get_media_type(path: str) -> str:
        """Guess media type from file extension."""
        ext = path.rsplit(".", 1)[-1].lower() if "." in path else ""
        if ext in ("jpg", "jpeg", "png", "gif", "webp"):
            return "photo"
        if ext == "ogg":
            return "voice"
        if ext in ("mp3", "m4a", "wav", "aac"):
            return "audio"
        return "document"

    async def send(self, msg: OutboundMessage) -> None:
        """Send a message through Telegram."""
        if not self._app:
            logger.warning("Telegram bot not running")
            return

        is_progress = msg.metadata.get("_progress", False)

        # Handle progress messages
        if is_progress:
            if self.config.streaming:
                await self._send_progress(msg)
            # If not streaming, skip progress (or could send as separate messages)
            return

        # Final message
        await self._send_final(msg)

    async def _send_progress(self, msg: OutboundMessage) -> None:
        """Send a progress message (streaming) using sendMessageDraft API."""
        if not msg.content:
            return

        chat_id_str = str(msg.chat_id)
        try:
            chat_id_int = int(chat_id_str)
        except ValueError:
            logger.error("Invalid chat_id: {}", msg.chat_id)
            return

        is_tool_hint = msg.metadata.get("_tool_hint", False)
        prefix = "🔧 " if is_tool_hint else "↳ "

        import time

        now = time.time() * 1000
        last_update = self._last_draft_update.get(chat_id_int, 0)
        if now - last_update < self._draft_throttle_ms:
            return

        try:
            html = _markdown_to_telegram_html(prefix + msg.content)
            draft_id = self._active_drafts.get(chat_id_int)

            if draft_id:
                await self._app.bot.send_message_draft(
                    chat_id=chat_id_int,
                    draft_id=draft_id,
                    text=html,
                    parse_mode="HTML",
                )
            else:
                await self._app.bot.send_message_draft(
                    chat_id=chat_id_int,
                    draft_id=chat_id_int,
                    text=html,
                    parse_mode="HTML",
                )
                self._active_drafts[chat_id_int] = chat_id_int

            self._last_draft_update[chat_id_int] = now
        except Exception as e:
            logger.warning("Failed to send progress draft: {}", e)

    async def _send_final(self, msg: OutboundMessage) -> None:
        """Send the final message."""
        chat_id_str = str(msg.chat_id)
        try:
            chat_id_int = int(chat_id_str)
        except ValueError:
            logger.error("Invalid chat_id: {}", msg.chat_id)
            return

        is_final = msg.metadata.get("_final", True)
        draft_id = self._active_drafts.get(chat_id_int)
        draft_finalized = False

        # Build reply_params FIRST (before draft handling)
        reply_params = None
        if self.config.reply_to_message:
            reply_to_message_id = msg.metadata.get("message_id")
            if reply_to_message_id:
                reply_params = ReplyParameters(
                    message_id=reply_to_message_id, allow_sending_without_reply=True
                )

        if is_final:
            # Check if more messages pending before stopping typing
            self._active_message_count[chat_id_int] = (
                self._active_message_count.get(chat_id_int, 1) - 1
            )
            remaining = self._active_message_count.get(chat_id_int, 0)
            if remaining <= 0:
                logger.info("Telegram: stopping typing (all done) for chat_id={}", chat_id_str)
                self._stop_typing(chat_id_str)
                self._active_message_count[chat_id_int] = 0
            else:
                logger.info(
                    "Telegram: keeping typing ON ({} pending) for chat_id={}",
                    remaining,
                    chat_id_str,
                )
            if draft_id:
                try:
                    content = msg.content or ""
                    if content and content != "[empty message]":
                        html = _markdown_to_telegram_html(content)
                        await self._app.bot.send_message(
                            chat_id=chat_id_int,
                            text=html,
                            parse_mode="HTML",
                            reply_parameters=reply_params,  # Pass reply_params to draft!
                        )
                        draft_finalized = True
                    self._active_drafts.pop(chat_id_int, None)
                    self._last_draft_update.pop(chat_id_int, None)
                except Exception as e:
                    logger.warning("Failed to finalize draft: {}", e)
                    self._active_drafts.pop(chat_id_int, None)
                    self._last_draft_update.pop(chat_id_int, None)
        else:
            logger.info(
                "Telegram: NOT stopping typing (intermediate message) for chat_id={}", chat_id_str
            )

        # Send media files
        for media_path in msg.media or []:
            try:
                media_type = self._get_media_type(media_path)
                sender = {
                    "photo": self._app.bot.send_photo,
                    "voice": self._app.bot.send_voice,
                    "audio": self._app.bot.send_audio,
                }.get(media_type, self._app.bot.send_document)
                param = (
                    "photo"
                    if media_type == "photo"
                    else media_type
                    if media_type in ("voice", "audio")
                    else "document"
                )
                with open(media_path, "rb") as f:
                    await sender(chat_id=chat_id_int, **{param: f}, reply_parameters=reply_params)
            except Exception as e:
                filename = media_path.rsplit("/", 1)[-1]
                logger.error("Failed to send media {}: {}", media_path, e)
                await self._app.bot.send_message(
                    chat_id=chat_id_int,
                    text=f"[Failed to send: {filename}]",
                    reply_parameters=reply_params,
                )

        # Send text content (skip if draft was already finalized)
        if msg.content and msg.content != "[empty message]" and not draft_finalized:
            for chunk in _split_message(msg.content):
                try:
                    html = _markdown_to_telegram_html(chunk)
                    await self._app.bot.send_message(
                        chat_id=chat_id_int,
                        text=html,
                        parse_mode="HTML",
                        reply_parameters=reply_params,
                    )
                except Exception as e:
                    logger.warning("HTML parse failed, falling back to plain text: {}", e)
                    try:
                        await self._app.bot.send_message(
                            chat_id=chat_id_int, text=chunk, reply_parameters=reply_params
                        )
                    except Exception as e2:
                        logger.error("Error sending Telegram message: {}", e2)

        # Remove reaction from the user's message if enabled
        if is_final and self.config.react_to_message and self._app:
            original_message_id = msg.metadata.get("message_id")
            if original_message_id:
                try:
                    await self._app.bot.set_message_reaction(
                        chat_id=chat_id_int,
                        message_id=original_message_id,
                        reaction=[],  # Empty array removes all reactions
                    )
                    logger.debug("Telegram: removed reaction from message {}", original_message_id)
                except Exception as e:
                    logger.warning("Failed to remove reaction: {}", e)

    async def _on_start(self, update: Update, context: ContextTypes.DEFAULT_TYPE) -> None:
        """Handle /start command."""
        if not update.message or not update.effective_user:
            return

        user = update.effective_user
        await update.message.reply_text(
            f"👋 Hi {user.first_name}! I'm sarathy.\n\n"
            "Send me a message and I'll respond!\n"
            "Type /help to see available commands."
        )

    async def _on_help(self, update: Update, context: ContextTypes.DEFAULT_TYPE) -> None:
        """Handle /help command, bypassing ACL so all users can access it."""
        if not update.message:
            return

        lines = ["🪆 Available commands:"]

        # Get built-in and skill commands from command manager
        if self.command_manager:
            for cmd in self.command_manager.get_all_commands():
                lines.append(f"/{cmd.name} — {cmd.description}")

        await update.message.reply_text("\n".join(lines))

    async def _on_streaming(self, update: Update, context: ContextTypes.DEFAULT_TYPE) -> None:
        """Handle /streaming command - toggle streaming mode for this chat."""
        if not update.message or not update.message.chat_id:
            return

        chat_id = update.message.chat_id

        args = ""
        if update.message.text:
            parts = update.message.text.strip().split(None, 1)
            if len(parts) > 1:
                args = parts[1].strip().lower()

        if args == "status":
            current = chat_id in self._streaming_enabled_chats
            await update.message.reply_text(f"🔴 Streaming: {'enabled' if current else 'disabled'}")
        elif args in ("false", "off", "0"):
            self._streaming_enabled_chats.discard(chat_id)
            await update.message.reply_text("🔴 Streaming disabled for this chat.")
        elif args in ("true", "on", "1"):
            self._streaming_enabled_chats.add(chat_id)
            await update.message.reply_text("🟢 Streaming enabled for this chat.")
        else:
            current = chat_id in self._streaming_enabled_chats
            await update.message.reply_text(
                f"Usage: /streaming [true|false|status]\nCurrent: {'enabled' if current else 'disabled'}"
            )

    @staticmethod
    def _sender_id(user) -> str:
        """Build sender_id with username for allowlist matching."""
        sid = str(user.id)
        return f"{sid}|{user.username}" if user.username else sid

    async def _forward_command(self, update: Update, context: ContextTypes.DEFAULT_TYPE) -> None:
        """Forward slash commands to the bus for unified handling in AgentLoop."""
        if not update.message or not update.effective_user:
            return
        await self._handle_message(
            sender_id=self._sender_id(update.effective_user),
            chat_id=str(update.message.chat_id),
            content=update.message.text,
        )

    async def _forward_all_commands(
        self, update: Update, context: ContextTypes.DEFAULT_TYPE
    ) -> None:
        """Forward all slash commands (except /start, /help, /streaming) to agent loop."""
        if not update.message or not update.effective_user:
            return

        command = update.message.text.strip().lower()

        # Skip /start, /help, /streaming - they have local handlers
        if (
            command.startswith("/start")
            or command.startswith("/help")
            or command.startswith("/streaming")
        ):
            return

        await self._handle_message(
            sender_id=self._sender_id(update.effective_user),
            chat_id=str(update.message.chat_id),
            content=update.message.text,
        )

    async def _on_message(self, update: Update, context: ContextTypes.DEFAULT_TYPE) -> None:
        """Handle incoming messages (text, photos, voice, documents)."""
        if not update.message or not update.effective_user:
            return

        message = update.message
        user = update.effective_user
        chat_id = message.chat_id
        sender_id = self._sender_id(user)

        # Store chat_id for replies
        self._chat_ids[sender_id] = chat_id

        # Build content from text and/or media
        content_parts = []
        media_paths = []

        # Text content
        if message.text:
            content_parts.append(message.text)
        if message.caption:
            content_parts.append(message.caption)

        # Handle media files
        media_file = None
        media_type = None

        if message.photo:
            media_file = message.photo[-1]  # Largest photo
            media_type = "image"
        elif message.voice:
            media_file = message.voice
            media_type = "voice"
        elif message.audio:
            media_file = message.audio
            media_type = "audio"
        elif message.document:
            media_file = message.document
            media_type = "file"

        # Download media if present
        if media_file and self._app:
            # Send download progress if streaming is enabled
            if self.config.streaming:
                try:
                    from sarathy.bus.events import OutboundMessage

                    await self._send_progress(
                        OutboundMessage(
                            channel="telegram",
                            chat_id=str(chat_id),
                            content="📥 Downloading...",
                            metadata={"_progress": True},
                        )
                    )
                except Exception as e:
                    logger.debug("Failed to send download progress: {}", e)

            try:
                file = await self._app.bot.get_file(media_file.file_id)
                ext = self._get_extension(media_type, getattr(media_file, "mime_type", None))

                # Save to workspace/media/
                from pathlib import Path

                media_dir = Path.home() / ".sarathy" / "media"
                media_dir.mkdir(parents=True, exist_ok=True)

                file_path = media_dir / f"{media_file.file_id[:16]}{ext}"
                await file.download_to_drive(str(file_path))

                media_paths.append(str(file_path))

                content_parts.append(f"[{media_type}: {file_path}]")

                logger.debug("Downloaded {} to {}", media_type, file_path)
            except Exception as e:
                logger.error("Failed to download media: {}", e)
                content_parts.append(f"[{media_type}: download failed]")

        content = "\n".join(content_parts) if content_parts else "[empty message]"

        logger.debug("Telegram message from {}: {}...", sender_id, content[:50])

        str_chat_id = str(chat_id)

        # Start typing indicator before processing
        self._start_typing(str_chat_id)

        # Track active message count
        chat_id_int = int(str_chat_id)
        self._active_message_count[chat_id_int] = self._active_message_count.get(chat_id_int, 0) + 1

        # Add reaction to the user's message if enabled
        if self.config.react_to_message and self._app:
            try:
                emoji = self.config.reaction_emoji or "👀"
                await self._app.bot.set_message_reaction(
                    chat_id=chat_id_int,
                    message_id=message.message_id,
                    reaction=[ReactionTypeEmoji(emoji=emoji)],
                )
                logger.debug("Telegram: added {} reaction to message {}", emoji, message.message_id)
            except Exception as e:
                logger.warning("Failed to set reaction: {}", e)

        # Send "Sending to sarathy..." progress if media was attached and streaming is enabled
        if media_paths and self.config.streaming:
            try:
                from sarathy.bus.events import OutboundMessage

                user_name = user.first_name or "you"
                await self._send_progress(
                    OutboundMessage(
                        channel="telegram",
                        chat_id=str_chat_id,
                        content=f"📬 {user_name}, sending to sarathy...",
                        metadata={"_progress": True},
                    )
                )
            except Exception as e:
                logger.debug("Failed to send processing progress: {}", e)

        # Forward to the message bus
        await self._handle_message(
            sender_id=sender_id,
            chat_id=str_chat_id,
            content=content,
            media=media_paths,
            metadata={
                "message_id": message.message_id,
                "user_id": user.id,
                "username": user.username,
                "first_name": user.first_name,
                "is_group": message.chat.type != "private",
            },
        )

    def _start_typing(self, chat_id: str) -> None:
        """Start sending 'typing...' indicator for a chat."""
        # Cancel any existing typing task for this chat
        self._stop_typing(chat_id)
        logger.info("Telegram: starting typing indicator for chat_id={}", chat_id)
        self._typing_tasks[chat_id] = asyncio.create_task(self._typing_loop(chat_id))

    def _stop_typing(self, chat_id: str) -> None:
        """Stop the typing indicator for a chat."""
        task = self._typing_tasks.pop(chat_id, None)
        if task and not task.done():
            task.cancel()

    async def _typing_loop(self, chat_id: str) -> None:
        """Repeatedly send 'typing' action until cancelled. Includes TTL safety net."""
        import time

        typing_ttl_seconds = 600  # 10 minutes TTL safety net
        start_time = time.monotonic()
        try:
            while self._app:
                # Check TTL - stop after 2 minutes to prevent stuck indicators
                if time.monotonic() - start_time > typing_ttl_seconds:
                    logger.debug(
                        "Typing TTL reached ({}s); stopping typing indicator", typing_ttl_seconds
                    )
                    self._stop_typing(chat_id)
                    break
                await self._app.bot.send_chat_action(chat_id=int(chat_id), action="typing")
                await asyncio.sleep(4)
        except asyncio.CancelledError:
            pass
        except Exception as e:
            logger.debug("Typing indicator stopped for {}: {}", chat_id, e)

    async def _on_error(self, update: object, context: ContextTypes.DEFAULT_TYPE) -> None:
        """Log polling / handler errors instead of silently swallowing them."""
        logger.error("Telegram error: {}", context.error)

    def _get_extension(self, media_type: str, mime_type: str | None) -> str:
        """Get file extension based on media type."""
        if mime_type:
            ext_map = {
                "image/jpeg": ".jpg",
                "image/png": ".png",
                "image/gif": ".gif",
                "audio/ogg": ".ogg",
                "audio/mpeg": ".mp3",
                "audio/mp4": ".m4a",
            }
            if mime_type in ext_map:
                return ext_map[mime_type]

        type_map = {"image": ".jpg", "voice": ".ogg", "audio": ".mp3", "file": ""}
        return type_map.get(media_type, "")
