"""飞书通道实现（Stream 模式）使用官方 lark_oapi SDK"""

import json
import logging
import os
import threading
import time

import lark_oapi as lark
from lark_oapi.api.im.v1 import P2ImMessageReceiveV1

from ..base import Channel

logger = logging.getLogger("agent")


class FeishuStreamChannel(Channel):
    """飞书机器人长连接通道（Stream 模式）"""

    def __init__(
        self,
        app_id: str,
        app_secret: str,
        agent=None,
    ):
        """
        初始化飞书通道

        Args:
            app_id: 飞书应用 ID
            app_secret: 飞书应用密钥
            agent: Agent 实例（用于处理消息）
        """
        self._app_id = app_id
        self._app_secret = app_secret
        self._agent = agent
        self._client = None
        self._ws_client = None
        self._running = False

        # 消息去重配置：使用 SQLite 持久化存储
        # 5层dirname: channel.py -> feishu -> channels -> agent -> src -> 项目根目录
        project_root = os.path.dirname(os.path.dirname(os.path.dirname(os.path.dirname(os.path.dirname(os.path.abspath(__file__))))))
        data_dir = os.path.join(project_root, "db", "sqlite")
        self._dedup_db_path = os.path.join(data_dir, "feishu_dedup.db")
        self._dedup_duration = 300  # 5分钟
        self._init_dedup_db()

    def set_agent(self, agent):
        """设置 Agent 实例"""
        self._agent = agent

    def _init_dedup_db(self):
        """初始化去重数据库"""
        import sqlite3
        os.makedirs(os.path.dirname(self._dedup_db_path), exist_ok=True)
        with sqlite3.connect(self._dedup_db_path) as conn:
            conn.execute("""
                CREATE TABLE IF NOT EXISTS processed_messages (
                    message_id TEXT PRIMARY KEY,
                    processed_at REAL
                )
            """)
            conn.commit()
        logger.info(f"去重数据库初始化完成: {self._dedup_db_path}")

    def _is_message_processed(self, message_id: str) -> bool:
        """检查消息是否已处理"""
        import sqlite3
        current_time = time.time()

        # 清理过期记录
        with sqlite3.connect(self._dedup_db_path) as conn:
            conn.execute(
                "DELETE FROM processed_messages WHERE processed_at < ?",
                (current_time - self._dedup_duration,)
            )
            conn.commit()

            # 检查消息是否已存在
            cursor = conn.execute(
                "SELECT 1 FROM processed_messages WHERE message_id = ?",
                (message_id,)
            )
            return cursor.fetchone() is not None

    def _mark_message_processed(self, message_id: str):
        """标记消息已处理"""
        import sqlite3
        with sqlite3.connect(self._dedup_db_path) as conn:
            conn.execute(
                "INSERT OR REPLACE INTO processed_messages (message_id, processed_at) VALUES (?, ?)",
                (message_id, time.time())
            )
            conn.commit()

    def _handle_message(self, data: P2ImMessageReceiveV1):
        """处理接收到的消息事件"""
        try:
            # 获取事件头信息，过滤非消息事件
            header = getattr(data, 'header', None)
            if header:
                event_type = getattr(header, 'event_type', None)
                # 只处理消息接收事件
                if event_type != 'im.message.receive_v1':
                    logger.debug(f"跳过非消息事件: {event_type}")
                    return

            # lark-oapi SDK v1.5+ 结构: data.event.message
            # event 是一个 P2ImMessageReceiveV1Data 对象
            event = getattr(data, 'event', None)
            if not event:
                logger.error(f"无法获取事件对象, data: {data}")
                return

            message = getattr(event, 'message', None)
            if not message:
                logger.error(f"无法获取消息对象, event: {event}")
                return

            # 获取发送者信息
            sender = getattr(event, 'sender', None)
            sender_id = getattr(sender, 'sender_id', None) if sender else None

            msg_type = message.message_type
            chat_id = message.chat_id
            chat_type = message.chat_type
            content = message.content
            message_id = message.message_id

            # 去重：使用 SQLite 检查是否已处理
            if self._is_message_processed(message_id):
                logger.warning(f"消息 {message_id} 已处理过，跳过")
                return
            self._mark_message_processed(message_id)

            # 根据 chat_type 决定接收者 ID 类型
            # p2p（私聊）: 使用 open_id
            # group（群聊）: 使用 chat_id
            if chat_type == "p2p" and sender_id:
                receive_id = getattr(sender_id, 'open_id', None)
                receive_id_type = "open_id"
            else:
                receive_id = chat_id
                receive_id_type = "chat_id"

            logger.info(f"chat_type={chat_type}, receive_id={receive_id}, receive_id_type={receive_id_type}")

            user_message = ""
            if msg_type == "text":
                try:
                    content_obj = json.loads(content)
                    user_message = content_obj.get("text", "").strip()
                except Exception:
                    user_message = content.strip()

            if not user_message:
                logger.warning("无法解析消息内容")
                return

            # 获取发送者 open_id（用于私聊会话隔离）
            sender_open_id = getattr(sender_id, 'open_id', None) if sender_id else None

            # 构建上下文
            context = {
                'source': 'feishu',
                'user_id': sender_open_id if chat_type == 'p2p' else None,
                'chat_id': chat_id if chat_type == 'group' else None,
            }

            logger.info(f"收到消息: {user_message[:50]}...")

            # 使用 Agent 统一处理 /new 等指令
            response = self._agent.process_command(user_message, context)
            if response:
                self._send_message(message_id, response)
                return

            # 获取或创建带有正确会话的 Agent
            session_id = self._agent.get_or_create_session(
                source='feishu',
                user_id=sender_open_id if chat_type == 'p2p' else None,
                chat_id=chat_id if chat_type == 'group' else None,
            )
            if session_id:
                self._agent._session_id = session_id

            # 先发送收到消息的确认
            self._send_message(message_id, "👍 收到消息，正在思考...")

            if self._agent:
                # 使用 process_with_thinking 获取思考过程
                result = self._agent.process_with_thinking(user_message)
                response = result.get("response", "")
                thinking = result.get("thinking", [])

                import re

                # 按原始顺序发送思考过程（保持顺序正确）
                current_section = None
                section_content = []

                for step in thinking:
                    # 判断当前步骤的类型
                    if step.startswith("🔧 调用工具:") or step.startswith("   输入:"):
                        section = "tool_call"
                    elif step.startswith("   →"):
                        section = "tool_result"
                    else:
                        section = "thinking"

                    # 如果换 section 了，先发送之前的
                    if current_section and current_section != section:
                        if section_content:
                            if current_section == "tool_call":
                                self._send_message(message_id, "<b>🔧 工具调用</b>\n" + "\n".join(section_content))
                            elif current_section == "tool_result":
                                self._send_message(message_id, "<b>🔧 工具结果</b>\n" + "\n".join(section_content))
                            elif current_section == "thinking":
                                for s in section_content:
                                    self._send_message(message_id, f"<b>💭 思考</b>\n{s}")
                            section_content = []

                    current_section = section
                    section_content.append(step)

                # 发送最后一个 section
                if current_section and section_content:
                    if current_section == "tool_call":
                        self._send_message(message_id, "<b>🔧 工具调用</b>\n" + "\n".join(section_content))
                    elif current_section == "tool_result":
                        self._send_message(message_id, "<b>🔧 工具结果</b>\n" + "\n".join(section_content))
                    elif current_section == "thinking":
                        for s in section_content:
                            self._send_message(message_id, f"<b>💭 思考</b>\n{s}")

                # 最后发送最终响应
                response_text = re.sub(r'\*\*(.*?)\*\*', r'<b>\1</b>', response)
                self._send_message(message_id, response_text)

                # 保存会话信息
                if self._agent.memory:
                    self._agent.memory.save(**context)
            else:
                logger.warning("Agent 未设置")

        except Exception as e:
            logger.error(f"处理消息错误: {e}", exc_info=True)

    def _do_p2_im_message_receive_v1(self, data: P2ImMessageReceiveV1) -> None:
        """消息接收事件处理"""
        logger.debug(f"收到消息事件: {data}")
        self._handle_message(data)

    def _get_agent_for_session(self, session_id: str):
        """获取指定会话的 Agent

        如果当前 agent 的 session_id 与请求的不同，则创建一个新的 agent
        """
        if not self._agent:
            return None

        # 检查当前 agent 是否匹配
        if self._agent.session_id == session_id:
            return self._agent

        # 需要创建新的 agent
        from src.core.agent import Agent

        logger.info(f"切换会话: {self._agent.session_id[:8]}... -> {session_id[:8]}...")

        new_agent = Agent(
            tools=self._agent._tools,
            llm_client=self._agent._llm_client,
            max_iterations=self._agent._max_iterations,
            show_thinking=self._agent._show_thinking,
            session_id=session_id,
            enable_memory=self._agent._enable_memory,
            enable_mcp=False,  # 不重复加载 MCP 工具
        )
        # 加载已有记忆
        if new_agent._memory:
            new_agent._memory.load(session_id)

        return new_agent

    def _send_message(self, message_id: str, content: str):
        """回复消息 - 使用 text 类型"""
        # 直接使用 text 类型，避免 post 类型的格式兼容问题
        # text 类型已经能正确发送消息
        msg_type = "text"

        try:
            # 移除 HTML 标签（text 类型不支持富文本）
            import re
            clean_content = re.sub(r'<[^>]+>', '', content)

            body = lark.im.v1.ReplyMessageRequestBody.builder() \
                .msg_type(msg_type) \
                .content(json.dumps({"text": clean_content}, ensure_ascii=False)) \
                .build()

            # 构建请求
            request = lark.im.v1.ReplyMessageRequest.builder() \
                .message_id(message_id) \
                .request_body(body) \
                .build()

            response = self._client.im.v1.message.reply(request)

            if response.success():
                logger.info("消息发送成功（text 类型）")
            else:
                logger.error(f"发送消息失败: {response.msg}")

        except Exception as e:
            logger.error(f"发送消息异常: {e}", exc_info=True)

    def _create_ws_client(self):
        """创建 WebSocket 客户端"""
        # 构建事件处理器
        event_handler = lark.EventDispatcherHandler.builder("", "") \
            .register_p2_im_message_receive_v1(self._do_p2_im_message_receive_v1) \
            .build()

        # 创建 WS 客户端
        self._ws_client = lark.ws.Client(
            self._app_id,
            self._app_secret,
            event_handler=event_handler,
            log_level=lark.LogLevel.WARNING
        )

    def _create_client(self):
        """创建 API 客户端"""
        self._client = lark.Client.builder() \
            .app_id(self._app_id) \
            .app_secret(self._app_secret) \
            .build()

    def start(self):
        """启动长连接"""
        logger.info("启动飞书 WebSocket 连接...")

        # 创建客户端
        self._create_client()
        self._create_ws_client()

        logger.info("连接飞书 WebSocket...")

        # 启动 WebSocket 连接（阻塞）
        self._running = True
        self._ws_client.start()

    def run(self, agent):
        """运行飞书通道（阻塞）"""
        self._agent = agent
        self.start()

    def start_background(self, agent):
        """后台启动飞书通道（不阻塞）"""
        self._agent = agent
        thread = threading.Thread(target=self.start, daemon=True)
        thread.start()
        logger.info("飞书通道已在后台启动")
        return thread

    def send(self, message: str) -> None:
        """发送消息（需要指定接收者）"""
        raise NotImplementedError("请使用 _send_message 方法指定接收者")

    def stop(self):
        """停止连接"""
        self._running = False
        if self._ws_client:
            logger.info("正在关闭飞书 WebSocket 连接...")
