"""fmessage 系统消息 XML 解析器。

解析微信 4.x Linux 的 fmessage sysmsg XML，提取好友申请信息。
无状态函数，便于单测。

XML 格式（推断，需环境验证）：
<sysmsg type="verifyUser" ...>
  <Link ...>
    <UserName>xxx@stranger</UserName>
    <NickName>申请人昵称</NickName>
    <Content>验证消息内容</Content>
    <Scene>...</Scene>
  </Link>
</sysmsg>
"""

from __future__ import annotations

import logging
import xml.etree.ElementTree as ET
from typing import Optional

from woc_bridge.models.contact import FriendRequestInfo

logger = logging.getLogger("woc-bridge")


# 可能的好友申请 XML 类型标记（大小写不敏感）
_VERIFYUSER_TYPES = {"verifyuser", "verify_user", "verification"}


def parse_friend_request(
    content: str, create_time: int, msg_local_id: int
) -> Optional[FriendRequestInfo]:
    """解析 fmessage 系统消息 XML，提取好友申请信息。

    兼容多种实际格式：
    - <sysmsg type="verifyUser"><Link><UserName>...</UserName>...</Link></sysmsg>
    - <sysmsg type="verifyUser"><verifyuser><username>...</username>...</verifyuser></sysmsg>
    - <verifyuser>...</verifyuser> 根节点
    - 标签大小写/命名空间不一致

    Args:
        content: message_content 原始文本（XML）
        create_time: 消息时间戳
        msg_local_id: 消息 local_id

    Returns:
        FriendRequestInfo 或 None（解析失败 / 非 verifyUser 类型）
    """
    if not content or not content.strip():
        return None

    try:
        root = ET.fromstring(content)
    except ET.ParseError:
        # 部分消息可能不是合法 XML（如纯文本通知），跳过
        return None

    # 1. 判断是否为好友申请类型
    if not _is_verify_user_root(root):
        return None

    # 2. 提取字段：优先 Link 子树，其次 verifyuser/verification 子树
    link = root.find(".//Link")
    if link is not None:
        stranger_wxid = _text(link, "UserName")
        nickname = _text(link, "NickName")
        verify_message = _text(link, "Content")
        scene = _text(link, "Scene")
    else:
        # 无 Link 节点时从任意子节点按候选标签名搜索
        stranger_wxid = _find_text(root, ["UserName", "username", "v1", "ticket"])
        nickname = _find_text(root, ["NickName", "nickname", "nick"])
        verify_message = _find_text(root, ["Content", "content", "msg", "verifyContent"])
        scene = _find_text(root, ["Scene", "scene", "sceneid", "scene_id"])

    # 3. 从 ticket/encrypt username 中反推带 @stranger 的 wxid
    if not stranger_wxid:
        return None
    if "@" not in stranger_wxid:
        # 微信 ticket 常见为 wxid_xxx@stranger 或加密串，统一补后缀
        # 若已含 @ 则保留原样（如 @stranger / @openim）
        stranger_wxid = f"{stranger_wxid}@stranger"

    return FriendRequestInfo(
        stranger_wxid=stranger_wxid,
        nickname=nickname,
        verify_message=verify_message,
        scene=scene,
        raw_xml=content,
        create_time=create_time,
        msg_local_id=msg_local_id,
    )


def _is_verify_user_root(root: ET.Element) -> bool:
    """判断 XML 根节点是否表示好友申请。"""
    tag = root.tag.split("}")[-1] if root.tag else ""
    if tag.lower() in _VERIFYUSER_TYPES:
        return True
    if tag.lower() == "sysmsg":
        msg_type = (root.get("type") or "").lower()
        if msg_type in _VERIFYUSER_TYPES:
            return True
    return False


def _text(parent: ET.Element, tag: str) -> str:
    """安全提取直接子元素文本（None 安全，去掉命名空间）。"""
    tag_lower = tag.lower()
    for child in parent:
        child_tag = child.tag.split("}")[-1] if child.tag else ""
        if child_tag.lower() == tag_lower:
            return child.text.strip() if child.text else ""
    return ""


def _find_child_recursive(parent: ET.Element, tag: str) -> Optional[ET.Element]:
    """按本地标签名递归查找后代元素（忽略命名空间）。"""
    tag_lower = tag.lower()
    for elem in parent.iter():
        elem_tag = elem.tag.split("}")[-1] if elem.tag else ""
        if elem_tag.lower() == tag_lower:
            return elem
    return None


def _find_text(parent: ET.Element, tags: list[str]) -> str:
    """按候选标签名列表顺序递归查找，返回首个非空文本。"""
    for tag in tags:
        el = _find_child_recursive(parent, tag)
        if el is not None and el.text:
            return el.text.strip()
    return ""
