from __future__ import annotations import logging from .graph import MSTeamsGraphClient logger = logging.getLogger(__name__) async def get_message( graph_client: MSTeamsGraphClient, chat_id: str, message_id: str, ) -> dict | None: path = f"/chats/{chat_id}/messages/{message_id}" try: data = await graph_client.fetch_json(path) return _parse_message(data) except Exception as e: logger.warning("Failed to get message %s from chat %s: %s", message_id, chat_id, e) return None async def search_messages( graph_client: MSTeamsGraphClient, chat_id: str, query: str, *, limit: int = 20, ) -> list[dict]: path = f'/chats/{chat_id}/messages?$search="{query}"&$top={limit}' try: data = await graph_client.fetch_json(path) return _parse_messages(data) except Exception as e: logger.warning("Failed to search messages in chat %s: %s", chat_id, e) return [] async def pin_message( graph_client: MSTeamsGraphClient, chat_id: str, message_id: str, ) -> bool: path = f"/chats/{chat_id}/pinnedMessages" body = {"message@odata.bind": f"https://graph.microsoft.com/v1.0/chats/{chat_id}/messages/{message_id}"} try: await graph_client.fetch_json(path, method="POST", body=body) return True except Exception as e: logger.warning("Failed to pin message %s in chat %s: %s", message_id, chat_id, e) return False async def unpin_message( graph_client: MSTeamsGraphClient, chat_id: str, pinned_message_id: str, ) -> bool: path = f"/chats/{chat_id}/pinnedMessages/{pinned_message_id}" try: await graph_client.fetch_json(path, method="DELETE") return True except Exception as e: logger.warning("Failed to unpin message %s in chat %s: %s", pinned_message_id, chat_id, e) return False async def list_pinned_messages( graph_client: MSTeamsGraphClient, chat_id: str, ) -> list[dict]: path = f"/chats/{chat_id}/pinnedMessages?$expand=message" try: data = await graph_client.fetch_json(path) return data.get("value", []) except Exception as e: logger.warning("Failed to list pinned messages in chat %s: %s", chat_id, e) return [] async def set_reaction( graph_client: MSTeamsGraphClient, chat_id: str, message_id: str, reaction_type: str, user_id: str | None = None, ) -> bool: path = f"/chats/{chat_id}/messages/{message_id}/setReaction" body = {"reactionType": reaction_type} try: await graph_client.fetch_json(path, method="POST", body=body) return True except Exception as e: logger.warning("Failed to set reaction on message %s: %s", message_id, e) return False async def unset_reaction( graph_client: MSTeamsGraphClient, chat_id: str, message_id: str, reaction_type: str, user_id: str | None = None, ) -> bool: path = f"/chats/{chat_id}/messages/{message_id}/unsetReaction" body = {"reactionType": reaction_type} try: await graph_client.fetch_json(path, method="POST", body=body) return True except Exception as e: logger.warning("Failed to unset reaction on message %s: %s", message_id, e) return False def _parse_message(data: dict) -> dict: body = data.get("body", {}) from_info = data.get("from", {}) return { "id": data.get("id", ""), "text": body.get("content", ""), "content_type": body.get("contentType", "text"), "created_at": data.get("createdDateTime", ""), "last_modified_at": data.get("lastModifiedDateTime", ""), "from": from_info, "from_name": from_info.get("user", {}).get("displayName", ""), "message_type": data.get("messageType", "message"), "importance": data.get("importance", "normal"), "subject": data.get("subject", ""), "attachments": data.get("attachments", []), "reactions": data.get("reactions", []), } def _parse_messages(data: dict) -> list[dict]: messages = data.get("value", []) return [_parse_message(msg) for msg in messages]