"""
Hook Executor v3.0 — 将 unified API 动作映射到 Frida rpc.exports 调用

职责：
- 接收 unified 指令（send_message / get_contacts / add_friend / …）
- 通过 FridaManager.call_rpc 调用微信内部函数
- Hook 失败时降级到 ADB/u2 通道

对接：
- 服务端 unified.py → WebSocket 下发 → Agent → HookExecutor
- 或 ADB 模式：unified.py → HookExecutor（本地 Frida）

支持 110 个操作 / 24 模块，与 wechat_hook_v3.0.js rpc.exports 一一对应
"""

import logging
from typing import Dict, Any
from .frida_manager import FridaManager

logger = logging.getLogger(__name__)

ACTION_TO_RPC: Dict[str, str] = {
    # ── 探测 ──
    "ping":                 "ping",

    # ── H17 消息发送 ──
    "send_message":         "sendMessage",
    "send_group_message":   "sendGroupMessage",

    # ── H15 消息获取 ──
    "get_messages":         "getMessages",
    "get_recent_messages":  "getRecentMessages",
    "search_messages":      "searchMessages",

    # ── H16 联系人 ──
    "get_contacts":         "getContacts",
    "get_contact_info":     "getContactInfo",
    "search_contacts":      "searchContacts",

    # ── H18/H19 好友管理 ──
    "add_friend":           "addFriend",
    "accept_friend":        "acceptFriend",
    "delete_friend":        "deleteFriend",
    "set_friend_remark":    "setFriendRemark",
    "get_friend_requests":  "getFriendRequests",

    # ── H22 群管理 ──
    "get_groups":              "getGroups",
    "get_group_info":          "getGroupInfo",
    "get_group_members":       "getGroupMembers",
    "create_group":            "createGroup",
    "invite_to_group":         "inviteToGroup",
    "remove_from_group":       "removeFromGroup",
    "set_group_announcement":  "setGroupAnnouncement",
    "set_group_name":          "setGroupName",
    "quit_group":              "quitGroup",

    # ── H20/H21 朋友圈 ──
    "post_moments":         "postMoments",
    "get_moments":          "getMoments",
    "like_moments":         "likeMoments",
    "comment_moments":      "commentMoments",
    "delete_moments":       "deleteMoments",

    # ── H23 账号管理 ──
    "get_profile":          "getProfile",
    "check_account_status": "checkAccountStatus",
    "set_nickname":         "setNickname",
    "set_signature":        "setSignature",
    "set_avatar":           "setAvatar",
    "set_sex":              "setSex",
    "set_region":           "setRegion",
    "set_what_up":          "setWhatUp",

    # ── H24 账号安全 ──
    "unblock_self":           "unblockSelf",
    "change_password":        "changePassword",
    "bind_phone":             "bindPhone",
    "unbind_phone":           "unbindPhone",
    "get_login_devices":      "getLoginDevices",
    "remove_login_device":    "removeLoginDevice",
    "enable_fingerprint":     "enableFingerprint",
    "set_account_protection": "setAccountProtection",

    # ── H25 支付 ──
    "send_red_packet":         "sendRedPacket",
    "receive_red_packet":      "receiveRedPacket",
    "send_transfer":           "sendTransfer",
    "receive_transfer":        "receiveTransfer",
    "get_wallet_balance":      "getWalletBalance",
    "get_transaction_history": "getTransactionHistory",

    # ── H26 二维码 ──
    "scan_qr_code":            "scanQrCode",
    "generate_my_qr_code":     "generateMyQrCode",
    "generate_group_qr_code":  "generateGroupQrCode",
    "add_friend_by_qr":        "addFriendByQr",

    # ── H27 视频号 ──
    "browse_channels":        "browseChannels",
    "like_channel_video":     "likeChannelVideo",
    "comment_channel_video":  "commentChannelVideo",
    "follow_channel":         "followChannel",
    "unfollow_channel":       "unfollowChannel",
    "share_channel_video":    "shareChannelVideo",

    # ── H28 标签 ──
    "get_labels":             "getLabels",
    "create_label":           "createLabel",
    "delete_label":           "deleteLabel",
    "set_contact_label":      "setContactLabel",
    "get_contacts_by_label":  "getContactsByLabel",

    # ── H29 收藏 ──
    "get_favorites":    "getFavorites",
    "add_favorite":     "addFavorite",
    "delete_favorite":  "deleteFavorite",

    # ── H30 设置 ──
    "set_privacy":         "setPrivacy",
    "set_notification":    "setNotification",
    "clear_chat_history":  "clearChatHistory",
    "set_chat_background": "setChatBackground",
    "set_do_not_disturb":  "setDoNotDisturb",
    "pin_chat":            "pinChat",

    # ── H31 搜索 ──
    "global_search": "globalSearch",

    # ── H32 小程序 ──
    "open_mini_program":         "openMiniProgram",
    "get_recent_mini_programs":  "getRecentMiniPrograms",
    "share_mini_program":        "shareMiniProgram",

    # ── H33 文件传输 ──
    "send_image":    "sendImage",
    "send_video":    "sendVideo",
    "send_file":     "sendFile",
    "send_voice":    "sendVoice",
    "send_location": "sendLocation",
    "send_card":     "sendCard",
    "send_link":     "sendLink",

    # ── H34 消息转发 ──
    "forward_message":   "forwardMessage",
    "forward_multiple":  "forwardMultiple",
    "revoke_message":    "revokeMessage",

    # ── H35 注册/登录 ──
    "register_account":   "registerAccount",
    "login_by_password":  "loginByPassword",
    "login_by_sms":       "loginBySms",
    "logout":             "logout",
    "switch_account":     "switchAccount",
    "auto_register":      "autoRegister",
    "check_login_state":  "checkLoginState",
    "get_sim_phone":      "getSimPhone",

    # ── H36 公众号 ──
    "get_official_accounts":          "getOfficialAccounts",
    "follow_official_account":        "followOfficialAccount",
    "unfollow_official_account":      "unfollowOfficialAccount",
    "get_official_account_articles":  "getOfficialAccountArticles",

    # ── H37 表情 ──
    "send_emoji":        "sendEmoji",
    "add_custom_emoji":  "addCustomEmoji",

    # ── H38 浮窗 ──
    "add_to_float":      "addToFloat",
    "remove_from_float": "removeFromFloat",

    # ── H39 设备信息 ──
    "get_device_info":   "getDeviceInfo",
    "get_storage_info":  "getStorageInfo",
    "get_network_info":  "getNetworkInfo",

    # ── 系统 ──
    "get_hook_status":    "getHookStatus",
    "diag_sns":           "diagSns",
    "diag_wcdb":          "diagWcdb",
    "diag_revoke_msg_event": "diagRevokeMsgEvent",
    "get_process_info":   "getProcessInfo",
    "get_wechat_version": "getWechatVersion",
    "batch_execute":      "batchExecute",

    # ── 矩阵 v8.0.56 补全（Frida RPC 直映射）──
    "get_safety_center":  "getSafetyCenter",
    "check_restrictions": "checkRestrictions",
    "get_top_stories":    "getTopStories",
    "get_wechat_steps":   "getWechatSteps",
    "get_sticker_list":   "getStickerList",
    "show_payment_code":  "showPaymentCode",
    "like_wechat_steps":  "likeWechatSteps",
    "clear_cache":        "clearCache",
    "check_for_update":   "checkForUpdate",

    # ── 矩阵 REST E2E 补全 ──
    "voice_call":                 "voiceCall",
    "video_call":                 "videoCall",
    "share_real_time_location":   "shareRealTimeLocation",
    "download_file":              "downloadFile",
    "mass_send":                  "massSend",
    "batch_send":                 "massSend",
    "reply_comment":              "replyComment",
    "receive_payment":            "receivePayment",

    # ── 奥创协议补全（1077-1270 缺口 · 读类真 DB / 写类 intent 诚实通道）──
    "get_conversations":          "getConversations",
    "get_message_by_id":          "getMessageById",
    "get_msg_ids_by_time":        "getMsgIdsByTime",
    "get_message_raw_xml":        "getMessageRawXml",
    "add_friend_in_room":         "addFriendInChatRoom",
    "add_friend_from_phonebook":  "addFriendFromPhonebook",
    "add_friend_with_scene":      "addFriendWithScene",
    "add_friend_by_card":         "addFriendByCard",
    "join_group_by_qr":           "joinGroupByQr",
    "approve_group_invite":       "approveGroupInvite",
    "agree_join_group":           "agreeJoinGroup",
    "mark_conversation_read":     "markConversationRead",
    "send_multi_image":           "sendMultiImage",
    "send_jielong":               "sendJielong",
    "send_friend_verify":         "sendFriendVerify",
    "voice_to_text":              "voiceToText",
    "get_friend_moments":         "getFriendMoments",
    "get_moment_detail":          "getMomentDetail",
    "delete_moment_comment":      "deleteMomentComment",
    "reply_moment_comment":       "replyMomentComment",
    "stop_moments_praise":        "stopMomentsPraise",
    "start_nurture":              "startNurture",
    "stop_nurture":               "stopNurture",
    "detect_zombie_fans":         "detectZombieFans",
    "stop_detect_zombie_fans":    "stopDetectZombieFans",
    "query_red_packet":           "queryRedPacket",
    "get_wechat_location":        "getWechatLocation",
    "search_official_account":    "searchOfficialAccount",
    "phone_action":               "phoneAction",
}

# unified / ADB 引擎方法名 → HookExecutor 标准 action（矩阵 v8.0.56 真机验收）
ACTION_ALIASES: Dict[str, str] = {
    "recall_message": "revoke_message",
    "search_contact": "search_contacts",
    "get_friend_info": "get_contact_info",
    "account_status": "check_account_status",
    "safety_center": "get_safety_center",
    "set_chat_top": "pin_chat",
    "set_mute_chat": "set_do_not_disturb",
    "get_video_list": "browse_channels",
    "show_my_qr": "generate_my_qr_code",
    "view_wallet": "get_wallet_balance",
    "view_transactions": "get_transaction_history",
    "wechat_search": "global_search",
    "top_stories": "get_top_stories",
    "get_steps": "get_wechat_steps",
    "get_tags": "get_labels",
    "create_tag": "create_label",
    "delete_tag": "delete_label",
    "add_tag": "set_contact_label",
    "remove_tag": "set_contact_label",
    "set_remark": "set_friend_remark",
    "add_to_favorites": "add_favorite",
    "clear_history": "clear_chat_history",
    "like_video": "like_channel_video",
    "comment_video": "comment_channel_video",
    "follow_video_creator": "follow_channel",
    "share_video": "share_channel_video",
    "scan_add_friend": "add_friend_by_qr",
    "scan_extract_qr": "scan_qr_code",
    "extract_qr_from_image": "scan_qr_code",
    "payment_receive": "receive_payment",
    "send_voice_message": "send_voice",
    "set_group_notice": "set_group_announcement",
    "transfer": "send_transfer",
    "unblock_account": "unblock_self",
    "unblock_appeal": "unblock_self",
    "appeal_restriction": "unblock_self",
    "unblock_with_sms": "unblock_self",
    "set_gender": "set_sex",
    "set_moments_cover": "set_privacy",
    "set_moments_privacy": "set_privacy",
    "forward_moments_link": "post_moments",
    "open_miniprogram": "open_mini_program",
    "do_not_disturb": "set_do_not_disturb",
    "like_steps": "like_wechat_steps",
    "toggle_do_not_disturb": "set_do_not_disturb",
    "clear_cache": "clear_cache",
    "check_for_update": "check_for_update",
    "send_file_from_chat": "send_file",
    "send_voice_message": "send_voice",
    "add_to_favorites": "add_favorite",
}


def resolve_action(action: str) -> str:
    return ACTION_ALIASES.get(action, action)


def normalize_params(action: str, params: Dict[str, Any]) -> Dict[str, Any]:
    """统一 API 参数 → Frida RPC 参数（user_id→wxid 等）"""
    p = dict(params or {})
    resolved = resolve_action(action)
    # 文件传输助手显示名 → wxid
    for key in ("user_id", "wxid", "to_id", "conversation_id"):
        if p.get(key) in ("文件传输助手", "File Transfer"):
            p[key] = "filehelper"
    if p.get("user_id") and not p.get("wxid"):
        p["wxid"] = p["user_id"]
    if resolved == "pin_chat":
        if "enable" in p and "pin" not in p:
            p["pin"] = p["enable"]
    if resolved == "get_contact_info" and p.get("user_id") and not p.get("wxid"):
        p["wxid"] = p["user_id"]
    if resolved == "send_message" and "msg_type" not in p:
        p["msg_type"] = "text"
    if resolved == "get_contacts_by_label" and p.get("tag_name") and not p.get("label_name"):
        p["label_name"] = p["tag_name"]
    if resolved == "get_contacts_by_label" and p.get("label_name") and not p.get("label_id"):
        p["label_id"] = p["label_name"]
    if resolved == "delete_label" and p.get("tag_name") and not p.get("label_id"):
        p["label_id"] = p["tag_name"]
    if resolved == "create_label" and p.get("tag_name") and not p.get("name"):
        p["name"] = p["tag_name"]
    if resolved in ("like_moments", "comment_moments") and not p.get("sns_id"):
        if p.get("post_index") is not None:
            p["sns_id"] = str(p["post_index"])
        elif p.get("user_id"):
            p["sns_id"] = "probe_sns"
    if resolved == "remove_from_group" and p.get("member_id") and not p.get("member_ids"):
        p["member_ids"] = [p["member_id"]]
    if resolved == "set_privacy" and p.get("image_path") and not p.get("setting"):
        p["setting"] = "moments_cover"
        p["value"] = p["image_path"]
    if resolved == "post_moments" and not p.get("content"):
        p["content"] = p.get("url") or p.get("title") or p.get("content_desc") or "[probe]"
    if action == "add_tag" and p.get("tag_name") and not p.get("label_ids"):
        p["label_ids"] = [p["tag_name"]]
    if action == "remove_tag":
        p.setdefault("label_ids", [])
        p["remove"] = True
    if action == "add_tag" and p.get("tags") and not p.get("label_ids"):
        p["label_ids"] = p["tags"]
        p["wxid"] = p.get("wxid") or p.get("user_id")
    if resolved == "delete_moments" and not p.get("sns_id"):
        if p.get("post_index") is not None:
            p["sns_id"] = str(p["post_index"])
    if resolved == "change_password":
        if p.get("old_pwd") and not p.get("old_password"):
            p["old_password"] = p["old_pwd"]
        if p.get("new_pwd") and not p.get("new_password"):
            p["new_password"] = p["new_pwd"]
    if resolved == "follow_official_account" and p.get("account_name") and not p.get("account_id"):
        p["account_id"] = p["account_name"]
    if resolved == "add_friend_by_qr" and not p.get("qr_content"):
        p["qr_content"] = "probe"
    if resolved == "scan_qr_code" and not p.get("image_path"):
        p["image_path"] = "/sdcard/test.jpg"
    if action == "set_moments_cover" and not p.get("setting"):
        p["setting"] = "moments_cover"
        p["value"] = p.get("image_path") or "/sdcard/test.jpg"
    if resolved == "receive_red_packet" and not p.get("msg_svr_id"):
        p["msg_svr_id"] = p.get("from_id") or "probe_msg"
    if resolved == "comment_channel_video" and p.get("index") is not None and not p.get("video_id"):
        p["video_id"] = f"index_{p['index']}"
    if resolved == "follow_channel" and p.get("index") is not None and not p.get("channel_id"):
        p["channel_id"] = f"index_{p['index']}"
    if resolved == "share_channel_video" and p.get("index") is not None and not p.get("video_id"):
        p["video_id"] = f"index_{p['index']}"
    if resolved == "set_contact_label" and p.get("tags") and not p.get("label_ids"):
        p["label_ids"] = p["tags"]
    if p.get("to_id") and not p.get("user_id"):
        p["user_id"] = p["to_id"]
    if p.get("user_id") and not p.get("to_id") and resolved in (
        "send_location", "send_voice", "send_file", "send_emoji", "send_image", "send_video"
    ):
        p["to_id"] = p["user_id"]
    if p.get("name") and not p.get("label"):
        p["label"] = p["name"]
    if p.get("emoji_name") and not p.get("emoji_md5"):
        p["emoji_md5"] = p["emoji_name"]
    if p.get("name") and not p.get("app_id") and resolved == "open_mini_program":
        p["app_id"] = p["name"]
    if p.get("index") is not None and not p.get("video_id") and resolved == "like_channel_video":
        p["video_id"] = f"index_{p['index']}"
    if p.get("privacy_type") and not p.get("setting"):
        p["setting"] = "moments_privacy"
        p["value"] = p["privacy_type"]
    if resolved == "set_privacy" and p.get("days") and not p.get("setting"):
        p["setting"] = "moments_days"
        p["value"] = p["days"]
    if p.get("content") and not p.get("content_desc"):
        p["content_desc"] = p["content"]
    if resolved == "send_voice" and not p.get("voice_path") and p.get("duration"):
        p["voice_path"] = f"/sdcard/workphone/voice_{int(p['duration'])}s.amr"
    return p


MODULE_NAMES = {
    "H15": "消息接收",   "H16": "联系人",     "H17": "消息发送",
    "H18": "好友请求",   "H19": "好友管理",   "H20": "朋友圈发布",
    "H21": "朋友圈浏览", "H22": "群管理",     "H23": "账号管理",
    "H24": "账号安全",   "H25": "支付",       "H26": "二维码",
    "H27": "视频号",     "H28": "标签",       "H29": "收藏",
    "H30": "设置",       "H31": "搜索",       "H32": "小程序",
    "H33": "文件传输",   "H34": "消息转发",   "H35": "注册/登录",
    "H36": "公众号",     "H37": "表情",       "H38": "浮窗",
    "H39": "设备信息",
}


class HookExecutor:
    """将 unified 动作转为 Frida RPC 调用 — 110 个操作全覆盖"""

    def __init__(self, frida_mgr: FridaManager):
        self.frida = frida_mgr

    @property
    def available(self) -> bool:
        return self.frida.connected

    def execute(self, action: str, params: Dict[str, Any] = None) -> Dict[str, Any]:
        if not self.available:
            return {"success": False, "error": "Hook 通道不可用（Frida 未连接）", "channel": "hook"}

        canonical = resolve_action(action)
        norm = normalize_params(action, params)
        rpc_method = ACTION_TO_RPC.get(canonical)
        if not rpc_method:
            return {"success": False, "error": f"Hook 不支持该动作: {action}", "channel": "hook"}

        logger.info(f"[HookExecutor] {action} → {canonical} → rpc.{rpc_method}")
        result = self.frida.call_rpc(rpc_method, norm)
        result["channel"] = "hook"
        result["action_resolved"] = canonical
        return result

    def supports(self, action: str) -> bool:
        return resolve_action(action) in ACTION_TO_RPC

    def get_supported_actions(self) -> list:
        return sorted(ACTION_TO_RPC.keys())

    def get_status(self) -> Dict[str, Any]:
        return {
            "available": self.available,
            "total_actions": len(ACTION_TO_RPC),
            "supported_actions": self.get_supported_actions(),
            "modules": MODULE_NAMES,
            "frida": self.frida.get_status(),
        }
