"""宝塔侧 Frida RPC 桥。

手机通过认证的反向隧道暴露 frida-server，SDK 容器在本模块中持有真正的
Frida Session 和 JS RPC。Android 系统控制仍走手机 WebSocket，两条通道互不抢占。
"""

from __future__ import annotations

import asyncio
import logging
import threading
from typing import Any, Dict

logger = logging.getLogger(__name__)


class ServerFridaBridge:
    def __init__(self) -> None:
        self._manager = None
        self._executor = None
        self._lock = threading.RLock()

    @staticmethod
    def _settings():
        from config import settings
        return settings

    def enabled_for(self, device_id: str) -> bool:
        settings = self._settings()
        if not bool(getattr(settings, "SERVER_FRIDA_ENABLED", False)):
            return False
        expected = str(getattr(settings, "SERVER_FRIDA_DEVICE_ID", "") or "").strip()
        return not expected or expected == device_id

    def _connect(self) -> bool:
        with self._lock:
            if self._manager and getattr(self._manager, "connected", False):
                return True

            from hook.frida_manager import FridaManager
            from hook.hook_executor import HookExecutor

            settings = self._settings()
            manager = FridaManager(
                mode="remote",
                gadget_host=str(getattr(settings, "SERVER_FRIDA_HOST", "172.18.0.1")),
                gadget_port=int(getattr(settings, "SERVER_FRIDA_PORT", 14538)),
                use_adb_forward=False,
                auto_reconnect=True,
            )
            if not manager.start():
                logger.warning("宝塔 Frida 桥连接失败")
                return False
            self._manager = manager
            self._executor = HookExecutor(manager)
            logger.info("宝塔 Frida 桥已附着微信并加载 RPC")
            return True

    def execute_sync(self, action: str, params: Dict[str, Any]) -> Dict[str, Any]:
        try:
            if not self._connect():
                return {
                    "success": False,
                    "code": 503,
                    "error": "宝塔 Frida 桥不可用，请检查手机反向隧道和微信进程",
                    "_channel_used": "server/frida/offline",
                }
            result = self._executor.execute(action, params)
            result.setdefault("code", 200 if result.get("success") else 500)
            result["_channel_used"] = "server/frida"
            result["transport"] = "frida_reverse_tunnel"
            return result
        except Exception as exc:
            logger.exception("宝塔 Frida RPC 执行异常")
            return {
                "success": False,
                "code": 500,
                "error": str(exc),
                "_channel_used": "server/frida/error",
            }

    async def execute(self, device_id: str, action: str, params: Dict[str, Any]) -> Dict[str, Any]:
        if not self.enabled_for(device_id):
            return {"success": False, "code": 503, "error": "宝塔 Frida 桥未启用"}
        return await asyncio.to_thread(self.execute_sync, action, params)

    def status(self) -> Dict[str, Any]:
        connected = bool(self._manager and getattr(self._manager, "connected", False))
        return {
            "enabled": bool(getattr(self._settings(), "SERVER_FRIDA_ENABLED", False)),
            "connected": connected,
            "manager": self._manager.get_status() if connected else None,
        }


server_frida_bridge = ServerFridaBridge()
