"""
工作手机SDK v3.0 - 设备管理路由
"""

from fastapi import APIRouter, HTTPException, Depends
from typing import List, Optional
from pydantic import BaseModel

from services.ws_hub import ws_hub
from services.device_manager import device_manager

router = APIRouter()


# ========== 数据模型 ==========

class DeviceResponse(BaseModel):
    """设备信息响应"""
    device_id: str
    device_id_md5: Optional[str] = None
    name: Optional[str] = None
    model: Optional[str] = None
    status: str = "offline"
    android_version: Optional[str] = None
    agent_version: Optional[str] = None
    capabilities: List[str] = []
    apps: List[str] = []
    last_heartbeat: Optional[str] = None


class ScreenshotResponse(BaseModel):
    """截图响应"""
    image_url: Optional[str] = None
    base64: Optional[str] = None
    width: int
    height: int


class ClickRequest(BaseModel):
    """点击请求"""
    x: int
    y: int


class ClickTextRequest(BaseModel):
    """点击文字请求"""
    text: str
    timeout: int = 10


class InputRequest(BaseModel):
    """输入请求"""
    text: str
    clear: bool = True


class SwipeRequest(BaseModel):
    """滑动请求"""
    direction: str  # up, down, left, right
    scale: float = 0.8


class HeartbeatConfigRequest(BaseModel):
    """心跳配置请求"""
    heartbeat_interval_seconds: int


class AITaskRequest(BaseModel):
    """AI 任务推送请求"""
    instruction: str
    priority: int = 5


class StandingOrderRequest(BaseModel):
    """常驻指令推送请求"""
    order: str


# ========== 设备列表 ==========

@router.get("/devices", response_model=dict)
async def get_devices():
    """获取所有设备列表（融合 WebSocket + ADB + DB）"""
    from services.device_fleet import list_merged_local_devices

    devices = await list_merged_local_devices()
    return {"code": 200, "data": devices}


@router.get("/devices/{device_id}", response_model=dict)
async def get_device(device_id: str):
    """获取设备详情（支持 WebSocket / ADB / DB）"""
    from services.adb_device import adb_manager
    
    # 检查 WebSocket 在线
    online_info = ws_hub.get_device_info(device_id)
    
    # 检查数据库（容错）
    db_info = None
    try:
        db_info = await device_manager.get_device(device_id)
    except Exception:
        pass
    
    # 检查 ADB 直连（在线程池中执行以避免阻塞）
    adb_info = None
    import asyncio

    def _check_adb():
        dev = adb_manager.get_device(device_id)
        if dev and dev.is_online():
            info = dev.get_info()
            info["connection_type"] = "adb"
            return info
        return None
    try:
        adb_info = await asyncio.get_running_loop().run_in_executor(None, _check_adb)
    except Exception:
        pass
    
    if not online_info and not db_info and not adb_info:
        raise HTTPException(status_code=404, detail="设备不存在")
    
    device = {**(db_info or {}), **(adb_info or {}), **(online_info or {})}
    if online_info:
        device["status"] = "online"
    elif adb_info:
        device["status"] = "adb"
    else:
        device["status"] = "offline"
    device["device_id"] = device_id
    from services.device_id_util import enrich_device_id_fields, sanitize_sensitive_fields
    enrich_device_id_fields(device)

    # 若 model/brand/android_version 为空或 Unknown，从 ADB 补充（设备可能同时连 WS 和 USB）
    def _is_empty_or_unknown(v) -> bool:
        return not v or (isinstance(v, str) and v.strip().lower() in ("", "unknown", "未知"))
    for field in ("model", "brand", "android_version"):
        if _is_empty_or_unknown(device.get(field)) and adb_info and adb_info.get(field):
            device[field] = adb_info[field]
    # 若仍缺失，尝试从 adb_manager 实时拉取（设备可能刚连上 ADB）
    if _is_empty_or_unknown(device.get("model")) or _is_empty_or_unknown(device.get("android_version")):
        try:
            dev = adb_manager.get_device(device_id)
            if dev and dev.is_online():
                info = await asyncio.wait_for(
                    asyncio.get_running_loop().run_in_executor(None, dev.get_info),
                    timeout=5.0,
                )
                for field in ("model", "brand", "android_version"):
                    if _is_empty_or_unknown(device.get(field)) and info.get(field):
                        device[field] = info[field]
        except (asyncio.TimeoutError, Exception):
            pass

    return {"code": 200, "data": sanitize_sensitive_fields(device)}


@router.get("/devices/{device_id}/heartbeat", response_model=dict)
async def get_device_heartbeat(device_id: str):
    """查询设备心跳状态"""
    status = ws_hub.get_heartbeat_status(device_id)
    if not status:
        raise HTTPException(status_code=404, detail="设备不存在或未上报心跳")
    return {"code": 200, "data": status}


@router.post("/devices/{device_id}/heartbeat/config", response_model=dict)
async def set_device_heartbeat(device_id: str, req: HeartbeatConfigRequest):
    """下发设备心跳配置（5-120 秒）"""
    ok = await ws_hub.set_heartbeat_interval(device_id, req.heartbeat_interval_seconds)
    if not ok:
        raise HTTPException(status_code=400, detail="heartbeat_interval_seconds 必须在 5-120 之间")
    return {
        "code": 200,
        "data": {
            "device_id": device_id,
            "heartbeat_interval_seconds": req.heartbeat_interval_seconds,
        },
    }


# ========== 设备控制 ==========

@router.post("/devices/{device_id}/screenshot", response_model=dict)
async def screenshot(device_id: str):
    """获取设备截图：WS Agent 优先，超时/失败时走 ADB 截图兜底。"""

    async def _adb_fallback(reason: str):
        from services.adb_device import adb_manager

        dev = adb_manager.get_device(device_id)
        if not dev:
            raise HTTPException(status_code=503, detail=f"设备不在线，截图失败: {reason}")
        result = dev.screenshot()
        if result.get("code") != 200:
            raise HTTPException(status_code=result.get("code", 500), detail=result.get("message") or reason)
        data = result.get("data", {})
        data["fallback"] = "adb"
        data["fallback_reason"] = reason
        return {"code": 200, "data": data}

    if not ws_hub.is_online(device_id):
        return await _adb_fallback("ws_offline")

    try:
        result = await ws_hub.send_command(device_id, {
            "type": "execute",
            "data": {
                "action": "screenshot"
            }
        }, timeout=12)
    except Exception as exc:
        return await _adb_fallback(f"ws_exception:{exc}")

    if result.get("code") != 200:
        return await _adb_fallback(result.get("message") or f"ws_code:{result.get('code')}")

    data = result.get("data", {})
    if not data.get("base64"):
        return await _adb_fallback("ws_empty_screenshot")
    data["fallback"] = "ws"
    return {"code": 200, "data": data}


@router.post("/devices/{device_id}/click", response_model=dict)
async def click(device_id: str, req: ClickRequest):
    """点击坐标"""
    
    if not ws_hub.is_online(device_id):
        raise HTTPException(status_code=503, detail="设备不在线")
    
    result = await ws_hub.send_command(device_id, {
        "type": "execute",
        "data": {
            "action": "click",
            "params": {"x": req.x, "y": req.y}
        }
    })
    
    return {"code": 200, "data": result.get("data", {})}


@router.post("/devices/{device_id}/click-text", response_model=dict)
async def click_text(device_id: str, req: ClickTextRequest):
    """点击文字"""
    
    if not ws_hub.is_online(device_id):
        raise HTTPException(status_code=503, detail="设备不在线")
    
    result = await ws_hub.send_command(device_id, {
        "type": "execute",
        "data": {
            "action": "click_text",
            "params": {"text": req.text, "timeout": req.timeout}
        }
    })
    
    return {"code": 200, "data": result.get("data", {})}


@router.post("/devices/{device_id}/input", response_model=dict)
async def input_text(device_id: str, req: InputRequest):
    """输入文字"""
    
    if not ws_hub.is_online(device_id):
        raise HTTPException(status_code=503, detail="设备不在线")
    
    result = await ws_hub.send_command(device_id, {
        "type": "execute",
        "data": {
            "action": "input",
            "params": {"text": req.text, "clear": req.clear}
        }
    })
    
    return {"code": 200, "data": result.get("data", {})}


@router.post("/devices/{device_id}/swipe", response_model=dict)
async def swipe(device_id: str, req: SwipeRequest):
    """滑动"""
    
    if not ws_hub.is_online(device_id):
        raise HTTPException(status_code=503, detail="设备不在线")
    
    result = await ws_hub.send_command(device_id, {
        "type": "execute",
        "data": {
            "action": "swipe",
            "params": {"direction": req.direction, "scale": req.scale}
        }
    })
    
    return {"code": 200, "data": result.get("data", {})}


@router.get("/devices/{device_id}/ui-tree", response_model=dict)
async def get_ui_tree(device_id: str):
    """获取UI树"""
    
    if not ws_hub.is_online(device_id):
        raise HTTPException(status_code=503, detail="设备不在线")
    
    result = await ws_hub.send_command(device_id, {
        "type": "execute",
        "data": {
            "action": "ui_tree"
        }
    })
    
    return {"code": 200, "data": result.get("data", {})}


# ========== 脚本执行 ==========

@router.post("/devices/{device_id}/execute", response_model=dict)
async def execute_script(device_id: str, script: str, action: str, params: dict = {}, timeout: int = 30):
    """执行脚本"""
    
    if not ws_hub.is_online(device_id):
        raise HTTPException(status_code=503, detail="设备不在线")
    
    result = await ws_hub.send_command(device_id, {
        "type": "execute",
        "data": {
            "script": script,
            "action": action,
            "params": params
        }
    }, timeout=timeout)
    
    await device_manager.log_command(device_id, f"{script}.{action}", params, result)
    
    return {
        "code": result.get("code", 200),
        "message": result.get("message", ""),
        "data": result.get("data", {}),
    }


# ========== AI Brain 管理 ==========

@router.get("/devices/{device_id}/ai/status", response_model=dict)
async def get_ai_brain_status(device_id: str):
    """获取设备 AI Brain 状态"""
    status = ws_hub.get_ai_brain_status(device_id)
    if not status:
        raise HTTPException(status_code=404, detail="设备不存在或未上线")
    return {"code": 200, "data": status}


@router.post("/devices/{device_id}/ai/task", response_model=dict)
async def push_ai_task(device_id: str, req: AITaskRequest):
    """向设备推送 AI 任务（AI Brain 会在下次心跳周期执行）"""
    if not ws_hub.is_online(device_id):
        raise HTTPException(status_code=503, detail="设备不在线")

    ok = await ws_hub.push_ai_task(device_id, req.instruction, req.priority)
    if not ok:
        raise HTTPException(status_code=500, detail="推送失败")
    return {
        "code": 200,
        "data": {
            "device_id": device_id,
            "instruction": req.instruction,
            "priority": req.priority,
            "status": "queued",
        },
    }


@router.post("/devices/{device_id}/ai/standing-order", response_model=dict)
async def push_standing_order(device_id: str, req: StandingOrderRequest):
    """向设备推送常驻指令（离线时自动执行）"""
    if not ws_hub.is_online(device_id):
        raise HTTPException(status_code=503, detail="设备不在线")

    ok = await ws_hub.push_standing_order(device_id, req.order)
    if not ok:
        raise HTTPException(status_code=500, detail="推送失败")
    return {
        "code": 200,
        "data": {
            "device_id": device_id,
            "order": req.order,
            "status": "pushed",
        },
    }


@router.post("/devices/{device_id}/ai/execute", response_model=dict)
async def ai_execute(device_id: str, task: str, timeout: int = 60):
    """让设备 AI Agent 执行自然语言任务（同步等待结果）"""
    if not ws_hub.is_online(device_id):
        raise HTTPException(status_code=503, detail="设备不在线")

    result = await ws_hub.send_command(device_id, {
        "type": "agent_execute",
        "data": {"task": task},
    }, timeout=timeout)

    return {
        "code": result.get("code", 200),
        "message": result.get("message", ""),
        "data": result.get("data", {}),
    }


class DeviceAIChatRequest(BaseModel):
    """卡若网关决策 + WS 下发（手机无需本地 api_key）"""
    instruction: str
    timeout: int = 120


@router.post("/devices/{device_id}/ai/chat", response_model=dict)
async def device_ai_chat(device_id: str, req: DeviceAIChatRequest):
    """
    小 AI 核心端点：服务端调卡若 /api/gateway/chat 决策，经 WS 让手机执行。
    与日常卡若接口一致，不另建 Ollama/local-ai。
    """
    from services.karuo_device_ai import chat_and_execute_on_device

    result = await chat_and_execute_on_device(device_id, req.instruction, req.timeout)
    code = int(result.get("code", 200))
    if code >= 400:
        raise HTTPException(status_code=code, detail=result.get("message", "执行失败"))
    return {"code": 200, "data": result}


class HotUpdateRequest(BaseModel):
    update_type: str = "config"  # config | hub_html | refresh
    config: Optional[dict] = None
    content: Optional[str] = None
    url: Optional[str] = None


@router.post("/devices/{device_id}/hot-update", response_model=dict)
async def device_hot_update(device_id: str, req: HotUpdateRequest):
    """热更新 Hub / 配置（如 ai_api_key），无需重装 APK"""
    if not ws_hub.is_online(device_id):
        raise HTTPException(status_code=503, detail="设备不在线")
    payload: dict = {"update_type": req.update_type}
    if req.config:
        payload["config"] = req.config
    if req.content:
        payload["content"] = req.content
    if req.url:
        payload["url"] = req.url
    result = await ws_hub.send_command(
        device_id,
        {"type": "ui_update", "data": payload},
        timeout=60,
    )
    return {"code": result.get("code", 200), "data": result}


# ========== AI 心跳监控仪表盘 ==========

@router.get("/heartbeat/dashboard", response_model=dict)
async def heartbeat_dashboard():
    """AI 心跳监控仪表盘 — 所有设备健康总览"""
    from services.ai_heartbeat import ai_heartbeat
    return {"code": 200, "data": ai_heartbeat.get_dashboard()}


@router.get("/devices/{device_id}/health", response_model=dict)
async def device_health(device_id: str):
    """获取单台设备的 AI 健康评分与状态"""
    from services.ai_heartbeat import ai_heartbeat
    h = ai_heartbeat.get_device_health(device_id)
    if not h:
        raise HTTPException(status_code=404, detail="设备未纳入监控")
    return {"code": 200, "data": h}


@router.get("/devices/{device_id}/health/events", response_model=dict)
async def device_health_events(device_id: str, limit: int = 30):
    """获取设备健康事件（告警历史）"""
    from services.ai_heartbeat import ai_heartbeat
    return {"code": 200, "data": ai_heartbeat.get_events(device_id, limit)}


@router.get("/heartbeat/events", response_model=dict)
async def all_health_events(limit: int = 50):
    """全局健康事件流"""
    from services.ai_heartbeat import ai_heartbeat
    return {"code": 200, "data": ai_heartbeat.get_events(limit=limit)}


@router.post("/devices/{device_id}/ai/queue-task", response_model=dict)
async def queue_ai_task(device_id: str, req: AITaskRequest):
    """向设备心跳任务队列添加待执行任务（心跳周期自动下发）"""
    from services.ai_heartbeat import ai_heartbeat
    ai_heartbeat.enqueue_task(device_id, {
        "instruction": req.instruction,
        "priority": req.priority,
    })
    return {
        "code": 200,
        "data": ai_heartbeat.get_task_queue_status(device_id),
    }


# ========== 连接守护事件 ==========

_guard_event_store: dict = {}
_MAX_EVENTS_PER_DEVICE = 200


@router.get("/devices/{device_id}/guard-events", response_model=dict, tags=["连接守护"])
async def get_guard_events(device_id: str, limit: int = 50):
    """获取设备的连接守护事件（弹窗处理、异常告警等）"""
    events = _guard_event_store.get(device_id, [])
    return {"code": 200, "data": {"device_id": device_id, "events": events[-limit:], "total": len(events)}}


@router.post("/devices/{device_id}/guard-events", response_model=dict, tags=["连接守护"])
async def post_guard_event(device_id: str, event: dict):
    """上报连接守护事件（Agent 心跳或守护循环调用）"""
    import time
    event["server_received_at"] = time.time()
    if device_id not in _guard_event_store:
        _guard_event_store[device_id] = []
    _guard_event_store[device_id].append(event)
    if len(_guard_event_store[device_id]) > _MAX_EVENTS_PER_DEVICE:
        _guard_event_store[device_id] = _guard_event_store[device_id][-_MAX_EVENTS_PER_DEVICE:]
    return {"code": 200, "data": {"stored": True}}


@router.get("/guard-events/all", response_model=dict, tags=["连接守护"])
async def get_all_guard_events(limit: int = 100):
    """获取所有设备的守护事件（全局视图）"""
    all_events = []
    for did, events in _guard_event_store.items():
        for evt in events:
            all_events.append({**evt, "device_id": did})
    all_events.sort(key=lambda x: x.get("server_received_at", 0), reverse=True)
    return {"code": 200, "data": {"events": all_events[:limit], "total": len(all_events)}}
