from typing import List
from langchain_core.prompts import ChatPromptTemplate
from langchain_core.output_parsers import JsonOutputParser
from langchain_core.exceptions import OutputParserException

from typing import List, Dict, Any, TypedDict, Annotated, Optional
from langchain_core.language_models import BaseChatModel
from pydantic import BaseModel, Field


class IntentionResult(BaseModel):
    """
    意图分类结果模型，标准化返回意图索引和分类原因
    适配 LangChain 结构化输出、JSON 解析器，支持自动类型校验
    """
    # 意图分类索引ID：对应intents列表的下标，兜底时为fallback_index（默认-1）
    classification_id: int = Field(
        ...,
        description="意图分类的索引ID，匹配输入intents列表的下标，兜底值通常为-1",
        gt=-2  # 简单校验：索引ID最小为-1（避免无效负数，可根据业务调整）
    )

    reason: str = Field(
        ...,
        description="意图分类的依据说明，异常场景下为具体错误信息",
        min_length=1  # 简单校验：不可为空字符串
    )

DEFAULT_INTENT_PROMPT_TEMPLATE = """
你是专业的意图分类助手，需严格按照以下规则处理：
1. 从给定的选项中为用户输入匹配唯一的意图，返回对应的索引ID（fallback_index={fallback_index} 为兜底选项，仅当无匹配时使用）
2. 必须以 **纯JSON格式** 输出，字段为 classification_id（int类型）和 reason（str类型），无其他多余文本、注释
3. reason 需简洁说明分类依据，不超过50字

可用意图选项：
{intents}
"""

def execute_intent_classification(
    query: str, 
    intents: List[str], 
    model: BaseChatModel,
    fallback_index: int = -1
) -> IntentionResult:
    """
    核心业务逻辑：执行意图分类（适配所有支持JSON输出的大模型）。
    """
    if not intents:
        return IntentionResult(classification_id=fallback_index, reason='input intent list is empty')

    parser = JsonOutputParser(pydantic_object=IntentionResult)

    formatted_intents = "\n".join([f"选项{i}: {intent}" for i, intent in enumerate(intents)])
    prompt = ChatPromptTemplate.from_template(DEFAULT_INTENT_PROMPT_TEMPLATE)
    full_prompt = prompt.format_prompt(
        fallback_index=fallback_index,
        intents=formatted_intents
    )

    user_prompt = f"### 用户输入\n{query}\n\n{parser.get_format_instructions()}"

    try:
        # 显式指定 response_format={"type": "json_object"}，强制模型返回JSON
        response = model.invoke(
            [
                ("system", full_prompt.to_string()),
                ("user", user_prompt)
            ],
            response_format={"type": "json_object"}
        )
        result_dict = parser.parse(response.content)
        return IntentionResult(**result_dict)
    except OutputParserException as e:
        error_msg = f"JSON解析失败，模型输出非标准格式：{str(e)}"
        import sys
        sys.stderr.write(f"Error during classification: {error_msg}\n")
        return IntentionResult(classification_id=fallback_index, reason=error_msg)
    except Exception as e:
        error_msg = f"分类过程中发生错误：{str(e)}"
        import sys
        sys.stderr.write(f"Error during classification: {error_msg}\n")
        return IntentionResult(classification_id=fallback_index, reason=error_msg)


# def inner_test():
#     from alayaflow.component.chat_model import mk_chat_model_deepseek
#     model = mk_chat_model_deepseek()
#     query = "你好"
#     intents = ["问候", "查询"]
#     result = execute_intent_classification(query, intents, model)
#     print(result)

# if __name__ == "__main__":
#     inner_test()