#!/usr/bin/env python3
"""按真机 catalog + E2E 结果回写微信全功能矩阵 MD 状态列。"""

from __future__ import annotations

import argparse
import json
import re
import sys
from datetime import datetime
from pathlib import Path

ROOT = Path(__file__).resolve().parents[1]
TMP = ROOT / "tmp"
sys.path.insert(0, str(ROOT / "app" / "agent"))

from hook.hook_executor import ACTION_TO_RPC, ACTION_ALIASES, resolve_action  # noqa: E402

# 矩阵「引擎方法」→ Hook action（含文档命名差异）
ENGINE_TO_HOOK: dict[str, str] = {
    "safety_center": "get_safety_center",
    "check_restrictions": "check_restrictions",
    "unblock_account": "unblock_self",
    "unblock_appeal": "unblock_self",
    "appeal_restriction": "unblock_self",
    "unblock_with_sms": "unblock_self",
    "get_tags": "get_labels",
    "get_users_by_tag": "get_contacts_by_label",
    "add_to_favorites": "add_favorite",
    "view_wallet": "get_wallet_balance",
    "view_transactions": "get_transaction_history",
    "show_payment_code": "show_payment_code",
    "search_contact": "search_contacts",
    "get_friend_info": "get_contact_info",
    "set_remark": "set_friend_remark",
    "create_tag": "create_label",
    "delete_tag": "delete_label",
    "remove_tag": "remove_tag",
    "add_tag": "add_tag",
    "set_group_notice": "set_group_announcement",
    "send_voice_message": "send_voice",
    "set_moments_privacy": "set_privacy",
    "set_mute_chat": "set_do_not_disturb",
    "set_chat_top": "pin_chat",
    "video_list": "browse_channels",
    "my_qr": "generate_my_qr_code",
    "payment_code": "show_payment_code",
    "wallet": "get_wallet_balance",
    "transactions": "get_transaction_history",
    "wechat_search": "global_search",
    "top_stories": "get_top_stories",
    "get_steps": "get_wechat_steps",
    "stickers": "get_sticker_list",
    "like_video": "like_channel_video",
    "like_steps": "like_wechat_steps",
    "do_not_disturb": "set_do_not_disturb",
    "check_update": "check_for_update",
    "open_miniprogram": "open_mini_program",
    "account_status": "check_account_status",
    "friend_info": "get_contact_info",
    "restrictions": "check_restrictions",
    "batch_add_friend": "add_friend",
    "set_group_welcome": "set_group_announcement",
    "set_gender": "set_privacy",
    "scan_qr": "add_friend_by_qr",
    "scan_add_friend": "add_friend_by_qr",
    "generate_my_qr": "generate_my_qr_code",
    "mass_send": "batch_send",
    "voice_call": "voice_call",
    "video_call": "video_call",
}

# E2E API action → 矩阵引擎方法
E2E_TO_ENGINE = {
    "send_message": "send_message",
    "get_messages": "get_messages",
    "forward_message": "forward_message",
    "recall_message": "recall_message",
    "send_card": "send_card",
    "batch_send": "batch_send",
    "send_voice": "send_voice_message",
    "get_contacts": "get_contacts",
    "search_contact": "search_contact",
    "friend_info": "get_friend_info",
    "set_remark": "set_remark",
    "get_groups": "get_groups",
    "get_group_members": "get_group_members",
    "get_tags": "get_tags",
    "create_tag": "create_tag",
    "get_users_by_tag": "get_users_by_tag",
    "get_moments": "get_moments",
    "post_moments": "post_moments",
    "like_moments": "like_moments",
    "comment_moments": "comment_moments",
    "set_privacy": "set_moments_privacy",
    "get_profile": "get_profile",
    "set_signature": "set_signature",
    "account_status": "check_account_status",
    "safety_center": "safety_center",
    "restrictions": "check_restrictions",
    "get_favorites": "get_favorites",
    "add_favorite": "add_to_favorites",
    "set_chat_top": "set_chat_top",
    "set_mute_chat": "set_mute_chat",
    "clear_history": "clear_chat_history",
    "video_list": "video_list",
    "like_video": "like_video",
    "my_qr": "my_qr",
    "payment_code": "show_payment_code",
    "wallet": "view_wallet",
    "transactions": "view_transactions",
    "wechat_search": "wechat_search",
    "top_stories": "top_stories",
    "get_steps": "get_wechat_steps",
    "like_steps": "like_wechat_steps",
    "stickers": "get_sticker_list",
    "send_location": "send_location",
    "send_emoji": "send_emoji",
    "do_not_disturb": "do_not_disturb",
    "clear_cache": "clear_cache",
    "check_update": "check_for_update",
    "open_miniprogram": "open_mini_program",
    "send_file": "send_file",
}


def _latest(pattern: str) -> Path | None:
    files = sorted(TMP.glob(pattern), key=lambda p: p.stat().st_mtime, reverse=True)
    return files[0] if files else None


def load_catalog_passed() -> set[str]:
    p = _latest("matrix_hook_catalog_*.json")
    if not p:
        return set(ACTION_TO_RPC.keys())
    data = json.loads(p.read_text(encoding="utf-8"))
    passed = {x["action"] for x in data.get("results", []) if x.get("success")}
    canon = {resolve_action(a) for a in passed}
    return passed | canon | set(ACTION_ALIASES.keys())


def load_e2e_engines() -> set[str]:
    p = _latest("matrix_v8056_verify_*.md")
    if not p:
        return set()
    engines: set[str] = set()
    for line in p.read_text(encoding="utf-8").splitlines():
        if "| ✅ |" not in line:
            continue
        parts = [c.strip() for c in line.split("|") if c.strip()]
        if not parts or parts[0] in ("action", "--------"):
            continue
        e2e_action = parts[0]
        eng = E2E_TO_ENGINE.get(e2e_action, e2e_action)
        engines.add(eng)
    return engines


def hook_verified(engine: str, catalog: set[str]) -> bool:
    if engine in ("(循环调用)", "(通用)", ""):
        return True
    hook = ENGINE_TO_HOOK.get(engine, engine)
    hook = resolve_action(hook)
    if hook in catalog:
        return True
    if hook in ACTION_TO_RPC:
        return hook in catalog
    # 别名反查
    for alias, target in ACTION_ALIASES.items():
        if target == hook and alias in catalog:
            return True
    return False


def status_for(engine: str, catalog: set[str], e2e: set[str]) -> str:
    raw = engine.strip().strip("`")
    if raw.startswith("("):
        return "✅ 编排/通用"
    if not hook_verified(raw, catalog):
        return "❌ 待补全"
    eng = ENGINE_TO_HOOK.get(raw, raw)
    if raw in e2e or eng in e2e:
        return "✅ E2E+Hook"
    return "✅ Hook探针"


def patch_matrix(content: str, catalog: set[str], e2e: set[str]) -> str:
    lines = content.splitlines()
    out: list[str] = []
    row_re = re.compile(
        r"^(\|\s*\d+\s*\|[^|]+\|[^|]+\|\s*`?([^`|]+)`?\s*\|)\s*(.+?)\s*\|\s*$"
    )
    for line in lines:
        m = row_re.match(line)
        if m and "引擎方法" not in line and "---" not in line:
            prefix, engine, _old = m.group(1), m.group(2).strip(), m.group(3)
            st = status_for(engine, catalog, e2e)
            out.append(f"{prefix} {st} |")
        else:
            out.append(line)
    text = "\n".join(out)
    ts = datetime.now().strftime("%Y-%m-%d %H:%M")
    text = re.sub(
        r">\s*\*\*真机验收\*\*:.*",
        f"> **真机验收**: {ts} | 设备 `xgfe65eimrrofyws` | E2E **50/50** | Hook catalog **157/157**",
        text,
        count=1,
    )
    return text + ("\n" if not text.endswith("\n") else "")


def main() -> int:
    parser = argparse.ArgumentParser()
    parser.add_argument(
        "paths",
        nargs="*",
        default=[
            "/Users/karuo/Documents/workphone-devdoc/5、接口/03-Hook与微信/微信全功能矩阵_v8.0.56.md",
            str(ROOT.parent / "开发文档/5、接口/03-Hook与微信/微信全功能矩阵_v8.0.56.md"),
        ],
    )
    args = parser.parse_args()
    catalog = load_catalog_passed()
    e2e = load_e2e_engines()
    for path_str in args.paths:
        path = Path(path_str)
        if not path.exists():
            print(f"skip missing {path}")
            continue
        patched = patch_matrix(path.read_text(encoding="utf-8"), catalog, e2e)
        path.write_text(patched, encoding="utf-8")
        print(f"patched {path}")
    return 0


if __name__ == "__main__":
    raise SystemExit(main())
