"""
连接协议与状态路由
用于展示设备端（Agent/Hook）与服务端的连接方式、消息协议和实时状态。
"""

from __future__ import annotations

from datetime import datetime, timezone
from typing import Any, Dict, List

from fastapi import APIRouter, HTTPException
from pydantic import BaseModel, Field

from services.ws_hub import ws_hub
from services.adb_device import adb_manager
from services.hook_module_service import hook_module_service
from services.connection_priority import connection_priority
from services.device_id_util import device_id_md5, enrich_device_id_fields, sanitize_sensitive_fields

router = APIRouter()


class SimRegisterRequest(BaseModel):
    device_id: str
    project_id: str = "cunkebao"
    model: str = "Simulator Device"
    platform: str = "android"
    capabilities: List[str] = Field(default_factory=lambda: ["event", "device_request"])


class SimHeartbeatRequest(BaseModel):
    device_id: str


class SimHookEventRequest(BaseModel):
    device_id: str
    platform: str = "wechat"
    event_type: str = "message_received"
    payload: Dict[str, Any] = Field(default_factory=dict)


def _iso_now() -> str:
    return datetime.now(timezone.utc).isoformat()


def _heartbeat_age_seconds(last_heartbeat: str) -> int:
    if not last_heartbeat:
        return -1
    try:
        dt = datetime.fromisoformat(last_heartbeat.replace("Z", "+00:00"))
        return max(0, int((datetime.now(dt.tzinfo or timezone.utc) - dt).total_seconds()))
    except Exception:
        return -1


@router.get("/connection/protocol")
async def get_connection_protocol() -> Dict[str, Any]:
    """连接方式协议：给前端/对接方直观看结构。"""
    return {
        "code": 200,
        "data": {
            "version": "v1",
            "generated_at": _iso_now(),
            "transport": {
                "agent_ws": "ws://<host>:8899/ws/device/{device_id}",
                "hook_events_ws": "ws://<host>:8899/api/v3/hook/events/stream",
                "rest_base": "http://<host>:8899/api/v3",
            },
            "handshake": {
                "client_register": {
                    "type": "register",
                    "data": {
                        "project_id": "cunkebao",
                        "agent_version": "3.0.0",
                        "model": "Redmi 11",
                        "capabilities": ["u2", "skill_wechat", "event", "device_request"],
                    },
                },
                "server_ack": {
                    "type": "registered",
                    "success": True,
                    "device_id": "<device_id>",
                    "project_id": "<project_id>",
                },
            },
            "heartbeat": {
                "client_ping_type": "heartbeat",
                "server_pong_type": "pong",
                "recommended_interval_seconds": [5, 10, 30],
            },
            "message_types": {
                "device_to_server": [
                    "register",
                    "heartbeat",
                    "response",
                    "status_report",
                    "event",
                    "device_request",
                ],
                "server_to_device": [
                    "registered",
                    "pong",
                    "execute",
                    "agent_execute",
                    "config_update",
                    "device_request_ack",
                ],
            },
            "hook_rest": {
                "list_modules": "GET /api/v3/modules",
                "device_modules": "GET /api/v3/devices/{device_id}/modules",
                "deploy_script": "POST /api/v3/scripts/{script_id}/deploy",
                "ingest_event": "POST /api/v3/hook/events",
            },
        },
    }


@router.get("/connection/status")
async def get_connection_status() -> Dict[str, Any]:
    """实时连接状态：用于控制台展示。"""
    online_devices: List[Dict[str, Any]] = ws_hub.get_online_devices()
    adb_devices = adb_manager.scan_devices()

    from services.device_transport import device_transport
    transport_policy = {
        "ws_first": device_transport.ws_first_enabled(),
        "ws_hook_only_wechat": device_transport.ws_hook_only("wechat"),
        "host_adb_probe": device_transport.host_adb_probe_enabled(),
        "mandatory_layer": "device_transport",
        "doc": "开发文档/5、接口/02-业务对接/WebSocket无线主控口径.md",
    }

    device_rows: List[Dict[str, Any]] = []
    for item in online_devices:
        device_id = item.get("device_id", "")
        last_heartbeat = item.get("last_heartbeat", "")
        row = enrich_device_id_fields({
            "device_id": device_id,
            "project_id": item.get("project_id", ""),
            "model": item.get("model", ""),
            "platform": item.get("platform", ""),
            "status": item.get("status", "online"),
            "last_heartbeat": last_heartbeat,
            "heartbeat_age_seconds": _heartbeat_age_seconds(last_heartbeat),
            "capabilities": item.get("capabilities", []),
            "wechat_running": item.get("wechat_running"),
            "wechat_foreground": item.get("wechat_foreground"),
            "network_type": item.get("network_type"),
            "screen_on": item.get("screen_on"),
            "current_app": item.get("current_app"),
            "connect_stage": item.get("connect_stage", "primary"),  # BIND-07 寻服来源
            "server_url": item.get("server_url"),
        })
        device_rows.append(row)

    return {
        "code": 200,
        "data": sanitize_sensitive_fields({
            "server_time": _iso_now(),
            "ws_path": "/ws/device/{device_id}",
            "hook_events_stream": "/api/v3/hook/events/stream",
            "online_ws_count": len(ws_hub.connections),
            "online_device_ids": list(ws_hub.connections.keys()),
            "online_device_ids_md5": {
                did: device_id_md5(did) for did in ws_hub.connections.keys()
            },
            "adb_count": len(adb_devices),
            "adb_serials": adb_devices,
            "adb_serials_md5": {s: device_id_md5(s) for s in adb_devices},
            "transport_policy": transport_policy,
            "devices": device_rows,
        }),
    }


@router.get("/connection/bootstrap/{device_id}")
async def get_connection_bootstrap(device_id: str) -> Dict[str, Any]:
    """
    设备无线主控启动指引 — Termux Agent 一行命令 + 验收 URL。
    供存客宝 BFF / 控制台展示，禁止空占位。
    """
    import json
    import socket
    from pathlib import Path
    from services.device_transport import device_transport

    sdk_port = 8899
    lan_ip = "127.0.0.1"
    import subprocess
    for cmd in (
        ["ipconfig", "getifaddr", "en0"],
        ["ipconfig", "getifaddr", "en1"],
    ):
        try:
            out = subprocess.check_output(cmd, text=True).strip()
            if out and not out.startswith("198.18."):
                lan_ip = out
                break
        except Exception:
            pass
    if lan_ip == "127.0.0.1":
        try:
            s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
            s.connect(("8.8.8.8", 80))
            cand = s.getsockname()[0]
            s.close()
            if cand and not cand.startswith("198.18."):
                lan_ip = cand
        except Exception:
            pass

    frida_port = 27042
    frida_binary = "/data/local/tmp/frida-server"
    cfg = Path(__file__).resolve().parents[2] / "scripts" / "anti_detect" / "phantom_frida_config.json"
    if cfg.exists():
        try:
            _pc = json.loads(cfg.read_text())
            frida_port = int(_pc.get("listen_port", frida_port))
            frida_binary = _pc.get("binary_path", frida_binary)
        except Exception:
            pass

    ws_online = device_transport.is_ws_online(device_id)
    termux_cmd = (
        f"export WP_AGENT_ON_DEVICE=1 WP_FRIDA_MODE=remote WP_FRIDA_PORT={frida_port} WP_AUTO_DISCOVER=1\n"
        f"cd ~/workphone/agent && python agent.py -d {device_id} --heartbeat 10"
    )
    frida_up_cmd = f"bash ~/workphone/sdk/scripts/termux_frida_up_onphone.sh -d {device_id}"
    return {
        "code": 200,
        "data": enrich_device_id_fields({
            "device_id": device_id,
            "ws_online": ws_online,
            "sdk_base": f"http://{lan_ip}:{sdk_port}",
            "ws_url": f"ws://{lan_ip}:{sdk_port}/ws/device/{device_id}",
            "frida_port": frida_port,
            "frida_binary": frida_binary,
            "frida_up_on_phone": frida_up_cmd,
            "termux_one_liner": termux_cmd,
            "verify_urls": {
                "connection_status": f"http://{lan_ip}:{sdk_port}/api/v3/connection/status",
                "hook_probe": f"http://{lan_ip}:{sdk_port}/api/v3/hook/probe/{device_id}",
            },
            "acceptance_script": "bash sdk/scripts/run_wechat_full_acceptance.sh",
            "interface_audit": "python3 sdk/scripts/wechat_interface_audit.py --probe-full -d " + device_id,
            "catalog_verify": f"python3 sdk/scripts/matrix_hook_catalog_verify.py -d {device_id}",
            "wechat_actions": 128,
            "catalog_actions": 174,
        }),
    }


async def simulate_register(req: SimRegisterRequest) -> Dict[str, Any]:
    """协议联调：模拟设备 register（不建立真实 WS，仅写入状态面板）。"""
    await ws_hub.handle_message(
        req.device_id,
        {
            "type": "register",
            "data": {
                "device_id": req.device_id,
                "project_id": req.project_id,
                "model": req.model,
                "platform": req.platform,
                "status": "simulated",
                "capabilities": req.capabilities,
                "source": "connection_simulator",
            },
        },
    )
    return {"code": 200, "data": {"device_id": req.device_id, "simulated": True, "action": "register"}}


@router.post("/connection/simulate/heartbeat")
async def simulate_heartbeat(req: SimHeartbeatRequest) -> Dict[str, Any]:
    """协议联调：模拟心跳。"""
    if not ws_hub.get_device_info(req.device_id):
        raise HTTPException(status_code=404, detail="设备未注册，先模拟 register")
    await ws_hub.handle_message(req.device_id, {"type": "heartbeat", "device_id": req.device_id})
    return {"code": 200, "data": {"device_id": req.device_id, "simulated": True, "action": "heartbeat"}}


@router.post("/connection/simulate/hook-event")
async def simulate_hook_event(req: SimHookEventRequest) -> Dict[str, Any]:
    """协议联调：模拟 hook 事件写入并广播到事件流。"""
    event = await hook_module_service.add_event(
        {
            "event_type": req.event_type,
            "device_id": req.device_id,
            "platform": req.platform,
            "payload": req.payload,
            "source": "connection_simulator",
        }
    )
    return {"code": 200, "data": event}


# ========== 连接优先级 ==========

@router.get("/connection/modes/{device_id}")
async def get_device_connection_modes(device_id: str, refresh: bool = False) -> Dict[str, Any]:
    """获取设备所有控制模式的可用性与优先级。refresh=true 强制刷新缓存。"""
    if refresh:
        connection_priority.invalidate_cache()
    modes = await connection_priority.async_evaluate(device_id)
    best = next((m for m in modes if m.available), None)
    return {
        "code": 200,
        "data": enrich_device_id_fields({
            "device_id": device_id,
            "best_mode": best.to_dict() if best else None,
            "modes": [m.to_dict() for m in modes],
        }),
    }


@router.get("/connection/modes")
async def get_all_connection_modes() -> Dict[str, Any]:
    """获取所有已知设备的控制模式概览。"""
    online_ids = list(ws_hub.connections.keys())
    adb_serials = await adb_manager.async_scan_devices()
    all_ids = list(set(online_ids + adb_serials))

    result = []
    for did in all_ids:
        modes = await connection_priority.async_evaluate(did)
        best = next((m for m in modes if m.available), None)
        result.append(enrich_device_id_fields({
            "device_id": did,
            "best_mode": best.to_dict() if best else None,
            "available_count": sum(1 for m in modes if m.available),
            "modes": [m.to_dict() for m in modes],
        }))
    return {"code": 200, "data": result}
