"""
设备列表融合：WebSocket + MongoDB + ADB（供 /devices 与多机注册聚合复用）
"""

from typing import Any, Dict, List
import asyncio
import re

from services.ws_hub import ws_hub
from services.device_manager import device_manager
from services.adb_device import adb_manager
from services.device_id_util import enrich_device_id_fields, sanitize_sensitive_fields


async def list_merged_local_devices() -> List[Dict[str, Any]]:
    """与 routers.devices.get_devices 逻辑一致，返回设备 dict 列表。"""
    db_devices: List[dict] = []
    try:
        db_devices = await device_manager.get_all_devices()
    except Exception:
        pass

    online_devices = {d["device_id"]: d for d in ws_hub.get_online_devices()}
    online_serials = {
        value
        for d in online_devices.values()
        for value in (d.get("device_id"), d.get("serial"), d.get("adb_serial"), d.get("wifi_serial"))
        if value
    }
    online_fingerprints = {
        d.get("fingerprint_hash")
        for d in online_devices.values()
        if d.get("fingerprint_hash")
    }
    online_models = {
        d.get("model")
        for d in online_devices.values()
        if d.get("model")
    }
    try:
        adb_serials = await asyncio.wait_for(adb_manager.async_scan_devices(), timeout=0.5)
    except asyncio.TimeoutError:
        adb_serials = list(adb_manager._scan_cache or [])

    seen_ids: set = set()
    devices: List[Dict[str, Any]] = []

    for raw in db_devices:
        device = dict(raw)
        device_id = device["device_id"]
        serial = device.get("serial") or device.get("adb_serial") or device.get("wifi_serial")
        fingerprint = device.get("fingerprint_hash")
        is_online_alias = (
            device_id not in online_devices
            and (
                (serial and serial in online_serials)
                or (fingerprint and fingerprint in online_fingerprints)
            )
        )
        adb_serial = adb_manager.resolve_serial(device_id)
        is_adb_alias = (
            device_id not in online_devices
            and adb_serial in adb_serials
            and device_id != adb_serial
        )
        is_stale_synthetic_alias = (
            device_id not in online_devices
            and not serial
            and isinstance(device_id, str)
            and re.fullmatch(r"[0-9a-f]{32}", device_id)
            and device.get("model") in online_models
        )
        if is_online_alias or is_adb_alias or is_stale_synthetic_alias:
            continue
        seen_ids.add(device_id)
        if device_id in online_devices:
            device = {**device, **online_devices[device_id]}
            device["status"] = "online"
        else:
            device["status"] = "offline"
        devices.append(enrich_device_id_fields(device))

    for device_id, info in online_devices.items():
        if device_id not in seen_ids:
            seen_ids.add(device_id)
            devices.append(enrich_device_id_fields(dict(info)))

    for serial in adb_serials:
        if serial not in seen_ids:
            adb_dev = adb_manager.get_device(serial)
            if adb_dev:
                info = adb_dev.get_info()
                real_serial = info.get("serial") or serial
                fingerprint = device_manager.compute_fingerprint({"device_id": real_serial, **info})
                is_wifi_adb_alias = isinstance(serial, str) and ":" in serial and info.get("model") in online_models
                if real_serial in online_serials or fingerprint in online_fingerprints or is_wifi_adb_alias:
                    continue
                devices.append(
                    enrich_device_id_fields(
                        {
                            "device_id": serial,
                            "model": info.get("model", "Unknown"),
                            "brand": info.get("brand", "Unknown"),
                            "android_version": info.get("android_version", "Unknown"),
                            "status": "adb",
                            "connection_type": "adb",
                            "display": info.get("display", {}),
                        }
                    )
                )

    return sanitize_sensitive_fields(devices)
