import asyncio
import aiohttp
import struct
import logging
from typing import Optional, Dict, Any
from PIL import Image

# 配置日志
logging.basicConfig(
    level=logging.DEBUG, format="%(asctime)s - %(levelname)s - %(message)s"
)
logger = logging.getLogger(__name__)


class RFBProtocol:
    """RFB (Remote FrameBuffer) 协议处理类"""

    # RFB协议版本
    RFB_VERSION = b"RFB 003.008\n"

    # 安全类型
    SECURITY_NONE = 1
    SECURITY_VNC_AUTH = 2

    # 客户端到服务器消息类型
    CLIENT_SET_PIXEL_FORMAT = 0
    CLIENT_SET_ENCODINGS = 2
    CLIENT_FRAMEBUFFER_UPDATE_REQUEST = 3
    CLIENT_KEY_EVENT = 4
    CLIENT_POINTER_EVENT = 5
    CLIENT_CUT_TEXT = 6

    # 服务器到客户端消息类型
    SERVER_FRAMEBUFFER_UPDATE = 0
    SERVER_SET_COLOUR_MAP_ENTRIES = 1
    SERVER_BELL = 2
    SERVER_CUT_TEXT = 3

    # 鼠标按钮掩码
    MOUSE_LEFT_BUTTON = 1  # bit 0
    MOUSE_MIDDLE_BUTTON = 2  # bit 1
    MOUSE_RIGHT_BUTTON = 4  # bit 2
    MOUSE_SCROLL_UP = 8  # bit 3
    MOUSE_SCROLL_DOWN = 16  # bit 4


class NoVNCClient:
    """noVNC WebSocket + RFB 客户端"""

    def __init__(
        self, host: str = "localhost", port: int = 6080, path: str = "/websockify"
    ):
        self.host = host
        self.port = port
        self.path = path
        self.websocket: Optional[aiohttp.ClientWebSocketResponse] = None
        self.session: Optional[aiohttp.ClientSession] = None
        self.server_name: str = ""
        self.width: int = 0
        self.height: int = 0
        self.pixel_format: Dict[str, Any] = {}
        self.framebuffer: Optional[bytearray] = None

    async def connect(self) -> bool:
        """连接到noVNC WebSocket服务"""
        try:
            self.session = aiohttp.ClientSession()
            url = f"ws://{self.host}:{self.port}{self.path}"
            logger.info(f"正在连接到 {url}")

            self.websocket = await self.session.ws_connect(url)
            logger.info("WebSocket连接成功")
            return True

        except Exception as e:
            logger.error(f"WebSocket连接失败: {e}")
            if self.session:
                await self.session.close()
            return False

    async def disconnect(self):
        """断开连接"""
        if self.websocket:
            await self.websocket.close()
        if self.session:
            await self.session.close()
        logger.info("连接已断开")

    async def send_binary(self, data: bytes):
        """发送二进制数据"""
        if self.websocket:
            await self.websocket.send_bytes(data)
            logger.debug(f"发送数据: {data.hex()[:100]}...")

    async def receive_binary(self, length: Optional[int] = None) -> bytes:
        """接收二进制数据"""
        if not self.websocket:
            return b""

        try:
            msg = await asyncio.wait_for(self.websocket.receive(), timeout=10.0)
            if msg.type == aiohttp.WSMsgType.BINARY:
                logger.debug(f"接收数据: {msg.data.hex()[:100]}...")
                return msg.data
            elif msg.type == aiohttp.WSMsgType.TEXT:
                logger.debug(f"接收文本: {msg.data}")
                return msg.data.encode("utf-8")
            elif msg.type == aiohttp.WSMsgType.ERROR:
                logger.error(f"WebSocket错误: {self.websocket.exception()}")
                return b""
            elif msg.type == aiohttp.WSMsgType.CLOSE:
                logger.info("WebSocket连接已关闭")
                return b""
            else:
                logger.warning(f"未知消息类型: {msg.type}")
                return b""
        except asyncio.TimeoutError:
            logger.error("接收数据超时")
            return b""
        except Exception as e:
            logger.error(f"接收数据失败: {e}")
            return b""

    async def rfb_handshake(self) -> bool:
        """执行RFB协议握手"""
        try:
            # 1. 协议版本协商
            logger.info("开始RFB协议握手...")

            # 接收服务器版本
            version_data = await self.receive_binary()
            if not version_data:
                logger.error("无法接收服务器版本")
                return False

            if not version_data.startswith(b"RFB "):
                logger.error(f"无效的RFB版本: {version_data}")
                return False

            logger.info(f"服务器RFB版本: {version_data.decode().strip()}")

            # 发送客户端版本
            await self.send_binary(RFBProtocol.RFB_VERSION)
            logger.info("已发送客户端RFB版本")

            # 2. 安全类型协商
            security_data = await self.receive_binary()
            if not security_data or len(security_data) < 1:
                logger.error("无法接收安全类型")
                return False

            security_types_count = security_data[0]
            logger.info(f"可用安全类型数量: {security_types_count}")

            if security_types_count == 0:
                # 连接失败
                if len(security_data) >= 5:
                    reason_length = struct.unpack(">I", security_data[1:5])[0]
                    reason = security_data[5 : 5 + reason_length].decode("utf-8")
                    logger.error(f"连接被拒绝: {reason}")
                else:
                    logger.error("连接被拒绝，原因未知")
                return False

            # 选择无认证方式
            security_types = security_data[1 : 1 + security_types_count]
            if RFBProtocol.SECURITY_NONE in security_types:
                await self.send_binary(bytes([RFBProtocol.SECURITY_NONE]))
                logger.info("选择无认证安全类型")
            else:
                logger.error(
                    f"服务器不支持无认证模式，可用类型: {list(security_types)}"
                )
                return False

            # 3. 安全结果
            security_result = await self.receive_binary()
            if not security_result or len(security_result) < 4:
                logger.error("无法接收安全结果")
                return False

            result = struct.unpack(">I", security_result[:4])[0]
            if result != 0:
                logger.error(f"安全握手失败: {result}")
                return False
            logger.info("安全握手成功")

            # 4. 客户端初始化
            # shared_flag = 1 表示共享桌面
            await self.send_binary(bytes([1]))
            logger.info("已发送客户端初始化消息")

            # 5. 服务器初始化
            server_init = await self.receive_binary()
            if not server_init or len(server_init) < 24:
                logger.error(
                    f"服务器初始化消息太短，长度: {len(server_init) if server_init else 0}"
                )
                return False

            # 解析服务器初始化消息
            self.width = struct.unpack(">H", server_init[0:2])[0]
            self.height = struct.unpack(">H", server_init[2:4])[0]

            # 像素格式 (16字节)
            pixel_format = server_init[4:20]
            self.pixel_format = {
                "bits_per_pixel": pixel_format[0],
                "depth": pixel_format[1],
                "big_endian": pixel_format[2],
                "true_colour": pixel_format[3],
                "red_max": struct.unpack(">H", pixel_format[4:6])[0],
                "green_max": struct.unpack(">H", pixel_format[6:8])[0],
                "blue_max": struct.unpack(">H", pixel_format[8:10])[0],
                "red_shift": pixel_format[10],
                "green_shift": pixel_format[11],
                "blue_shift": pixel_format[12],
            }

            # 服务器名称长度和名称
            name_length = struct.unpack(">I", server_init[20:24])[0]
            if len(server_init) >= 24 + name_length:
                self.server_name = server_init[24 : 24 + name_length].decode(
                    "utf-8", errors="ignore"
                )

            logger.info("服务器初始化完成:")
            logger.info(f"  分辨率: {self.width}x{self.height}")
            logger.info(f"  像素格式: {self.pixel_format}")
            logger.info(f"  服务器名称: {self.server_name}")

            return True

        except Exception as e:
            logger.error(f"RFB握手失败: {e}")
            import traceback

            logger.debug(traceback.format_exc())
            return False

    async def request_framebuffer_update(
        self,
        incremental: bool = False,
        x: int = 0,
        y: int = 0,
        width: Optional[int] = None,
        height: Optional[int] = None,
    ):
        """请求帧缓冲区更新"""
        if width is None:
            width = self.width
        if height is None:
            height = self.height

        # 构造帧缓冲区更新请求消息
        message = struct.pack(
            ">BBHHHH",
            RFBProtocol.CLIENT_FRAMEBUFFER_UPDATE_REQUEST,
            1 if incremental else 0,
            x,
            y,
            width,
            height,
        )

        await self.send_binary(message)
        logger.info(f"请求帧缓冲区更新: {x},{y} {width}x{height} (增量: {incremental})")

    async def handle_server_message(self) -> bool:
        """处理服务器消息"""
        try:
            # 接收消息类型
            msg_data = await self.receive_binary()
            if not msg_data:
                return False

            msg_type = msg_data[0]

            if msg_type == RFBProtocol.SERVER_FRAMEBUFFER_UPDATE:
                await self._handle_framebuffer_update(msg_data)
                return True

            elif msg_type == RFBProtocol.SERVER_BELL:
                logger.info("收到响铃消息")
                return True

            elif msg_type == RFBProtocol.SERVER_CUT_TEXT:
                logger.info("收到剪贴板文本消息")
                return True

            else:
                logger.warning(f"未知的服务器消息类型: {msg_type}")
                return True

        except Exception as e:
            logger.error(f"处理服务器消息失败: {e}")
            return False

    async def _handle_framebuffer_update(self, initial_data: bytes):
        """处理帧缓冲区更新消息"""
        try:
            # 简化处理：从初始数据解析基本信息
            if len(initial_data) < 4:
                logger.error("帧缓冲区更新数据不足")
                return

            # 解析头部：消息类型(1) + padding(1) + rectangles数量(2)
            rect_count = struct.unpack(">H", initial_data[2:4])[0]
            logger.info(f"收到帧缓冲区更新，包含 {rect_count} 个矩形")

            # 检查是否有矩形数据
            if len(initial_data) >= 16:  # 4字节头部 + 12字节矩形头部
                # 解析第一个矩形
                x, y, width, height, encoding = struct.unpack(
                    ">HHHHI", initial_data[4:16]
                )
                logger.info(f"矩形: ({x},{y}) {width}x{height}, 编码: {encoding}")

                if encoding == 0:  # Raw encoding
                    # 简化处理：直接将后续接收到的数据作为像素数据处理
                    pixel_data = initial_data[16:]  # 跳过头部和矩形头部

                    # 继续接收像素数据
                    bytes_per_pixel = 4  # 32位BGRA
                    expected_size = width * height * bytes_per_pixel

                    # 累积接收剩余数据
                    attempts = 0
                    max_attempts = 200  # 增加最大尝试次数
                    while len(pixel_data) < expected_size and attempts < max_attempts:
                        additional = await self.receive_binary()
                        if additional:
                            pixel_data += additional
                            logger.debug(
                                f"累积接收: {len(pixel_data)}/{expected_size} 字节"
                            )
                        else:
                            logger.debug(f"接收数据为空，尝试次数: {attempts}")
                            await asyncio.sleep(0.01)  # 短暂等待
                        attempts += 1

                        # 每接收一定量数据就更新一次进度
                        if attempts % 50 == 0:
                            logger.info(
                                f"接收进度: {len(pixel_data)}/{expected_size} 字节 ({len(pixel_data) / expected_size * 100:.1f}%)"
                            )

                    if len(pixel_data) >= expected_size:
                        # 更新帧缓冲区
                        await self._update_framebuffer(
                            x, y, width, height, pixel_data[:expected_size]
                        )
                        logger.info(f"成功更新帧缓冲区: ({x},{y}) {width}x{height}")
                    else:
                        logger.warning(
                            f"像素数据不足: 期望 {expected_size}, 实际 {len(pixel_data)}"
                        )
                else:
                    logger.warning(f"不支持的编码类型: {encoding}")
            else:
                logger.warning("帧缓冲区更新数据格式不完整")

        except Exception as e:
            logger.error(f"处理帧缓冲区更新失败: {e}")
            import traceback

            logger.debug(traceback.format_exc())

    async def _update_framebuffer(
        self, x: int, y: int, width: int, height: int, pixel_data: bytes
    ):
        """更新帧缓冲区"""
        try:
            # 初始化帧缓冲区
            if self.framebuffer is None:
                bytes_per_pixel = self.pixel_format.get("bits_per_pixel", 32) // 8
                total_size = self.width * self.height * bytes_per_pixel
                self.framebuffer = bytearray(total_size)

            bytes_per_pixel = self.pixel_format.get("bits_per_pixel", 32) // 8
            fb = bytearray(self.framebuffer)

            # 将像素数据复制到帧缓冲区的相应位置
            for row in range(height):
                src_offset = row * width * bytes_per_pixel
                dst_offset = ((y + row) * self.width + x) * bytes_per_pixel
                fb[dst_offset : dst_offset + width * bytes_per_pixel] = pixel_data[
                    src_offset : src_offset + width * bytes_per_pixel
                ]

            self.framebuffer = fb

        except Exception as e:
            logger.error(f"更新帧缓冲区失败: {e}")

    async def save_screenshot(self, filename: str = "screenshot.png") -> bool:
        """保存当前帧缓冲区为PNG图片"""
        try:
            if self.framebuffer is None:
                logger.error("帧缓冲区为空，无法保存截图")
                return False

            if self.width == 0 or self.height == 0:
                logger.error("屏幕尺寸无效，无法保存截图")
                return False

            # 获取像素格式信息
            bits_per_pixel = self.pixel_format.get("bits_per_pixel", 32)
            bytes_per_pixel = bits_per_pixel // 8

            # 检查数据长度
            expected_size = self.width * self.height * bytes_per_pixel
            if len(self.framebuffer) < expected_size:
                logger.error(
                    f"帧缓冲区数据不足，期望 {expected_size} 字节，实际 {len(self.framebuffer)} 字节"
                )
                return False

            # 转换像素格式
            if bits_per_pixel == 32:
                # 假设是BGRA格式，转换为RGB
                rgb_data = bytearray()
                for i in range(0, len(self.framebuffer), 4):
                    if i + 3 < len(self.framebuffer):
                        b = self.framebuffer[i]
                        g = self.framebuffer[i + 1]
                        r = self.framebuffer[i + 2]
                        # 跳过alpha通道
                        rgb_data.extend([r, g, b])

                # 创建PIL图像
                image = Image.frombytes(
                    "RGB", (self.width, self.height), bytes(rgb_data)
                )
            else:
                logger.error(f"不支持的像素格式: {bits_per_pixel} 位")
                return False

            # 保存图片
            image.save(filename)
            logger.info(f"截图已保存到: {filename}")
            return True

        except Exception as e:
            logger.error(f"保存截图失败: {e}")
            import traceback

            logger.debug(traceback.format_exc())
            return False

    async def run_session(self, duration: Optional[int] = 10):
        """运行会话，duration为None时不限时间运行"""
        logger.info(
            f"开始运行会话... {'无限时间' if duration is None else f'{duration}秒'}"
        )

        if not await self.connect():
            logger.error("连接失败")
            return False

        try:
            if not await self.rfb_handshake():
                logger.error("RFB握手失败")
                return False

            # 请求初始帧缓冲区更新
            await self.request_framebuffer_update(incremental=False)

            # 处理消息循环
            start_time = asyncio.get_event_loop().time()
            message_count = 0

            while True:
                # 检查是否超时（如果设置了duration）
                if (
                    duration is not None
                    and asyncio.get_event_loop().time() - start_time >= duration
                ):
                    break

                if not await self.handle_server_message():
                    break
                message_count += 1
                await asyncio.sleep(0.1)

            logger.info(f"会话结束，处理了 {message_count} 条消息")
            return True

        except KeyboardInterrupt:
            logger.info("会话被用户中断")
            return True
        except Exception as e:
            logger.error(f"会话运行失败: {e}")
            import traceback

            logger.debug(traceback.format_exc())
            return False
        finally:
            await self.disconnect()

    async def send_pointer_event(self, x: int, y: int, button_mask: int = 0):
        """发送鼠标指针事件

        Args:
            x: X坐标
            y: Y坐标
            button_mask: 按钮掩码 (0=无按钮, 1=左键, 2=中键, 4=右键, 8=向上滚轮, 16=向下滚轮)
        """
        if not self.websocket:
            logger.error("WebSocket连接未建立")
            return False

        try:
            # 构造鼠标事件消息
            message = struct.pack(
                ">BBHH", RFBProtocol.CLIENT_POINTER_EVENT, button_mask, x, y
            )

            await self.send_binary(message)
            logger.debug(f"发送鼠标事件: ({x},{y}) 按钮掩码={button_mask}")
            return True

        except Exception as e:
            logger.error(f"发送鼠标事件失败: {e}")
            return False

    async def mouse_move(self, x: int, y: int):
        """移动鼠标到指定位置"""
        return await self.send_pointer_event(x, y, 0)

    async def mouse_click(self, x: int, y: int, button: str = "left"):
        """鼠标点击

        Args:
            x: X坐标
            y: Y坐标
            button: 按钮类型 ('left', 'right', 'middle')
        """
        button_map = {
            "left": RFBProtocol.MOUSE_LEFT_BUTTON,
            "right": RFBProtocol.MOUSE_RIGHT_BUTTON,
            "middle": RFBProtocol.MOUSE_MIDDLE_BUTTON,
        }

        if button not in button_map:
            logger.error(f"不支持的鼠标按钮: {button}")
            return False

        button_mask = button_map[button]

        try:
            # 按下按钮
            await self.send_pointer_event(x, y, button_mask)
            await asyncio.sleep(0.05)  # 短暂延迟

            # 释放按钮
            await self.send_pointer_event(x, y, 0)

            logger.info(f"鼠标{button}键点击: ({x},{y})")
            return True

        except Exception as e:
            logger.error(f"鼠标点击失败: {e}")
            return False

    async def mouse_double_click(self, x: int, y: int, button: str = "left"):
        """鼠标双击"""
        success1 = await self.mouse_click(x, y, button)
        await asyncio.sleep(0.1)
        success2 = await self.mouse_click(x, y, button)

        if success1 and success2:
            logger.info(f"鼠标{button}键双击: ({x},{y})")
            return True
        return False

    async def mouse_drag(
        self,
        start_x: int,
        start_y: int,
        end_x: int,
        end_y: int,
        button: str = "left",
        steps: int = 10,
    ):
        """鼠标拖拽

        Args:
            start_x, start_y: 起始坐标
            end_x, end_y: 结束坐标
            button: 按钮类型
            steps: 拖拽步数
        """
        button_map = {
            "left": RFBProtocol.MOUSE_LEFT_BUTTON,
            "right": RFBProtocol.MOUSE_RIGHT_BUTTON,
            "middle": RFBProtocol.MOUSE_MIDDLE_BUTTON,
        }

        if button not in button_map:
            logger.error(f"不支持的鼠标按钮: {button}")
            return False

        button_mask = button_map[button]

        try:
            # 移动到起始位置并按下按钮
            await self.send_pointer_event(start_x, start_y, button_mask)
            await asyncio.sleep(0.05)

            # 分步拖拽到目标位置
            for i in range(1, steps + 1):
                x = start_x + (end_x - start_x) * i // steps
                y = start_y + (end_y - start_y) * i // steps
                await self.send_pointer_event(x, y, button_mask)
                await asyncio.sleep(0.02)

            # 释放按钮
            await self.send_pointer_event(end_x, end_y, 0)

            logger.info(f"鼠标拖拽: ({start_x},{start_y}) -> ({end_x},{end_y})")
            return True

        except Exception as e:
            logger.error(f"鼠标拖拽失败: {e}")
            return False

    async def mouse_scroll(self, x: int, y: int, direction: str = "up", steps: int = 1):
        """鼠标滚轮

        Args:
            x, y: 滚轮位置
            direction: 滚动方向 ('up', 'down')
            steps: 滚动步数
        """
        if direction == "up":
            button_mask = RFBProtocol.MOUSE_SCROLL_UP
        elif direction == "down":
            button_mask = RFBProtocol.MOUSE_SCROLL_DOWN
        else:
            logger.error(f"不支持的滚动方向: {direction}")
            return False

        try:
            for _ in range(steps):
                # 滚轮事件：按下然后立即释放
                await self.send_pointer_event(x, y, button_mask)
                await asyncio.sleep(0.02)
                await self.send_pointer_event(x, y, 0)
                await asyncio.sleep(0.02)

            logger.info(f"鼠标滚轮{direction}: ({x},{y}) 步数={steps}")
            return True

        except Exception as e:
            logger.error(f"鼠标滚轮失败: {e}")
            return False


# 简单测试代码
async def test_novnc_connection():
    """测试noVNC连接"""
    logger.info("开始测试noVNC连接...")

    client = NoVNCClient(host="localhost", port=6080, path="/websockify")

    try:
        success = await client.run_session(duration=5)
        if success:
            logger.info("测试成功完成！")
        else:
            logger.error("测试失败")
        return success
    except Exception as e:
        logger.error(f"测试过程中发生错误: {e}")
        import traceback

        logger.debug(traceback.format_exc())
        return False


async def test_screenshot():
    """测试截图功能"""
    logger.info("开始测试截图功能...")

    client = NoVNCClient(host="localhost", port=6080, path="/websockify")

    if not await client.connect():
        logger.error("连接失败")
        return False

    try:
        if not await client.rfb_handshake():
            logger.error("RFB握手失败")
            return False

        # 请求帧缓冲区更新并等待数据
        await client.request_framebuffer_update(incremental=False)
        logger.info("已请求帧缓冲区更新，等待数据...")

        # 处理几轮消息以获取屏幕数据
        for i in range(10):
            if not await client.handle_server_message():
                break
            await asyncio.sleep(0.1)

        # 尝试保存截图
        screenshot_filename = "novnc_screenshot.png"
        if await client.save_screenshot(screenshot_filename):
            logger.info(f"✅ 截图保存成功: {screenshot_filename}")
            return True
        else:
            logger.error("❌ 截图保存失败")
            return False

    except Exception as e:
        logger.error(f"截图测试失败: {e}")
        import traceback

        logger.debug(traceback.format_exc())
        return False
    finally:
        await client.disconnect()


async def test_mouse_operations():
    """测试鼠标操作功能"""
    logger.info("开始测试鼠标操作功能...")

    client = NoVNCClient(host="localhost", port=6080, path="/websockify")

    if not await client.connect():
        logger.error("连接失败")
        return False

    try:
        if not await client.rfb_handshake():
            logger.error("RFB握手失败")
            return False

        logger.info("✅ 连接和握手成功，开始鼠标测试...")

        # 获取屏幕中心位置
        center_x = client.width // 2
        center_y = client.height // 2

        logger.info(f"屏幕尺寸: {client.width}x{client.height}")
        logger.info(f"测试位置（屏幕中心）: ({center_x}, {center_y})")

        # 测试1: 鼠标移动
        logger.info("🖱️ 测试鼠标移动...")
        await client.mouse_move(center_x, center_y)
        await asyncio.sleep(1)

        # 测试2: 左键点击
        logger.info("🖱️ 测试左键点击...")
        await client.mouse_click(center_x, center_y, "left")
        await asyncio.sleep(1)

        # 测试3: 右键点击
        logger.info("🖱️ 测试右键点击...")
        await client.mouse_click(center_x + 50, center_y, "right")
        await asyncio.sleep(1)

        # 测试4: 双击
        logger.info("🖱️ 测试双击...")
        await client.mouse_double_click(center_x - 50, center_y, "left")
        await asyncio.sleep(1)

        # 测试5: 拖拽
        logger.info("🖱️ 测试拖拽...")
        await client.mouse_drag(
            center_x - 100, center_y - 100, center_x + 100, center_y + 100, "left", 20
        )
        await asyncio.sleep(1)

        # 测试6: 滚轮
        logger.info("🖱️ 测试滚轮...")
        await client.mouse_scroll(center_x, center_y, "up", 3)
        await asyncio.sleep(0.5)
        await client.mouse_scroll(center_x, center_y, "down", 3)
        await asyncio.sleep(1)

        # 请求帧缓冲区更新以获取可能的变化
        logger.info("📸 请求屏幕更新以验证操作结果...")
        await client.request_framebuffer_update(incremental=False)

        # 处理几轮消息以获取屏幕数据
        for i in range(10):
            if not await client.handle_server_message():
                break
            await asyncio.sleep(0.1)

        # 保存测试后的截图
        test_screenshot_filename = "mouse_test_screenshot.png"
        if await client.save_screenshot(test_screenshot_filename):
            logger.info(f"✅ 鼠标测试后截图保存成功: {test_screenshot_filename}")

        logger.info("✅ 鼠标操作测试完成！")
        logger.info("验证方法:")
        logger.info("1. 检查截图中是否有鼠标操作的痕迹")
        logger.info("2. 如果桌面有应用程序，可以观察是否有窗口被点击或移动")
        logger.info("3. 右键点击可能会显示上下文菜单")

        return True

    except Exception as e:
        logger.error(f"鼠标操作测试失败: {e}")
        import traceback

        logger.debug(traceback.format_exc())
        return False
    finally:
        await client.disconnect()


if __name__ == "__main__":
    # 运行测试
    print("noVNC WebSocket + RFB 协议客户端")
    print("=" * 50)

    try:
        # 先测试基本连接
        print("🔗 测试基本连接...")
        basic_result = asyncio.run(test_novnc_connection())

        if basic_result:
            print("✅ 基本连接测试成功！")

            # 测试截图功能
            print("\n📸 测试截图功能...")
            screenshot_result = asyncio.run(test_screenshot())

            if screenshot_result:
                print("✅ 截图功能测试成功！")

                # 测试鼠标操作功能
                print("\n🖱️ 测试鼠标操作功能...")
                mouse_result = asyncio.run(test_mouse_operations())

                if mouse_result:
                    print("✅ 鼠标操作功能测试成功！")
                    print("\n🎉 所有测试完成！可以使用以下功能:")
                    print("1. 基本VNC连接和RFB协议通信")
                    print("2. 不限时间运行 (设置duration=None)")
                    print("3. 屏幕截图功能 (调用save_screenshot())")
                    print("4. 完整的鼠标操作支持:")
                    print("   - mouse_move(x, y) - 移动鼠标")
                    print("   - mouse_click(x, y, button) - 点击 (left/right/middle)")
                    print("   - mouse_double_click(x, y, button) - 双击")
                    print(
                        "   - mouse_drag(start_x, start_y, end_x, end_y, button) - 拖拽"
                    )
                    print("   - mouse_scroll(x, y, direction, steps) - 滚轮 (up/down)")
                else:
                    print("❌ 鼠标操作功能测试失败！")
            else:
                print("❌ 截图功能测试失败！")
        else:
            print("❌ 基本连接测试失败！")

    except KeyboardInterrupt:
        print("\n测试被用户中断")
    except Exception as e:
        print(f"测试失败: {e}")
