from __future__ import annotations from typing import Any from yuxi.channels.adapters.bluebubbles.client import BlueBubblesClient from yuxi.utils.logging_config import logger def normalize_bluebubbles_handle(handle: str) -> str: return handle.strip().lstrip("+") def parse_target(target: str) -> dict[str, str]: result: dict[str, str] = {"type": "unknown", "value": target} if target.startswith("chat_guid:"): result["type"] = "chat_guid" result["value"] = target[len("chat_guid:") :] elif target.startswith("group:"): result["type"] = "group_identifier" result["value"] = target[len("group:") :] elif target.startswith("chat_id:"): result["type"] = "chat_id" result["value"] = target[len("chat_id:") :] elif target.startswith("handle:"): result["type"] = "handle" result["value"] = normalize_bluebubbles_handle(target[len("handle:") :]) elif target.startswith("+"): result["type"] = "handle" result["value"] = normalize_bluebubbles_handle(target) elif ";" in target: result["type"] = "group_identifier" result["value"] = target else: result["type"] = "chat_guid" result["value"] = target return result async def resolve_chat_guid( client: BlueBubblesClient, target: str, ) -> str | None: parsed = parse_target(target) if parsed["type"] == "chat_guid": return parsed["value"] if parsed["type"] == "handle": chats = await _query_chats(client) for chat in chats: participants = chat.get("participants", []) if len(participants) == 1: addr = participants[0].get("address", "") if normalize_bluebubbles_handle(addr) == normalize_bluebubbles_handle(parsed["value"]): return chat.get("guid") return None if parsed["type"] == "group_identifier": chats = await _query_chats(client) for chat in chats: display_name = chat.get("displayName", "") if display_name == parsed["value"]: return chat.get("guid") return None return parsed["value"] async def resolve_chat_guid_with_auto_create( client: BlueBubblesClient, target: str, initial_text: str = "", ) -> str | None: guid = await resolve_chat_guid(client, target) if guid: return guid parsed = parse_target(target) if parsed["type"] not in ("handle",): return None from yuxi.channels.adapters.bluebubbles.send import auto_create_chat try: new = await auto_create_chat(client, parsed["value"], initial_text) return new.get("chatGuid") except Exception: logger.warning("[BlueBubbles] Auto-create chat failed for target=%s", target) return None async def _query_chats(client: BlueBubblesClient) -> list[dict[str, Any]]: try: result = await client.get("/api/v1/chat/query") return result.get("data", []) except Exception: logger.warning("[BlueBubbles] Failed to query chats for target resolution") return []