"""RFB 协议相关常量和处理函数"""

import struct
from typing import Tuple
from .types import PixelFormat, ServerInfo, Rectangle
from .exceptions import ProtocolError


class RFBProtocol:
    """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
    MOUSE_MIDDLE_BUTTON = 2
    MOUSE_RIGHT_BUTTON = 4
    MOUSE_SCROLL_UP = 8
    MOUSE_SCROLL_DOWN = 16

    # 编码类型
    ENCODING_RAW = 0
    ENCODING_COPYRECT = 1
    ENCODING_RRE = 2
    ENCODING_HEXTILE = 5
    ENCODING_TRLE = 15
    ENCODING_ZRLE = 16

    # 键盘常量 (VNC Key Symbols)
    KEY_BACKSPACE = 0xFF08
    KEY_TAB = 0xFF09
    KEY_RETURN = 0xFF0D
    KEY_ESCAPE = 0xFF1B
    KEY_DELETE = 0xFFFF
    KEY_HOME = 0xFF50
    KEY_LEFT = 0xFF51
    KEY_UP = 0xFF52
    KEY_RIGHT = 0xFF53
    KEY_DOWN = 0xFF54
    KEY_PAGE_UP = 0xFF55
    KEY_PAGE_DOWN = 0xFF56
    KEY_END = 0xFF57
    KEY_INSERT = 0xFF63
    KEY_F1 = 0xFFBE
    KEY_F2 = 0xFFBF
    KEY_F3 = 0xFFC0
    KEY_F4 = 0xFFC1
    KEY_F5 = 0xFFC2
    KEY_F6 = 0xFFC3
    KEY_F7 = 0xFFC4
    KEY_F8 = 0xFFC5
    KEY_F9 = 0xFFC6
    KEY_F10 = 0xFFC7
    KEY_F11 = 0xFFC8
    KEY_F12 = 0xFFC9
    KEY_SHIFT_L = 0xFFE1
    KEY_SHIFT_R = 0xFFE2
    KEY_CTRL_L = 0xFFE3
    KEY_CTRL_R = 0xFFE4
    KEY_ALT_L = 0xFFE9
    KEY_ALT_R = 0xFFEA
    KEY_WIN_L = 0xFFEB
    KEY_WIN_R = 0xFFEC


def parse_server_version(data: bytes) -> str:
    """解析服务器版本"""
    if not data.startswith(b"RFB "):
        raise ProtocolError(f"无效的 RFB 版本: {data}")
    return data.decode().strip()


def parse_security_types(data: bytes) -> list[int]:
    """解析可用的安全类型"""
    if not data or len(data) < 1:
        raise ProtocolError("无效的安全类型数据")

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

    if len(data) < 1 + count:
        raise ProtocolError("安全类型数据不完整")

    return list(data[1 : 1 + count])


def parse_server_init(data: bytes) -> ServerInfo:
    """解析服务器初始化消息"""
    if not data or len(data) < 24:
        raise ProtocolError(f"服务器初始化消息太短: {len(data) if data else 0}")

    # 解析基本信息
    width = struct.unpack(">H", data[0:2])[0]
    height = struct.unpack(">H", data[2:4])[0]

    # 解析像素格式
    pixel_data = data[4:20]
    pixel_format = PixelFormat(
        bits_per_pixel=pixel_data[0],
        depth=pixel_data[1],
        big_endian=bool(pixel_data[2]),
        true_colour=bool(pixel_data[3]),
        red_max=struct.unpack(">H", pixel_data[4:6])[0],
        green_max=struct.unpack(">H", pixel_data[6:8])[0],
        blue_max=struct.unpack(">H", pixel_data[8:10])[0],
        red_shift=pixel_data[10],
        green_shift=pixel_data[11],
        blue_shift=pixel_data[12],
    )

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

    return ServerInfo(
        width=width, height=height, pixel_format=pixel_format, server_name=server_name
    )


def create_framebuffer_update_request(
    incremental: bool, x: int = 0, y: int = 0, width: int = 0, height: int = 0
) -> bytes:
    """创建帧缓冲区更新请求消息"""
    return struct.pack(
        ">BBHHHH",
        RFBProtocol.CLIENT_FRAMEBUFFER_UPDATE_REQUEST,
        1 if incremental else 0,
        x,
        y,
        width,
        height,
    )


def create_pointer_event(x: int, y: int, button_mask: int) -> bytes:
    """创建鼠标指针事件消息"""
    return struct.pack(">BBHH", RFBProtocol.CLIENT_POINTER_EVENT, button_mask, x, y)


def create_key_event(key: int, down: bool) -> bytes:
    """创建键盘事件消息"""
    return struct.pack(
        ">BBBBI",
        RFBProtocol.CLIENT_KEY_EVENT,
        1 if down else 0,
        0,
        0,  # padding
        key,
    )


def parse_framebuffer_update_header(data: bytes) -> Tuple[int, list[Rectangle]]:
    """解析帧缓冲区更新消息头部"""
    if len(data) < 4:
        raise ProtocolError("帧缓冲区更新头部数据不足")

    # 消息类型(1) + padding(1) + 矩形数量(2)
    rect_count = struct.unpack(">H", data[2:4])[0]

    rectangles = []
    offset = 4

    for _ in range(rect_count):
        if len(data) < offset + 12:
            break  # 数据不足，可能需要继续接收

        # 解析矩形: x(2) + y(2) + width(2) + height(2) + encoding(4)
        x, y, width, height, encoding = struct.unpack(
            ">HHHHI", data[offset : offset + 12]
        )
        rectangles.append(Rectangle(x, y, width, height, encoding))
        offset += 12

    return rect_count, rectangles


def get_mouse_button_mask(button: str) -> int:
    """获取鼠标按钮掩码"""
    button_map = {
        "left": RFBProtocol.MOUSE_LEFT_BUTTON,
        "right": RFBProtocol.MOUSE_RIGHT_BUTTON,
        "middle": RFBProtocol.MOUSE_MIDDLE_BUTTON,
    }
    return button_map.get(button, 0)


def get_scroll_button_mask(direction: str) -> int:
    """获取滚轮按钮掩码"""
    scroll_map = {
        "up": RFBProtocol.MOUSE_SCROLL_UP,
        "down": RFBProtocol.MOUSE_SCROLL_DOWN,
    }
    return scroll_map.get(direction, 0)


def char_to_keysym(char: str) -> int:
    """将字符转换为 VNC 键码

    将单个字符转换为对应的 VNC 键码（KeySym）。支持 ASCII 字符和常见的特殊字符。

    Args:
        char: 单个字符，支持的字符类型：
            - ASCII 可打印字符 (32-126)：空格、字母、数字、标点符号
            - 特殊控制字符：换行符、制表符、退格符、删除符、ESC

    Returns:
        int: 对应的 VNC 键码 (KeySym)
            - ASCII 字符：直接返回 ASCII 码值
            - 特殊字符：返回对应的 VNC 键码常量

    Raises:
        ValueError: 如果输入不是单个字符或不支持的字符

    Examples:
        >>> char_to_keysym('a')        # 97 (ASCII 'a')
        >>> char_to_keysym('A')        # 65 (ASCII 'A')
        >>> char_to_keysym(' ')        # 32 (空格)
        >>> char_to_keysym('1')        # 49 (ASCII '1')
        >>> char_to_keysym('!')        # 33 (ASCII '!')
        >>> char_to_keysym('\\n')      # 0xFF0D (VNC 回车键)
        >>> char_to_keysym('\\t')      # 0xFF09 (VNC Tab 键)

    Note:
        - 支持的特殊字符：
          - '\\n' (换行) → KEY_RETURN (0xFF0D)
          - '\\r' (回车) → KEY_RETURN (0xFF0D)
          - '\\t' (制表) → KEY_TAB (0xFF09)
          - '\\b' (退格) → KEY_BACKSPACE (0xFF08)
          - '\\x1b' (ESC) → KEY_ESCAPE (0xFF1B)
          - '\\x7f' (DEL) → KEY_DELETE (0xFFFF)
    """
    if len(char) != 1:
        raise ValueError("只支持单个字符")

    code = ord(char)

    # ASCII 可打印字符直接返回 (空格到波浪号)
    if 32 <= code <= 126:
        return code

    # 特殊字符映射表
    special_chars = {
        "\n": RFBProtocol.KEY_RETURN,  # 换行符 → 回车键
        "\r": RFBProtocol.KEY_RETURN,  # 回车符 → 回车键
        "\t": RFBProtocol.KEY_TAB,  # 制表符 → Tab 键
        "\b": RFBProtocol.KEY_BACKSPACE,  # 退格符 → 退格键
        "\x1b": RFBProtocol.KEY_ESCAPE,  # ESC 字符 → ESC 键
        "\x7f": RFBProtocol.KEY_DELETE,  # DEL 字符 → Delete 键
    }

    return special_chars.get(char, code)


def get_special_key(key_name: str) -> int:
    """获取特殊按键的 VNC 键码

    根据按键名称获取对应的 VNC 键码（KeySym）。支持导航键、功能键、修饰键等。

    Args:
        key_name: 按键名称（不区分大小写），支持的按键类型：
            - 编辑键：backspace, tab, return, enter, escape, delete, insert
            - 导航键：home, end, left, up, right, down, page_up, page_down
            - 功能键：f1, f2, f3, f4, f5, f6, f7, f8, f9, f10, f11, f12
            - 修饰键：shift, shift_l, shift_r, ctrl, ctrl_l, ctrl_r, alt, alt_l, alt_r
            - 系统键：win, win_l, win_r, windows, super

    Returns:
        int: 对应的 VNC 键码 (KeySym)

    Raises:
        ValueError: 如果按键名称不被支持

    Examples:
        >>> get_special_key('enter')        # 0xFF0D (回车键)
        >>> get_special_key('ENTER')        # 0xFF0D (不区分大小写)
        >>> get_special_key('f1')           # 0xFFBE (F1 键)
        >>> get_special_key('ctrl')         # 0xFFE3 (左 Ctrl 键)
        >>> get_special_key('ctrl_l')       # 0xFFE3 (左 Ctrl 键)
        >>> get_special_key('ctrl_r')       # 0xFFE4 (右 Ctrl 键)
        >>> get_special_key('left')         # 0xFF51 (左箭头键)
        >>> get_special_key('page_up')      # 0xFF55 (Page Up 键)
        >>> get_special_key('win')          # 0xFFEB (Windows 键)

    Note:
        按键名称映射表：

        编辑键：
        - 'backspace' → KEY_BACKSPACE (0xFF08)
        - 'tab' → KEY_TAB (0xFF09)
        - 'return', 'enter' → KEY_RETURN (0xFF0D)
        - 'escape' → KEY_ESCAPE (0xFF1B)
        - 'delete' → KEY_DELETE (0xFFFF)
        - 'insert' → KEY_INSERT (0xFF63)

        导航键：
        - 'home' → KEY_HOME (0xFF50)
        - 'end' → KEY_END (0xFF57)
        - 'left' → KEY_LEFT (0xFF51)
        - 'up' → KEY_UP (0xFF52)
        - 'right' → KEY_RIGHT (0xFF53)
        - 'down' → KEY_DOWN (0xFF54)
        - 'page_up' → KEY_PAGE_UP (0xFF55)
        - 'page_down' → KEY_PAGE_DOWN (0xFF56)

        功能键：
        - 'f1' → KEY_F1 (0xFFBE)
        - 'f2' → KEY_F2 (0xFFBF)
        - ... (f1-f12 按顺序递增)

        修饰键：
        - 'shift', 'shift_l' → KEY_SHIFT_L (0xFFE1)
        - 'shift_r' → KEY_SHIFT_R (0xFFE2)
        - 'ctrl', 'ctrl_l' → KEY_CTRL_L (0xFFE3)
        - 'ctrl_r' → KEY_CTRL_R (0xFFE4)
        - 'alt', 'alt_l' → KEY_ALT_L (0xFFE9)
        - 'alt_r' → KEY_ALT_R (0xFFEA)
        - 'win', 'win_l', 'windows', 'super' → KEY_WIN_L (0xFFEB)
        - 'win_r' → KEY_WIN_R (0xFFEC)
    """
    key_map = {
        # 编辑键
        "backspace": RFBProtocol.KEY_BACKSPACE,
        "tab": RFBProtocol.KEY_TAB,
        "return": RFBProtocol.KEY_RETURN,
        "enter": RFBProtocol.KEY_RETURN,
        "escape": RFBProtocol.KEY_ESCAPE,
        "delete": RFBProtocol.KEY_DELETE,
        "insert": RFBProtocol.KEY_INSERT,
        # 导航键
        "home": RFBProtocol.KEY_HOME,
        "end": RFBProtocol.KEY_END,
        "left": RFBProtocol.KEY_LEFT,
        "up": RFBProtocol.KEY_UP,
        "right": RFBProtocol.KEY_RIGHT,
        "down": RFBProtocol.KEY_DOWN,
        "page_up": RFBProtocol.KEY_PAGE_UP,
        "page_down": RFBProtocol.KEY_PAGE_DOWN,
        # 功能键
        "f1": RFBProtocol.KEY_F1,
        "f2": RFBProtocol.KEY_F2,
        "f3": RFBProtocol.KEY_F3,
        "f4": RFBProtocol.KEY_F4,
        "f5": RFBProtocol.KEY_F5,
        "f6": RFBProtocol.KEY_F6,
        "f7": RFBProtocol.KEY_F7,
        "f8": RFBProtocol.KEY_F8,
        "f9": RFBProtocol.KEY_F9,
        "f10": RFBProtocol.KEY_F10,
        "f11": RFBProtocol.KEY_F11,
        "f12": RFBProtocol.KEY_F12,
        # 修饰键
        "shift": RFBProtocol.KEY_SHIFT_L,
        "shift_l": RFBProtocol.KEY_SHIFT_L,
        "shift_r": RFBProtocol.KEY_SHIFT_R,
        "ctrl": RFBProtocol.KEY_CTRL_L,
        "ctrl_l": RFBProtocol.KEY_CTRL_L,
        "ctrl_r": RFBProtocol.KEY_CTRL_R,
        "alt": RFBProtocol.KEY_ALT_L,
        "alt_l": RFBProtocol.KEY_ALT_L,
        "alt_r": RFBProtocol.KEY_ALT_R,
        # 系统键
        "win": RFBProtocol.KEY_WIN_L,
        "win_l": RFBProtocol.KEY_WIN_L,
        "win_r": RFBProtocol.KEY_WIN_R,
        "windows": RFBProtocol.KEY_WIN_L,
        "super": RFBProtocol.KEY_WIN_L,
    }

    key_name_lower = key_name.lower()
    if key_name_lower not in key_map:
        raise ValueError(f"不支持的按键: {key_name}")

    return key_map[key_name_lower]
