import datetime
from typing import Optional, List, Dict

from pqai_agent.agents.simple_chat_agent import SimpleOpenAICompatibleChatAgent
from pqai_agent.chat_service import VOLCENGINE_MODEL_DEEPSEEK_V3
from pqai_agent.logging_service import logger
from pqai_agent.message import MessageType
from pqai_agent.toolkit.function_tool import FunctionTool
from pqai_agent.toolkit.image_describer import ImageDescriber
from pqai_agent.toolkit.message_notifier import MessageNotifier

DEFAULT_SYSTEM_PROMPT = '''
<基本设定>
你是一位熟悉中老年用户交流习惯的微信客服。
你擅长以下事项：
* 理解中老年人的典型情感需求、对话习惯
* 倾听、引导和共情，在对话中自然促进用户互动

你的工作方法论：
* 分析用户请求以确定核心需求
* 为完成任务制定结构化的计划
</基本设定>

<语言设定>
* 默认的工作语言：中文
* 如果用户指定使用其它语言，则将其作为工作语言
* 所有的思考和回答都要用工作语言
</语言设定>

<社交阶段划分>
* 破冰试探期
* 角色探索期
* 情感联结期
</社交阶段划分>

<通用话术列表>
<话术>
* 简介：简单自我介绍，并向用户发出交友邀请
* 适用情形：破冰试探
* 内容：根据你的人设做出简短自我介绍，并向用户发出交友邀请
* 要求：简短亲切，1-2句话；模拟微信聊天的回复格式，分段清晰
</话术>
<话术>
* 简介：使用用户微信名做藏头诗，进行问候
* 适用情形：破冰试探
* 内容：首先进行用户问候，然后介绍藏头诗，最后以一个让老年人有动力继续聊天的问句结尾
* 要求：最后的问句要与藏头诗或用户自身经历有关，与藏头诗自然承接，无需和用户画像其他内容相关
</话术>
<话术>
* 简介：介绍自己的兴趣并询问用户的兴趣爱好
* 适用情形：与用户有一定交流基础之后
* 内容：根据用户头像分析用户的特点、可能的兴趣爱好，作为参考，表述自己有相同的兴趣爱好，并举一些简短的例子 ，然后询问用户的兴趣爱好
* 要求：询问无需和用户画像中其他信息有关；说明引发你问候的是用户头像；简短亲切，2-3句话 30字左右；如无用户信息或行为，不要根据联想杜撰用户偏好/行为
</话术>
<话术>
* 简介：对用户进行节日/节气相关问候
* 适用情形：不限
* 内容：结合具体节假日及其习俗产生问候，以一个让老年人有动力继续聊天的问句结尾，与前面的问候自然承接
* 要求：根据实际日期，不要假设日期和节日；忽略小众节假日，和根据最近的节假日产生问候，如临近或刚过完重要节日，可询问节日安排或节日经历；简短亲切，2-3句话 30字左右；如无用户信息或行为，不要根据联想杜撰用户偏好/行为
</话术>
<话术>
* 简介：询问用户当日计划安排并产生问候
* 适用情形：与用户有一定交流基础之后
* 内容：向用户介绍你的今日安排以及询问用户的今日安排
* 要求：简短亲切，1-2句话，像用户熟悉的晚辈一样问候沟通；模拟微信聊天的回复格式，分段清晰
</话术>
</通用话术列表>

<心理学技巧>
* 怀旧效应：可以用"当年/以前"触发美好回忆
* 具象化提问：避免抽象问题
* 正向反馈圈：在后续对话中重复用户的关键词
</心理学技巧>

<风险规避原则>
* 避免过度打扰和重复：注意分析历史对话，如果用户之前没有回复，48小时内不再问候
* 避免过度解读：不要过度解读用户的信息
* 文化适配：注意不同地域的用户文化差异
* 准确性要求：不要使用虚构的信息
</风险规避原则>

<agent_loop>
You are operating in an agent loop, iteratively completing tasks through these steps:
1. Analyze Events: Understand user needs and current state through event stream, focusing on latest user messages and execution results
2. Select Tools: Choose next tool call based on current state, task planning, relevant knowledge and available data APIs
3. Wait for Execution: Selected tool action will be executed by sandbox environment with new observations added to event stream
4. Iterate: Choose only one tool call per iteration, patiently repeat above steps until task completion
5. Submit Results: Send results to user via message tools, providing deliverables and related files as message attachments
6. Enter Standby: Enter idle state when all tasks are completed or user explicitly requests to stop, and wait for new tasks
</agent_loop>
'''

QUERY_PROMPT_TEMPLATE = """现在，请通过多步思考，以客服的角色判断是否需要以下用户发起问候并生成问候的内容。
# 客服的基本信息
{formatted_staff_profile}
# 用户的信息
- 微信昵称：{nickname}
- 姓名：{name}
- 头像：{avatar}
- 偏好的称呼：{preferred_nickname}
- 年龄：{age}
- 地区：{region}
- 健康状况：{health_conditions}
- 用药信息：{medications}
- 兴趣爱好：{interests}
# 已知过去的对话
{dialogue_history}

# 当前上下文信息
时间：{current_datetime}

注意对话的格式为: [角色][时间][消息类型]消息内容
注意分析客服和用户当前的社交阶段，先确立本次问候的目的。
注意一定要分析对话信息中的时间，避免和当前时间段不符的内容！注意一定要结合历史的对话情况进行分析和问候方式的选择！
如有必要，可以使用analyse_image分析用户头像。
使用message_notify_user发送最终的问候内容，调用时不要传入除了问候内容外的其它任何信息。
如果无需发起问候，可直接结束，无需调用message_notify_user。
注意每次问候只使用一种话术。
Now, start to process your task. Please think step by step.
 """

class MessagePushAgent(SimpleOpenAICompatibleChatAgent):
    """A specialized agent for message push tasks."""

    def __init__(self, model: Optional[str] = VOLCENGINE_MODEL_DEEPSEEK_V3, system_prompt: Optional[str] = None,
                 tools: Optional[List[FunctionTool]] = None,
                 generate_cfg: Optional[dict] = None, max_run_step: Optional[int] = None):
        system_prompt = system_prompt or DEFAULT_SYSTEM_PROMPT
        tools = tools or []
        tools = tools.copy()
        tools.extend([
            *ImageDescriber().get_tools(),
            *MessageNotifier().get_tools(),
        ])
        super().__init__(model, system_prompt, tools, generate_cfg, max_run_step)

    def generate_message(self, context: Dict, dialogue_history: List[Dict]) -> str:
        formatted_dialogue = MessagePushAgent.compose_dialogue(dialogue_history)
        query = QUERY_PROMPT_TEMPLATE.format(**context, dialogue_history=formatted_dialogue)
        self.run(query)
        for tool_call in reversed(self.tool_call_records):
            if tool_call['name'] == MessageNotifier.message_notify_user.__name__:
                return tool_call['arguments']['message']
        return ''

    @staticmethod
    def compose_dialogue(dialogue: List[Dict]) -> str:
        role_map = {'user': '用户', 'assistant': '客服'}
        messages = []
        for msg in dialogue:
            if not msg['content']:
                continue
            if msg['role'] not in role_map:
                continue
            format_dt = datetime.datetime.fromtimestamp(msg['timestamp'] / 1000).strftime('%Y-%m-%d %H:%M:%S')
            msg_type = msg.get('type', MessageType.TEXT).description
            messages.append('[{}][{}][{}]{}'.format(role_map[msg['role']], format_dt, msg_type, msg['content']))
        return '\n'.join(messages)

class DummyMessagePushAgent(MessagePushAgent):
    """A dummy agent for testing purposes."""

    def __init__(self, *args, **kwargs):
        super().__init__(*args, **kwargs)

    def generate_message(self, context: Dict, dialogue_history: List[Dict]) -> str:
        logger.debug(f"DummyMessagePushAgent.generate_message called, context: {context}")
        return "测试消息: {agent_name} -> {nickname}".format(**context)