"""
连接守护技能 - 确保设备与服务器始终保持连接

职责：
1. 自动处理系统弹窗（USB调试授权、权限请求、系统更新提示等）
2. 监控 ADB / WiFi / 网络连通性
3. 检测并恢复 uiautomator2 服务
4. 检测屏幕状态，必要时亮屏
5. 与 Hawk 网络层协同做断网恢复

这是一个「常驻」技能，Agent 启动后以后台循环方式持续运行。
"""

import logging
import time
import re
from typing import Dict, Any, List, Optional

import sys
import os

_agent_dir = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
if _agent_dir not in sys.path:
    sys.path.insert(0, _agent_dir)

try:
    from skills.base import BaseSkill
except ImportError:
    from ..base import BaseSkill

logger = logging.getLogger(__name__)


# ═══════════════════════════════════════════════════════════════
# 弹窗规则库 — 覆盖主流安卓品牌：小米/华为/OPPO/vivo/三星/一加/荣耀/realme
#
# 每条规则: detect = 界面关键词（正则）, click = 要点击的按钮文案
# 规则按优先级排列，匹配到即执行，不会重复点击
# ═══════════════════════════════════════════════════════════════
_POPUP_DISMISS_RULES: List[Dict[str, Any]] = [

    # ─── 1. USB 调试授权（所有品牌） ───
    {"detect": [
        "USB调试", "USB debugging", "允许USB调试", "Allow USB debugging",
        "USB 偵錯",                              # 繁体
        "USB调试（安全设置）",                       # MIUI 特有
        "RSA.*密钥指纹", "RSA.*key fingerprint",  # 弹窗正文
        "允许通过USB调试",                          # 华为
        "이 컴퓨터에서 USB 디버깅",                  # 三星韩语
     ],
     "click": [
        "确定", "允许", "OK", "Allow", "始终允许", "Always allow",
        "확인",          # 三星韩语
        "允許",          # 繁体
     ]},

    # ─── 1b. USB 连接模式（仅充电 → 文件传输，防 MIUI 间歇掉 ADB） ───
    {"detect": [
        "USB 用于", "USB用途", "USB 用途", "连接方式",
        "仅充电", "充电模式", "Charging only", "Charge only",
        "USB 偏好设置", "Use USB for",
        "传输文件", "文件传输", "Transfer files",
     ],
     "click": [
        "传输文件", "文件传输", "Transfer files", "File transfer",
        "传输照片", "Photo transfer", "MTP",
     ]},

    # ─── 2. MIUI 安全弹窗（小米/红米特有） ───
    {"detect": [
        "安全警告", "此操作具有风险",
        "模拟点击", "模拟输入",                     # MIUI「检测到模拟操作」
        "检测到.*模拟", "监控.*辅助",
        "开发者选项.*安全", "安全设置已关闭",
     ],
     "click": ["确定", "继续", "我已知晓", "允许", "仍然允许"]},

    # ─── 3. 华为/荣耀 特有弹窗 ───
    {"detect": [
        "允许HiSuite通过", "HiSuite",
        "仅充电", "传输文件", "传输照片",            # USB 模式选择
        "华为手机助手",
        "应用.*未通过安全检测",                      # 华为安全中心
        "可能会损坏您的设备",
     ],
     "click": ["允许", "继续安装", "我已知晓", "确定", "仍然安装"]},

    # ─── 4. OPPO/realme/一加 特有弹窗 ───
    {"detect": [
        "ColorOS", "USB 传输",
        "允许.*调试", "您要允许.*USB调试",
        "开发者模式.*已开启",
        "USB用途", "连接方式",
        "充电模式.*传输",                           # OPPO USB 模式选择
     ],
     "click": ["确定", "允许", "OK", "传输文件"]},

    # ─── 5. vivo/iQOO 特有弹窗 ───
    {"detect": [
        "Funtouch", "OriginOS",
        "是否允许USB调试",
        "开启USB调试.*安全风险",
        "vivo.*安全",
     ],
     "click": ["确定", "允许", "OK", "已了解风险"]},

    # ─── 6. 三星 特有弹窗 ───
    {"detect": [
        "One UI", "Samsung",
        "您是否要允许USB调试", "Allow USB debugging",
        "Knox.*安全",
        "设备保护",
     ],
     "click": ["确定", "允许", "OK", "Allow"]},

    # ─── 7. ADB 通用权限 ───
    {"detect": ["允许通过", "ADB", "adb"],
     "click": ["确定", "允许", "OK"]},

    # ─── 8. 安装应用（所有品牌） ───
    {"detect": [
        "要安装", "允许安装", "安装应用",
        "安装未知应用", "Install unknown apps",
        "来源不明", "Unknown sources",
        "是否安装该应用", "Install this app",
        "外部来源", "第三方来源",
        "继续安装.*可能有风险",                      # 各品牌安全提示
        "仍要安装",
     ],
     "click": [
        "继续安装", "允许", "安装", "Install",
        "仍然安装", "仍要安装", "我已了解",
     ]},

    # ─── 9. 权限请求弹窗（通用） ───
    {"detect": [
        "允许.*访问", "允许.*使用", "Allow.*access",
        "请求.*权限", "needs.*permission",
        "允许.*读取", "允许.*写入",
        "允许.*拍照", "允许.*录音",
        "允许.*定位", "Allow.*location",
        "允许.*通知", "Allow.*notification",
        "允许.*悬浮窗", "允许.*显示在其他应用",
        "Display over other apps",
        "允许.*存储", "Allow.*storage",
     ],
     "click": [
        "允许", "始终允许", "Allow", "While using the app",
        "仅在使用时允许", "仅使用期间",
        "始终", "Always",
     ]},

    # ─── 10. 系统更新/升级 ───
    {"detect": [
        "系统更新", "System update", "升级",
        "发现新版本", "New version",
        "现在更新", "Update now",
        "MIUI.*更新", "EMUI.*更新", "ColorOS.*更新",
        "OTA.*更新",
     ],
     "click": ["稍后", "以后", "取消", "Later", "Cancel", "Not now", "稍后再说"]},

    # ─── 11. 电池优化（各品牌措辞不同） ───
    {"detect": [
        "电池优化", "Battery optimization", "忽略电池优化",
        "省电策略", "后台耗电", "电量管理",
        "自启动管理", "自启动",
        "是否允许.*后台运行",
        "关闭.*省电",
        "Ignore battery optimizations",
        "不再受限",                                  # 华为
     ],
     "click": ["允许", "是", "Yes", "Allow", "不受限制", "确定"]},

    # ─── 12. 后台运行保活 ───
    {"detect": [
        "后台运行", "后台活动", "Background",
        "锁定.*后台", "保持运行",
        "允许.*自启动", "允许.*后台",
        "关闭后台清理",
        "电池管理.*允许",
     ],
     "click": ["允许", "Allow", "确定", "开启"]},

    # ─── 13. 通知权限 ───
    {"detect": [
        "通知权限", "发送通知", "Post notifications",
        "允许.*推送", "开启通知",
        "Notification access",
     ],
     "click": ["允许", "Allow", "确定"]},

    # ─── 14. 悬浮窗/无障碍 ───
    {"detect": [
        "悬浮窗", "Display over", "draw over",
        "无障碍", "Accessibility",
        "辅助功能",
     ],
     "click": ["允许", "Allow", "确定", "开启"]},

    # ─── 15. Termux / 终端相关 ───
    {"detect": ["Termux", "终端", "com.termux"],
     "click": ["允许", "Allow", "确定"]},

    # ─── 16. 应用崩溃/ANR ───
    {"detect": [
        "ANR", "没有响应", "not responding", "停止运行",
        "已停止", "has stopped", "keeps stopping",
        "无响应.*关闭", "close app",
     ],
     "click": ["等待", "Wait", "再次打开", "Reopen"]},

    # ─── 17. 隐私合规弹窗（国内APP常见） ───
    {"detect": [
        "隐私政策", "用户协议", "Privacy policy",
        "个人信息保护", "我已阅读",
        "同意并继续", "Agree.*continue",
     ],
     "click": ["同意", "同意并继续", "Agree", "我已阅读并同意", "确定"]},

    # ─── 18. 广告/推广弹窗 ───
    {"detect": [
        "领取.*红包", "签到.*奖励",
        "今日推荐", "猜你喜欢",
        "开通.*会员", "免费试用",
        "跳过", "Skip",
     ],
     "click": ["跳过", "关闭", "Skip", "Close", "×", "✕"]},

    # ─── 19. SIM卡/运营商弹窗 ───
    {"detect": [
        "SIM.*未插入", "SIM.*not inserted",
        "无SIM卡", "No SIM",
        "紧急呼叫", "Emergency",
     ],
     "click": ["确定", "OK", "关闭"]},
]


class ConnectionGuardSkill(BaseSkill):
    """
    连接守护技能 — 常驻后台，确保设备与服务器始终连接

    核心能力：
    1. dismiss_popups()   — 自动关闭系统弹窗（USB授权、权限请求等）
    2. ensure_screen_on() — 确保屏幕亮起
    3. check_u2_alive()   — 检测 uiautomator2 是否存活
    4. check_network()    — 检测网络连通性（委托 Hawk）
    5. full_guard_cycle()  — 执行一轮完整守护（上述全部）
    """

    PACKAGE = ""
    NAME = "连接守护"

    def _shell(self, cmd: str) -> str:
        """安全执行 shell 并返回输出"""
        try:
            r = self.d.shell(cmd)
            return (getattr(r, "output", None) or str(r) or "").strip()
        except Exception:
            return ""

    # ========== 1. 弹窗自动处理 ==========

    def dismiss_popups(self) -> Dict[str, Any]:
        """
        扫描当前界面，自动点击 USB 授权/权限请求/系统弹窗的确认按钮。
        返回本轮处理了哪些弹窗。
        """
        dismissed = []
        if not self.d:
            return {"dismissed": dismissed, "count": 0}

        try:
            xml = self.d.dump_hierarchy()
        except Exception as e:
            logger.debug(f"dump_hierarchy 失败: {e}")
            return {"dismissed": dismissed, "count": 0, "error": str(e)}

        for rule in _POPUP_DISMISS_RULES:
            detected = False
            for keyword in rule["detect"]:
                if re.search(keyword, xml, re.IGNORECASE):
                    detected = True
                    break

            if not detected:
                continue

            for btn_text in rule["click"]:
                try:
                    if self.d(text=btn_text).exists(timeout=0.5):
                        self.d(text=btn_text).click()
                        dismissed.append({"popup": rule["detect"][0], "clicked": btn_text})
                        logger.info(f"🛡️ 自动处理弹窗: 检测到「{rule['detect'][0]}」→ 点击「{btn_text}」")
                        time.sleep(0.5)
                        break
                except Exception:
                    continue
                # textContains 兜底
                try:
                    if self.d(textContains=btn_text).exists(timeout=0.3):
                        self.d(textContains=btn_text).click()
                        dismissed.append({"popup": rule["detect"][0], "clicked": btn_text})
                        logger.info(f"🛡️ 自动处理弹窗: 检测到「{rule['detect'][0]}」→ 点击「{btn_text}」(contains)")
                        time.sleep(0.5)
                        break
                except Exception:
                    continue

        return {"dismissed": dismissed, "count": len(dismissed)}

    # ========== 2. 屏幕状态 ==========

    def ensure_screen_on(self) -> Dict[str, Any]:
        """确保屏幕亮起（某些 ADB 操作需要屏幕点亮）"""
        if not self.d:
            return {"screen_on": False, "action": "no_device"}

        try:
            info = self.d.info
            if info.get("screenOn"):
                return {"screen_on": True, "action": "already_on"}
            self.d.press("power")
            time.sleep(0.5)
            # 如果有锁屏，向上滑动解锁
            self.d.swipe_ext("up", scale=0.8)
            time.sleep(0.3)
            return {"screen_on": True, "action": "woke_up"}
        except Exception as e:
            logger.debug(f"ensure_screen_on 异常: {e}")
            return {"screen_on": False, "action": "error", "error": str(e)}

    # ========== 3. uiautomator2 存活检测 ==========

    def check_u2_alive(self) -> Dict[str, Any]:
        """检测 uiautomator2 是否正常工作，异常时尝试重启"""
        if not self.d:
            return {"alive": False, "action": "no_device"}

        try:
            info = self.d.info
            return {"alive": True, "package": info.get("currentPackageName", ""), "action": "ok"}
        except Exception as e:
            logger.warning(f"u2 异常: {e}，尝试重启服务")
            try:
                self._shell("am instrument -w -r -e debug false "
                            "-e class androidx.test.runner.AndroidJUnitRunner "
                            "io.appium.uiautomator2.server.test/"
                            "androidx.test.runner.AndroidJUnitRunner 2>/dev/null &")
                time.sleep(3)
                info = self.d.info
                return {"alive": True, "action": "restarted"}
            except Exception as e2:
                return {"alive": False, "action": "restart_failed", "error": str(e2)}

    # ========== 4. 网络检测（委托 Hawk） ==========

    def check_network(self) -> Dict[str, Any]:
        """检测网络连通性，断网时委托 Hawk 尝试恢复"""
        try:
            from hawk import is_network_available, try_reconnect_network

            if is_network_available(self.d):
                return {"network": True, "action": "ok"}

            logger.info("🌐 检测到断网，启动 Hawk 网络恢复...")
            result = try_reconnect_network(self.d)
            return {
                "network": result.get("success", False),
                "action": "hawk_reconnect",
                "detail": result,
            }
        except ImportError:
            # Hawk 不可用时仅做 ping 检测
            out = self._shell("ping -c 1 -W 2 8.8.8.8 2>/dev/null && echo ok || echo fail")
            return {"network": "ok" in out, "action": "ping_only"}
        except Exception as e:
            return {"network": False, "action": "error", "error": str(e)}

    # ========== 5. ADB 连接检测 ==========

    def check_adb_connection(self) -> Dict[str, Any]:
        """检测 ADB 连接状态"""
        out = self._shell("getprop ro.serialno 2>/dev/null || echo unknown")
        if out and out != "unknown":
            return {"adb": True, "serial": out}
        return {"adb": False, "serial": ""}

    # ========== 6. 完整守护周期 ==========

    def full_guard_cycle(self) -> Dict[str, Any]:
        """
        执行一轮完整守护检查（Agent 心跳循环中调用）：
        1. 自动处理弹窗（USB授权等）
        2. 确保屏幕亮起
        3. 检测 u2 存活
        4. 检测网络
        5. 检测 ADB
        """
        results = {}

        results["popups"] = self.dismiss_popups()
        results["screen"] = self.ensure_screen_on()
        results["u2"] = self.check_u2_alive()
        results["network"] = self.check_network()
        results["adb"] = self.check_adb_connection()

        all_ok = (
            results["u2"].get("alive", False)
            and results["network"].get("network", False)
        )
        results["all_ok"] = all_ok
        results["timestamp"] = int(time.time())

        if not all_ok:
            issues = []
            if not results["u2"].get("alive"):
                issues.append("u2不可用")
            if not results["network"].get("network"):
                issues.append("网络断开")
            logger.warning(f"⚠️ 守护检查发现问题: {', '.join(issues)}")
        else:
            popup_count = results["popups"].get("count", 0)
            if popup_count > 0:
                logger.info(f"🛡️ 守护周期完成: 处理了 {popup_count} 个弹窗，连接正常")

        return results
