from typing import Dict, Any, List
from agent_system.base import BaseAgent
from agent_system.evaluetor.prompt import EvaluatorPrompt
from agent_system.evaluetor.response_model import EvaluatorResult


class Evaluator(BaseAgent):
    """
    评价器Agent
    
    专门用于评价智能医疗系统的多维度评价工具。
    从七个核心维度对智能医生的表现进行全面评价，
    包括当前轮次的表现和结合所有轮次的累积表现。
    
    核心功能:
    1. 临床问诊能力评价
    2. 沟通表达能力评价
    3. 多轮一致性评价
    4. 整体专业性评价
    5. 现病史相似度评价
    6. 既往史相似度评价
    7. 主述相似度评价
    
    Attributes:
        model_type (str): 使用的大语言模型类型，默认为 gpt-oss:latest
        llm_config (dict): LLM模型配置参数
    """
    
    def __init__(self, model_type: str = "gpt-oss:latest", llm_config: dict = None):
        """
        初始化评价器Agent
        
        Args:
            model_type (str): 大语言模型类型，默认使用 gpt-oss:latest
            llm_config (dict): LLM模型的配置参数，如果为None则使用默认配置
        """
        super().__init__(
            model_type=model_type,
            description=EvaluatorPrompt.description,
            instructions=EvaluatorPrompt.instructions,
            response_model=EvaluatorResult,
            llm_config=llm_config or {},
            structured_outputs=True,
            markdown=False,
            use_cache=False
        )
    
    def run(self, patient_case: Dict[str, Any], current_round: int, 
            all_rounds_data: List[Dict[str, Any]], historical_scores: Dict[str, float] = None) -> EvaluatorResult:
        """
        执行评价任务
        
        基于患者病例信息、当前轮次和所有轮次的对话数据（包含历史评分），
        对智能医疗系统进行多维度评价。
        
        Args:
            patient_case (Dict[str, Any]): 患者病例信息
            current_round (int): 当前轮次
            all_rounds_data (List[Dict[str, Any]]): 所有轮次的数据，每个轮次数据包含评分信息
            
        Returns:
            EvaluatorResult: 包含评价结果的结构化数据，包括：
                - clinical_inquiry: 临床问诊能力评价
                - communication_quality: 沟通表达能力评价
                - information_completeness: 信息收集全面性评价
                - overall_professionalism: 整体专业性评价
                - present_illness_similarity: 现病史相似度评价
                - past_history_similarity: 既往史相似度评价
                - chief_complaint_similarity: 主述相似度评价
                - summary: 整体评价总结
                - key_suggestions: 关键改进建议列表
                
        Raises:
            Exception: 当LLM调用失败时，返回包含默认信息的EvaluatorResult
        """
        try:
            # 构建评价提示词
            prompt = self.build_prompt(patient_case, current_round, all_rounds_data, historical_scores)
            
            # 调用基类的run方法执行LLM推理
            result = super().run(prompt)
            
            # 确保返回正确的类型并进行类型转换
            return self._ensure_result_type(result)
            
        except Exception as e:
            # 当评价失败时记录错误并返回默认结果
            print(f"评价执行失败: {str(e)}")
            return self._get_fallback_result()
    
    def build_prompt(self, patient_case: Dict[str, Any], current_round: int, 
                     all_rounds_data: List[Dict[str, Any]], historical_scores: Dict[str, float] = None) -> str:
        """
        构建评价的提示词模板
        
        根据患者病例信息、当前轮次和所有轮次数据（包含历史评分），
        构建简洁高效的评价提示词，引导LLM进行专业的医疗系统评价。
        
        Args:
            patient_case (Dict[str, Any]): 患者病例信息
            current_round (int): 当前轮次
            all_rounds_data (List[Dict[str, Any]]): 所有轮次的数据，包含对话记录和历史评分
            
        Returns:
            str: 精简的评价提示词
        """
        # 格式化患者信息
        patient_info = self._format_patient_info(patient_case)
        
        # 格式化真实病历信息
        true_medical_info = self._format_true_medical_info(patient_case)
        
        # 格式化对话历史
        conversation_history = self._format_conversation_history(all_rounds_data)
        
        # 获取示例输出格式
        example_output = EvaluatorPrompt.get_example_output()
        
        # 格式化历史评分信息
        historical_scores_info = ""
        if historical_scores:
            historical_scores_info = "\n**历史评分信息**:\n"
            for dimension, score in historical_scores.items():
                historical_scores_info += f"- {dimension}: {score}\n"

        prompt = f"""患者病例信息：
{patient_info}

真实病历信息（用于相似度比较）：
{true_medical_info}

对话历史（共{current_round}轮，包含每轮评分）：
{conversation_history}
{historical_scores_info}
请基于对话历史、现病史、既往史、主诉以及上述历史评分，对七个维度进行综合评价，
严格按照JSON格式输出。

输出格式示例：
{example_output}

请严格按照上述JSON格式输出评价结果。"""
        
        return prompt
    
    def _ensure_result_type(self, result: Any) -> EvaluatorResult:
        """
        确保返回结果为正确的类型
        
        Args:
            result (Any): LLM返回的原始结果
            
        Returns:
            EvaluatorResult: 转换后的结构化结果
        """
        if isinstance(result, EvaluatorResult):
            return result
        elif isinstance(result, dict):
            return EvaluatorResult(**result)
        else:
            # 如果类型不匹配，返回默认结果
            return self._get_fallback_result()
    
    def _get_fallback_result(self) -> EvaluatorResult:
        """
        生成评价失败时的默认结果
        
        Returns:
            EvaluatorResult: 包含默认评价信息的结果
        """
        from agent_system.evaluetor.response_model import EvaluationDimension
        
        default_dimension = EvaluationDimension(
            score=0.0, 
            comment="评价失败：系统异常，无法完成评价"
        )
        
        return EvaluatorResult(
            clinical_inquiry=default_dimension,
            communication_quality=default_dimension,
            information_completeness=default_dimension,
            overall_professionalism=default_dimension,
            present_illness_similarity=default_dimension,
            past_history_similarity=default_dimension,
            chief_complaint_similarity=default_dimension,
            summary="评价失败：系统异常，无法完成评价",
            key_suggestions=["系统需要调试和修复"]
        )
    
    def _format_patient_info(self, patient_case: Dict[str, Any]) -> str:
        """格式化患者信息"""
        info_parts = []
        
        # 病案信息
        if '病案介绍' in patient_case:
            case_info = patient_case['病案介绍']
            
            if '基本信息' in case_info:
                info_parts.append(f"**基本信息**: {case_info['基本信息']}")
            
            if '主诉' in case_info:
                info_parts.append(f"**主诉**: {case_info['主诉']}")
            
            if '现病史' in case_info:
                info_parts.append(f"**现病史**: {case_info['现病史']}")
            
            if '既往史' in case_info:
                info_parts.append(f"**既往史**: {case_info['既往史']}")
        
        return '\n'.join(info_parts)
    
    def _format_true_medical_info(self, patient_case: Dict[str, Any]) -> str:
        """格式化真实病历信息，用于相似度比较"""
        info_parts = []
        
        # 病案信息
        if '病案介绍' in patient_case:
            case_info = patient_case['病案介绍']
            
            if '主诉' in case_info:
                info_parts.append(f"**真实主诉**: {case_info['主诉']}")
            
            if '现病史' in case_info:
                info_parts.append(f"**真实现病史**: {case_info['现病史']}")
            
            if '既往史' in case_info:
                info_parts.append(f"**真实既往史**: {case_info['既往史']}")
        
        return '\n'.join(info_parts)
    

    def _format_conversation_history(self, all_rounds_data: List[Dict[str, Any]]) -> str:
        """格式化对话历史，包含每轮的对话记录和评分"""
        history_parts = []
        
        for i, round_data in enumerate(all_rounds_data, 1):
            if i < len(all_rounds_data):
                continue
            history_parts.append(f"### 第{i}轮对话")
            
            if 'patient_response' in round_data:
                history_parts.append(f"**患者回答**: {round_data['patient_response']}")
            
            if 'doctor_inquiry' in round_data:
                history_parts.append(f"**医生询问**: {round_data['doctor_inquiry']}")
            
            if 'HPI' in round_data:
                history_parts.append(f"**现病史(HPI)**: {round_data['HPI']}")
            
            if 'PH' in round_data:
                history_parts.append(f"**既往史(PH)**: {round_data['PH']}")
            
            if 'chief_complaint' in round_data:
                history_parts.append(f"**主述(CC)**: {round_data['chief_complaint']}")
            
            # 添加该轮的评分信息
            if 'evaluation_scores' in round_data:
                scores = round_data['evaluation_scores']
                history_parts.append("**该轮评分**:")
                history_parts.append(f"- 临床问诊能力: {scores.get('clinical_inquiry', 'N/A')}/5")
                history_parts.append(f"- 沟通表达能力: {scores.get('communication_quality', 'N/A')}/5")
                history_parts.append(f"- 信息收集全面性: {scores.get('information_completeness', scores.get('multi_round_consistency', 'N/A'))}/5")
                history_parts.append(f"- 整体专业性: {scores.get('overall_professionalism', 'N/A')}/5")
                history_parts.append(f"- 现病史相似度: {scores.get('present_illness_similarity', 'N/A')}/5")
                history_parts.append(f"- 既往史相似度: {scores.get('past_history_similarity', 'N/A')}/5")
                history_parts.append(f"- 主述相似度: {scores.get('chief_complaint_similarity', 'N/A')}/5")
            
            history_parts.append("")  # 空行分隔
        
        return '\n'.join(history_parts)
    
    def evaluate_single_round(self, patient_case: Dict[str, Any], 
                             round_data: Dict[str, Any]) -> EvaluatorResult:
        """
        评价单轮对话的便捷接口
        
        Args:
            patient_case (Dict[str, Any]): 患者病例信息
            round_data (Dict[str, Any]): 单轮对话数据
            
        Returns:
            EvaluatorResult: 单轮评价结果
        """
        return self.run(patient_case, 1, [round_data])