"""
飞书消息处理客户端
基于 OpenClaw 项目的飞书集成代码整理

依赖安装:
    pip install lark-oapi websocket-client requests

使用示例:
    client = FeishuClient(app_id="cli_xxx", app_secret="xxx")

    # 发送消息
    client.send_message(to="ou_xxx", text="Hello!")

    # 监听消息
    client.start_websocket(on_message=my_handler)
"""

import json
import io
import logging
import os
import tempfile
import threading
from dataclasses import dataclass, field
from enum import Enum
from typing import Any, Callable, Dict, List, Optional, Union

import lark_oapi as lark
import requests
from lark_oapi.api.contact.v3 import GetUserRequest, GetUserResponse
from lark_oapi.api.im.v1 import (
    CreateMessageRequest, CreateMessageRequestBody,
    ReplyMessageRequest, ReplyMessageRequestBody,
    GetMessageRequest, GetMessageResponse,
    PatchMessageRequest, PatchMessageRequestBody,
    CreateImageRequest, CreateImageRequestBody,
    GetImageRequest,
    CreateFileRequest, CreateFileRequestBody,
    GetMessageResourceRequest, GetMessageResourceResponse,
    ListMessageRequest, ListMessageResponse
)

logging.basicConfig(level=logging.INFO)
logger = logging.getLogger(__name__)


class FeishuDomain(Enum):
    """飞书域名"""
    FEISHU = "https://open.feishu.cn"      # 中国版
    LARK = "https://open.larksuite.com"    # 国际版


class ChatType(Enum):
    """聊天类型"""
    P2P = "p2p"      # 私聊
    GROUP = "group"  # 群聊


class ReceiveIdType(Enum):
    """接收者ID类型"""
    OPEN_ID = "open_id"
    USER_ID = "user_id"
    UNION_ID = "union_id"
    EMAIL = "email"
    CHAT_ID = "chat_id"


@dataclass
class FeishuMessageEvent:
    """飞书消息事件"""
    message_id: str
    chat_id: str
    chat_type: ChatType
    content: str
    content_type: str  # text, image, file, post, etc.
    sender_open_id: str
    sender_user_id: Optional[str] = None
    sender_name: Optional[str] = None
    root_id: Optional[str] = None      # 根消息ID（话题）
    parent_id: Optional[str] = None    # 父消息ID（回复）
    mentions: List[Dict] = field(default_factory=list)
    mentioned_bot: bool = False


@dataclass
class SendResult:
    """发送结果"""
    message_id: str
    chat_id: str


class FeishuClient:
    """
    飞书客户端

    功能:
    - 发送/接收消息
    - 上传/下载媒体文件
    - WebSocket 实时监听
    """

    def __init__(
        self,
        app_id: str,
        app_secret: str,
        domain: FeishuDomain = FeishuDomain.FEISHU,
        encrypt_key: Optional[str] = None,
        verification_token: Optional[str] = None,
    ):
        """
        初始化飞书客户端

        Args:
            app_id: 飞书应用 App ID
            app_secret: 飞书应用 App Secret
            domain: 飞书域名 (FEISHU 或 LARK)
            encrypt_key: 事件加密密钥 (可选)
            verification_token: 事件验证令牌 (可选)
        """
        self.app_id = app_id
        self.app_secret = app_secret
        self.domain = domain
        self.encrypt_key = encrypt_key
        self.verification_token = verification_token

        # 创建 Lark 客户端
        self.client = lark.Client.builder() \
            .app_id(app_id) \
            .app_secret(app_secret) \
            .domain(domain.value) \
            .build()

        # 缓存
        self._bot_open_id: Optional[str] = None
        self._sender_name_cache: Dict[str, str] = {}

    # ==================== 消息发送 ====================

    def send_message(
        self,
        to: str,
        text: str,
        reply_to_message_id: Optional[str] = None,
        receive_id_type: Optional[ReceiveIdType] = None,
    ) -> SendResult:
        """
        发送文本消息

        Args:
            to: 接收者ID (open_id, user_id, chat_id 等)
            text: 消息文本
            reply_to_message_id: 回复的消息ID (可选)
            receive_id_type: 接收者ID类型 (可选，自动推断)

        Returns:
            SendResult: 发送结果
        """
        if receive_id_type is None:
            receive_id_type = self._resolve_receive_id_type(to)

        # 构建富文本消息 (支持 Markdown)
        content = json.dumps({
            "zh_cn": {
                "content": [[{"tag": "md", "text": text}]]
            }
        })

        if reply_to_message_id:
            # 回复消息
            request = ReplyMessageRequest.builder() \
                .message_id(reply_to_message_id) \
                .request_body(ReplyMessageRequestBody.builder()
                    .content(content)
                    .msg_type("post")
                    .build()) \
                .build()

            response = self.client.im.v1.message.reply(request)
        else:
            # 新消息
            request = CreateMessageRequest.builder() \
                .receive_id_type(receive_id_type.value) \
                .request_body(CreateMessageRequestBody.builder()
                    .receive_id(to)
                    .content(content)
                    .msg_type("post")
                    .build()) \
                .build()

            response = self.client.im.v1.message.create(request)

        if not response.success():
            raise Exception(f"发送消息失败: {response.msg} (code: {response.code})")

        return SendResult(
            message_id=response.data.message_id,
            chat_id=response.data.chat_id
        )

    def send_card(
        self,
        to: str,
        card: Dict[str, Any],
        reply_to_message_id: Optional[str] = None,
        receive_id_type: Optional[ReceiveIdType] = None,
    ) -> SendResult:
        """
        发送卡片消息 (交互式消息)

        Args:
            to: 接收者ID
            card: 卡片内容 (JSON 结构)
            reply_to_message_id: 回复的消息ID (可选)
            receive_id_type: 接收者ID类型 (可选)

        Returns:
            SendResult: 发送结果
        """
        if receive_id_type is None:
            receive_id_type = self._resolve_receive_id_type(to)

        content = json.dumps(card)

        if reply_to_message_id:
            request = ReplyMessageRequest.builder() \
                .message_id(reply_to_message_id) \
                .request_body(ReplyMessageRequestBody.builder()
                    .content(content)
                    .msg_type("interactive")
                    .build()) \
                .build()

            response = self.client.im.v1.message.reply(request)
        else:
            request = CreateMessageRequest.builder() \
                .receive_id_type(receive_id_type.value) \
                .request_body(CreateMessageRequestBody.builder()
                    .receive_id(to)
                    .content(content)
                    .msg_type("interactive")
                    .build()) \
                .build()

            response = self.client.im.v1.message.create(request)

        if not response.success():
            raise Exception(f"发送卡片失败: {response.msg}")

        return SendResult(
            message_id=response.data.message_id,
            chat_id=response.data.chat_id
        )

    def send_markdown_card(
        self,
        to: str,
        text: str,
        reply_to_message_id: Optional[str] = None,
    ) -> SendResult:
        """
        发送 Markdown 卡片 (更好的格式渲染)

        Args:
            to: 接收者ID
            text: Markdown 文本
            reply_to_message_id: 回复的消息ID (可选)

        Returns:
            SendResult: 发送结果
        """
        card = {
            "config": {"wide_screen_mode": True},
            "elements": [{"tag": "markdown", "content": text}]
        }
        return self.send_card(to, card, reply_to_message_id)

    # ==================== 媒体处理 ====================

    def upload_image(
            self,
            image: Union[bytes, str],
            image_type: str = "message"
    ) -> str:
        """
        上传图片
        """
        file_obj = None

        try:
            # 1. 准备文件对象
            if isinstance(image, str):
                # 如果是路径，直接打开
                file_obj = open(image, "rb")
            else:
                # 如果是二进制数据，使用内存文件 (避免写磁盘)
                file_obj = io.BytesIO(image)
                # 某些 SDK/API 依赖文件名来判断 Content-Type，我们手动给一个名字
                # 如果知道真实格式更好，不知道则默认 .png 或 .bin
                file_obj.name = "upload.png"

                # 2. 构建请求
            # 注意：这里直接传入 file_obj
            request = CreateImageRequest.builder() \
                .request_body(CreateImageRequestBody.builder()
                              .image_type(image_type)
                              .image(file_obj)
                              .build()) \
                .build()

            # 3. 发起请求
            response = self.client.im.v1.image.create(request)

            if not response.success():
                raise Exception(f"上传图片失败: {response.msg}")

            return response.data.image_key

        finally:
            # 4. 显式关闭文件句柄
            if file_obj and not isinstance(file_obj, io.BytesIO):
                file_obj.close()

    def download_image(self, image_key: str) -> bytes:
        """
        下载图片

        Args:
            image_key: 图片 key

        Returns:
            bytes: 图片数据
        """
        request = GetImageRequest.builder() \
            .image_key(image_key) \
            .build()

        response = self.client.im.v1.image.get(request)

        if not response.success():
            raise Exception(f"下载图片失败: {response.msg}")

        return response.file.read()

    def send_image(
        self,
        to: str,
        image: Union[bytes, str],
        reply_to_message_id: Optional[str] = None,
    ) -> SendResult:
        """
        发送图片消息

        Args:
            to: 接收者ID
            image: 图片数据或文件路径
            reply_to_message_id: 回复的消息ID (可选)

        Returns:
            SendResult: 发送结果
        """
        image_key = self.upload_image(image)
        content = json.dumps({"image_key": image_key})

        receive_id_type = self._resolve_receive_id_type(to)

        if reply_to_message_id:
            request = ReplyMessageRequest.builder() \
                .message_id(reply_to_message_id) \
                .request_body(ReplyMessageRequestBody.builder()
                    .content(content)
                    .msg_type("image")
                    .build()) \
                .build()

            response = self.client.im.v1.message.reply(request)
        else:
            request = CreateMessageRequest.builder() \
                .receive_id_type(receive_id_type.value) \
                .request_body(CreateMessageRequestBody.builder()
                    .receive_id(to)
                    .content(content)
                    .msg_type("image")
                    .build()) \
                .build()

            response = self.client.im.v1.message.create(request)

        if not response.success():
            raise Exception(f"发送图片失败: {response.msg}")

        return SendResult(
            message_id=response.data.message_id,
            chat_id=response.data.chat_id
        )

    def upload_file(
        self,
        file: Union[bytes, str],
        file_name: str,
        file_type: str = "stream",
    ) -> str:
        """
        上传文件

        Args:
            file: 文件数据或路径
            file_name: 文件名
            file_type: 文件类型 (opus/mp4/pdf/doc/xls/ppt/stream)

        Returns:
            str: file_key
        """
        if isinstance(file, str):
            with open(file, "rb") as f:
                file_data = f.read()
            if not file_name:
                file_name = os.path.basename(file)
        else:
            file_data = file

        with tempfile.NamedTemporaryFile(delete=False) as tmp:
            tmp.write(file_data)
            tmp_path = tmp.name

        try:
            request = CreateFileRequest.builder() \
                .request_body(CreateFileRequestBody.builder()
                    .file_type(file_type)
                    .file_name(file_name)
                    .file(open(tmp_path, "rb"))
                    .build()) \
                .build()

            response = self.client.im.v1.file.create(request)

            if not response.success():
                raise Exception(f"上传文件失败: {response.msg}")

            return response.data.file_key
        finally:
            os.unlink(tmp_path)

    def send_file(
        self,
        to: str,
        file: Union[bytes, str],
        file_name: str,
        reply_to_message_id: Optional[str] = None,
    ) -> SendResult:
        """
        发送文件消息

        Args:
            to: 接收者ID
            file: 文件数据或路径
            file_name: 文件名
            reply_to_message_id: 回复的消息ID (可选)

        Returns:
            SendResult: 发送结果
        """
        file_type = self._detect_file_type(file_name)
        file_key = self.upload_file(file, file_name, file_type)
        content = json.dumps({"file_key": file_key})

        receive_id_type = self._resolve_receive_id_type(to)

        if reply_to_message_id:
            request = ReplyMessageRequest.builder() \
                .message_id(reply_to_message_id) \
                .request_body(ReplyMessageRequestBody.builder()
                    .content(content)
                    .msg_type("file")
                    .build()) \
                .build()

            response = self.client.im.v1.message.reply(request)
        else:
            request = CreateMessageRequest.builder() \
                .receive_id_type(receive_id_type.value) \
                .request_body(CreateMessageRequestBody.builder()
                    .receive_id(to)
                    .content(content)
                    .msg_type("file")
                    .build()) \
                .build()

            response = self.client.im.v1.message.create(request)

        if not response.success():
            raise Exception(f"发送文件失败: {response.msg}")

        return SendResult(
            message_id=response.data.message_id,
            chat_id=response.data.chat_id
        )

    def download_message_resource(
        self,
        message_id: str,
        file_key: str,
        resource_type: str = "file"
    ) -> bytes:
        """
        下载消息中的资源文件

        Args:
            message_id: 消息ID
            file_key: 文件 key
            resource_type: 资源类型 ("image" 或 "file")

        Returns:
            bytes: 文件数据
        """
        request = GetMessageResourceRequest.builder() \
            .message_id(message_id) \
            .file_key(file_key) \
            .type(resource_type) \
            .build()

        response = self.client.im.v1.message_resource.get(request)

        if not response.success():
            raise Exception(f"下载资源失败: {response.msg}")

        return response.file.read()

    # ==================== 消息获取 ====================

    def get_message(self, message_id: str) -> Optional[Dict]:
        """
        获取消息详情

        Args:
            message_id: 消息ID

        Returns:
            Dict: 消息详情，失败返回 None
        """
        request = GetMessageRequest.builder() \
            .message_id(message_id) \
            .build()

        response = self.client.im.v1.message.get(request)

        if not response.success():
            return None

        items = response.data.items
        if not items:
            return None

        item = items[0]
        content = item.body.content if item.body else ""

        # 解析文本内容
        try:
            parsed = json.loads(content)
            if item.msg_type == "text" and "text" in parsed:
                content = parsed["text"]
        except:
            pass

        return {
            "message_id": item.message_id,
            "chat_id": item.chat_id,
            "sender_id": item.sender.id if item.sender else None,
            "sender_type": item.sender.sender_type if item.sender else None,
            "content": content,
            "content_type": item.msg_type,
            "create_time": item.create_time,
        }

    def get_message_list(self, chat_id: str, start_time: Optional[Union[str, int]] = None, end_time: Optional[Union[str, int]] = None, page_size: int = 20, page_token: Optional[str] = None) -> Optional[Dict]:
        """
        获取消息列表

        Args:
            chat_id: 会话 ID
            start_time: 起始时间 (可选)
            end_time: 结束时间 (可选)
            page_size: 分页大小 (默认 20)
            page_token: 分页令牌 (可选)

        Returns:
            Dict: 包含消息列表和分页信息，失败返回 None
        """
        builder = ListMessageRequest.builder() \
            .container_id_type("chat") \
            .container_id(chat_id) \
            .sort_type("ByCreateTimeDesc") \
            .page_size(page_size)

        if start_time is not None:
            builder.start_time(str(start_time))
        if end_time is not None:
            builder.end_time(str(end_time))
        if page_token:
            builder.page_token(page_token)

        request = builder.build()

        # 发起请求
        response: ListMessageResponse = self.client.im.v1.message.list(request)

        # 处理失败返回
        if not response.success():
            logger.error(
                f"client.im.v1.message.list failed, code: {response.code}, msg: {response.msg}, log_id: {response.get_log_id()}")
            return None

        # 构建返回结果
        messages = []
        if response.data.items:
            for item in response.data.items:
                content = item.body.content if item.body else ""
                # 解析文本内容
                try:
                    parsed = json.loads(content)
                    if item.msg_type == "text" and "text" in parsed:
                        content = parsed["text"]
                except:
                    pass

                messages.append({
                    "message_id": item.message_id,
                    "chat_id": item.chat_id,
                    "sender_id": item.sender.id if item.sender else None,
                    "sender_type": item.sender.sender_type if item.sender else None,
                    "content": content,
                    "content_type": item.msg_type,
                    "create_time": item.create_time,
                    "mentions": item.mentions if hasattr(item, 'mentions') else [],
                })

        return {
            "items": messages,
            "page_token": response.data.page_token,
            "has_more": response.data.has_more
        }

    # ==================== 用户信息 ====================

    def get_user_info(self, open_id: str) -> Optional[Dict]:
        """
        获取用户信息

        Args:
            open_id: 用户 open_id

        Returns:
            Dict: 用户信息，失败返回 None
        """
        # 检查缓存
        if open_id in self._sender_name_cache:
            return {"name": self._sender_name_cache[open_id]}

        request = GetUserRequest.builder() \
            .user_id(open_id) \
            .user_id_type("open_id") \
            .build()

        response = self.client.contact.v3.user.get(request)

        if not response.success():
            return None

        user = response.data.user
        name = user.name or user.en_name or user.nickname

        if name:
            self._sender_name_cache[open_id] = name

        return {
            "open_id": user.open_id,
            "user_id": user.user_id,
            "name": name,
            "en_name": user.en_name,
            "nickname": user.nickname,
            "email": user.email,
            "mobile": user.mobile,
            "avatar": user.avatar.avatar_origin if user.avatar else None,
        }

    # ==================== WebSocket 监听 ====================

    def start_websocket(
        self,
        on_message: Callable[[FeishuMessageEvent], None],
        on_bot_added: Optional[Callable[[str], None]] = None,
        on_bot_removed: Optional[Callable[[str], None]] = None,
        blocking: bool = True,
    ):
        """
        启动 WebSocket 监听消息

        Args:
            on_message: 消息回调函数
            on_bot_added: 机器人被添加到群的回调 (可选)
            on_bot_removed: 机器人被移出群的回调 (可选)
            blocking: 是否阻塞当前线程
        """
        # 创建事件处理器
        # 注意: lark-oapi SDK 的回调函数只接受一个参数 (data)
        event_handler = lark.EventDispatcherHandler.builder(
            self.encrypt_key or "",
            self.verification_token or ""
        ).register_p2_im_message_receive_v1(
            lambda data: self._handle_message_event(data, on_message)
        )

        if on_bot_added:
            event_handler = event_handler.register_p2_im_chat_member_bot_added_v1(
                lambda data: on_bot_added(data.event.chat_id)
            )

        if on_bot_removed:
            event_handler = event_handler.register_p2_im_chat_member_bot_deleted_v1(
                lambda data: on_bot_removed(data.event.chat_id)
            )

        handler = event_handler.build()

        # 创建 WebSocket 客户端
        ws_client = lark.ws.Client(
            self.app_id,
            self.app_secret,
            event_handler=handler,
            domain=lark.FEISHU_DOMAIN if self.domain == FeishuDomain.FEISHU else lark.LARK_DOMAIN,
            log_level=lark.LogLevel.INFO,
        )

        logger.info("启动飞书 WebSocket 监听...")

        if blocking:
            ws_client.start()
        else:
            thread = threading.Thread(target=ws_client.start, daemon=True)
            thread.start()
            return thread

    def _handle_message_event(
        self,
        data,
        callback: Callable[[FeishuMessageEvent], None]
    ):
        """处理消息事件"""
        try:
            # data 结构: P2ImMessageReceiveV1 对象
            # data.event 包含实际的事件数据
            event = data.event
            msg = event.message
            sender = event.sender

            # 解析消息内容
            content = self._parse_message_content(msg.content, msg.message_type)

            # 检查是否 @了机器人
            mentioned_bot = self._check_bot_mentioned(msg.mentions)

            # 去除 @机器人 的文本
            if msg.mentions:
                content = self._strip_bot_mention(content, msg.mentions)

            # 构建事件对象
            message_event = FeishuMessageEvent(
                message_id=msg.message_id,
                chat_id=msg.chat_id,
                chat_type=ChatType(msg.chat_type),
                content=content,
                content_type=msg.message_type,
                sender_open_id=sender.sender_id.open_id if sender.sender_id else "",
                sender_user_id=sender.sender_id.user_id if sender.sender_id else None,
                root_id=msg.root_id,
                parent_id=msg.parent_id,
                mentions=[],  # 简化处理
                mentioned_bot=mentioned_bot,
            )

            # 尝试获取发送者名称 (可能会失败，不影响主流程)
            try:
                if message_event.sender_open_id:
                    user_info = self.get_user_info(message_event.sender_open_id)
                    if user_info:
                        message_event.sender_name = user_info.get("name")
            except Exception as e:
                logger.debug(f"获取用户信息失败: {e}")

            callback(message_event)

        except Exception as e:
            logger.error(f"处理消息事件失败: {e}", exc_info=True)

    # ==================== 辅助方法 ====================

    def _resolve_receive_id_type(self, receive_id: str) -> ReceiveIdType:
        """推断接收者ID类型"""
        if receive_id.startswith("ou_"):
            return ReceiveIdType.OPEN_ID
        elif receive_id.startswith("on_"):
            return ReceiveIdType.UNION_ID
        elif receive_id.startswith("oc_"):
            return ReceiveIdType.CHAT_ID
        elif "@" in receive_id:
            return ReceiveIdType.EMAIL
        else:
            return ReceiveIdType.USER_ID

    def _parse_message_content(self, content: str, message_type: str) -> str:
        """解析消息内容"""
        try:
            parsed = json.loads(content)
            if message_type == "text":
                return parsed.get("text", "")
            elif message_type == "post":
                return self._parse_post_content(parsed)
            return content
        except:
            return content

    def _parse_post_content(self, parsed: Dict) -> str:
        """解析富文本消息"""
        title = parsed.get("title", "")
        content_blocks = parsed.get("content", [])

        text_parts = [title] if title else []

        for paragraph in content_blocks:
            if isinstance(paragraph, list):
                for element in paragraph:
                    if element.get("tag") == "text":
                        text_parts.append(element.get("text", ""))
                    elif element.get("tag") == "a":
                        text_parts.append(element.get("text", element.get("href", "")))
                    elif element.get("tag") == "at":
                        text_parts.append(f"@{element.get('user_name', '')}")

        return "\n".join(text_parts).strip() or "[富文本消息]"

    def _check_bot_mentioned(self, mentions: Optional[List]) -> bool:
        """检查是否 @了机器人"""
        if not mentions:
            return False

        if not self._bot_open_id:
            try:
                self._load_bot_open_id()
            except Exception:
                logger.exception("获取机器人 open_id 失败，拒绝处理群聊 mention")
                return False

        return any(m.id.open_id == self._bot_open_id for m in mentions)

    def _load_bot_open_id(self) -> str:
        """从飞书查询当前应用机器人的 open_id。"""
        token_response = requests.post(
            f"{self.domain.value}/open-apis/auth/v3/tenant_access_token/internal/",
            json={"app_id": self.app_id, "app_secret": self.app_secret},
            timeout=10,
        )
        token_response.raise_for_status()
        token_payload = token_response.json()
        if int(token_payload.get("code") or 0) != 0:
            raise RuntimeError(
                f"获取 tenant_access_token 失败: {token_payload.get('msg')}"
            )
        tenant_access_token = str(
            token_payload.get("tenant_access_token") or ""
        ).strip()
        if not tenant_access_token:
            raise RuntimeError("飞书未返回 tenant_access_token")

        bot_response = requests.get(
            f"{self.domain.value}/open-apis/bot/v3/info",
            headers={"Authorization": f"Bearer {tenant_access_token}"},
            timeout=10,
        )
        bot_response.raise_for_status()
        bot_payload = bot_response.json()
        if int(bot_payload.get("code") or 0) != 0:
            raise RuntimeError(f"获取机器人信息失败: {bot_payload.get('msg')}")
        bot_open_id = str((bot_payload.get("bot") or {}).get("open_id") or "").strip()
        if not bot_open_id:
            raise RuntimeError("飞书机器人信息缺少 open_id")
        self._bot_open_id = bot_open_id
        return bot_open_id

    def _strip_bot_mention(self, text: str, mentions: List) -> str:
        """去除 @机器人 的文本"""
        result = text
        for mention in mentions:
            name = mention.name if hasattr(mention, 'name') else ""
            key = mention.key if hasattr(mention, 'key') else ""
            if name:
                result = result.replace(f"@{name}", "").strip()
            if key:
                result = result.replace(key, "").strip()
        return result

    def _detect_file_type(self, file_name: str) -> str:
        """检测文件类型"""
        ext = os.path.splitext(file_name)[1].lower()
        type_map = {
            ".opus": "opus", ".ogg": "opus",
            ".mp4": "mp4", ".mov": "mp4", ".avi": "mp4",
            ".pdf": "pdf",
            ".doc": "doc", ".docx": "doc",
            ".xls": "xls", ".xlsx": "xls",
            ".ppt": "ppt", ".pptx": "ppt",
        }
        return type_map.get(ext, "stream")


# ==================== 使用示例 ====================

if __name__ == "__main__":
    # 从环境变量获取配置
    APP_ID = os.getenv("FEISHU_APP_ID", "cli_a90fe317987a9cc9")
    APP_SECRET = os.getenv("FEISHU_APP_SECRET", "nn2dWuXTiRA2N6xodbm4g0qz1AfM2ayi")

    if not APP_ID or not APP_SECRET:
        print("请设置环境变量 FEISHU_APP_ID 和 FEISHU_APP_SECRET")
        exit(1)

    # 创建客户端
    client = FeishuClient(
        app_id=APP_ID,
        app_secret=APP_SECRET,
        domain=FeishuDomain.FEISHU,
    )

    # 消息处理回调
    def handle_message(event: FeishuMessageEvent):
        print(f"\n收到消息:")
        print(f"  发送者: {event.sender_name or event.sender_open_id}")
        print(f"  类型: {event.chat_type.value}")
        print(f"  内容: {event.content}")
        print(f"  @机器人: {event.mentioned_bot}")

        # 自动回复示例
        if event.chat_type == ChatType.P2P or event.mentioned_bot:
            # 先回复文字
            reply_text = f"收到你的消息: {event.content}"
            chat_id = event.chat_id
            content = event.content
            content_type = event.content_type # image、text等
            open_id = event.sender_open_id
            client.send_message(
                to=event.chat_id,
                text=reply_text,
                reply_to_message_id=event.message_id
            )
            print(f"  已回复文字: {reply_text}")

            # 再回复一张图片 (读取当前目录下的 hanli.png)
            try:
                image_path = os.path.join(os.path.dirname(__file__) or ".", "hanli.png")
                if os.path.exists(image_path):
                    client.send_image(
                        to=event.chat_id,
                        image=image_path,
                    )
                    print(f"  已回复图片: {image_path}")
                else:
                    print(f"  图片不存在: {image_path}")
            except Exception as e:
                print(f"  回复图片失败: {e}")

    # 启动 WebSocket 监听
    print("启动飞书消息监听...")
    print("按 Ctrl+C 退出")

    try:
        client.start_websocket(
            on_message=handle_message,
            on_bot_added=lambda chat_id: print(f"机器人被添加到群: {chat_id}"),
            on_bot_removed=lambda chat_id: print(f"机器人被移出群: {chat_id}"),
            blocking=True
        )

        # res = client.get_message_list(chat_id='oc_56e85f0e2c97405d176729b62d8f56e5', start_time=0, end_time=1770623620)
        # print(f"获取消息列表结果: {json.dumps(res, indent=4, ensure_ascii=False)}")
    except KeyboardInterrupt:
        print("\n退出")
