from typing import List, Dict
from datetime import datetime
import time

from langchain_core.prompts import PromptTemplate,ChatPromptTemplate,SystemMessagePromptTemplate,MessagesPlaceholder,HumanMessagePromptTemplate
from langchain.tools.render import  render_text_description_and_args
from langchain_core.output_parsers import JsonOutputParser as JSONOutputParser
from langchain_core.tools import BaseTool
from ..utils.logger import get_logger

PICKER_SYSTEM_PROMPT = """
你是一个智能工具选择助手,你需要根据用户的问题选择最合适的工具,并提取出工具所需的参数。

工作流程:
1. 分析用户问题,确定所需工具
2. 提取并整理工具所需的参数
3. 返回工具名称和参数

请遵循以下规则:
- 工具名称必须从工具列表中选择: {{tool_names}}
- 返回格式:
    ```json
    {{
        "tool": "工具名称", 
        "params": {{"参数1": "值1", "参数2": "值2"}}
    }}
    ```

工具列表详情:
{tools}

""" 

PICKER_HUMAN_PROMPT = """
用户的问题是:{input}
"""

class ToolPicker:
    def __init__(self, llm, tools: List):
        self.tools = tools
        self.llm = llm
        self.logger = get_logger("ToolPicker")
        
        date_now = datetime.now().strftime("%Y-%m-%d")
        picker_human = f"今天是{date_now}\n\n{PICKER_HUMAN_PROMPT}"
        prompt = ChatPromptTemplate.from_messages([
            SystemMessagePromptTemplate.from_template(PICKER_SYSTEM_PROMPT),
            MessagesPlaceholder(variable_name="chat_history", optional=True),
            HumanMessagePromptTemplate.from_template(picker_human)
        ])
        prompt = prompt.partial(tools=render_text_description_and_args(tools))

        self.chain = prompt | self.llm | JSONOutputParser()

    def pick(self, input: str):
        self.logger.info(f"Received input: {input}")
        try:
            result = self.chain.invoke({"input": input})
            self.logger.info(f"Selected tool: {result['tool']} with params: {result['params']}")
            return result
        except Exception as e:
            self.logger.error(f"Error picking tool: {str(e)}")
            raise



RUNNER_SYSTEM_PROMPT_V1 = """
你是一个擅长根据工具执行结果回答用户问题的助手。

工作流程:
1. 对获取的数据进行简要的分析和解读
2. 结合数据对用户问题进行回答

注意:
- 不要展示原数据,只展示分析和解读后的结果
- 不要提到工具调用
"""

# "这一版的问答效果相对来说比较好" -- wukai
RUNNER_SYSTEM_PROMPT_V0 = """
你是一个擅长根据工具执行结果回答用户问题的助手。

工作流程:
1. 分析用户的问题
2. 根据用户的问题,解读工具执行结果,进行简要的分析说明
3. 返回用户问题的答案

请遵循以下规则:
- 工具执行结果中的数据必须使用 markdown 表格展示
- 确保数据的完整性, 不要遗漏数据
- 表格中的数据只能来源于工具执行结果
"""


RUNNER_HUMAN_PROMPT = """
用户的问题是:{input}
工具的执行结果是:{result}
"""


class ToolRunner:
    def __init__(self, llm, tools: Dict[str, BaseTool],version: str = "v1"):
        self.tools = tools
        self.llm = llm
        self.logger = get_logger("ToolRunner")
        self.version = version
        system_prompt = RUNNER_SYSTEM_PROMPT_V1
        if version != "v1":
            system_prompt = RUNNER_SYSTEM_PROMPT_V0
        prompt = ChatPromptTemplate.from_messages([
            SystemMessagePromptTemplate.from_template(system_prompt),
            HumanMessagePromptTemplate.from_template(RUNNER_HUMAN_PROMPT)
        ])
        self.chain = prompt | self.llm 

    def run(self, input: str, tool_name: str, params: Dict):
        start_time = time.time()
        self.logger.info(f"开始执行工具 '{tool_name}',参数: {params}")
        
        if tool_name not in self.tools:
            self.logger.error(f"工具 {tool_name} 未找到")
            raise ValueError(f"Tool {tool_name} not found")
            
        try:
            # 工具执行
            tool_start = time.time()
            tool = self.tools[tool_name]
            self.logger.info(f"调用工具 {tool_name}")
            result = tool.invoke(params)
            tool_time = time.time() - tool_start
            self.logger.info(f"工具执行完成,耗时: {tool_time:.2f}秒")
            self.logger.debug(f"工具执行结果: {result}")
            
            # 提取 markdown 表格
            table = ""
            if "markdown" in result:
                table = result["markdown"]
                del result["markdown"]
            
            # LLM 解释结果
            llm_start = time.time()
            self.logger.info("开始 LLM 结果解释")
            llm_result = self.chain.invoke({"input": input, "result": result})
            llm_time = time.time() - llm_start
            self.logger.info(f"LLM 解释完成,耗时: {llm_time:.2f}秒")
            
            # 组装响应
            response = {
                "output": llm_result.content,
                "table": table
            }
            
            total_time = time.time() - start_time
            self.logger.info(f"工具执行完成,总耗时: {total_time:.2f}秒,其中工具执行: {tool_time:.2f}秒,LLM解释: {llm_time:.2f}秒")
            
            # 记录性能指标
            self.logger.info(
                "性能指标 - "
                f"总耗时: {total_time:.2f}秒, "
                f"工具执行: {tool_time:.2f}秒 ({(tool_time/total_time)*100:.1f}%), "
                f"LLM解释: {llm_time:.2f}秒 ({(llm_time/total_time)*100:.1f}%)"
            )
            
            return response
            
        except Exception as e:
            error_time = time.time() - start_time
            self.logger.error(f"工具执行失败,耗时: {error_time:.2f}秒,错误: {str(e)}", exc_info=True)
            raise