"""
User request constraint evaluator - use large model to evaluate whether the itinerary meets user expectations
"""

import json
from typing import Dict, Any, Tuple
from .base_evaluator import BaseEvaluator
from utils.llms import AbstractLLM, Gemini
from utils.user_request_evaluator_prompts import evaluation_system_prompt_zh, evaluation_system_prompt_en, evaluation_prompt_v2_zh, evaluation_prompt_v2_en


class UserRequestEvaluator(BaseEvaluator):
    """User Request Constraint Evaluator Class"""
    
    def __init__(self, llm: AbstractLLM = None, weight: float = 1.0):
        """
        Initialize User Request Constraint Evaluator
        
        Args:
            llm: LLM Instance, if None, use default Gemini model
            weight: Evaluation Weight
        """
        super().__init__("UserRequestEvaluator")
        self.llm = llm if llm is not None else Gemini()
        self.weight = weight
    
    def evaluate(self, data: Dict[str, Any]) -> Tuple[float, Dict[str, Any]]:
        """
        Evaluate if the itinerary meets user requests
        
        Args:
            data: Dictionary containing the following keys:
                - prompt_str: Original user request string
                - answer_text: Model answer text
                - itinerary: Parsed itinerary data
                
        Returns:
            Tuple[float, Dict]: (Score, Detailed Evaluation Result)
        """
        try:
            prompt_str = data.get("prompt_str", "")
            answer_text = data.get("answer_text", "")
            itinerary = data.get("itinerary", {})
            locale = data.get("poi_dict", {}).get("locale", "zh")
            
            # If necessary data is missing, return error
            if not prompt_str or not answer_text:
                return 0, {
                    "error": "Missing required evaluation data",
                    "user_request_compliance": 0,
                    "detailed_feedback": "Cannot evaluate due to missing user request or model response"
                }
            
            # Build evaluation prompt
            messages = self._build_evaluation_prompt(prompt_str, answer_text, itinerary, locale)
            
            # Get evaluation result
            response = self.llm(messages, one_line=False, json_mode=False)
            evaluation_result = self._parse_evaluation_response(response)
            
            # Calculate final score
            score = evaluation_result.get("final_score", 0) * self.weight
            
            return score, {
                "final_score": score,
                "detailed_feedback": evaluation_result.get("detailed_feedback", ""),
                "raw_llm_response": response
            }
            
        except Exception as e:
            return 0, {
                "error": f"Error occurred during evaluation: {str(e)}",
                "final_score": 0,
                "detailed_feedback": "Evaluation failed"
            }
    
    def _build_evaluation_prompt(self, prompt_str: str, answer_text: str, itinerary: Dict, locale: str) -> str:
        """
        Build evaluation prompt
        
        Args:
            prompt_str: Original user request
            answer_text: Model answer
            itinerary: Parsed itinerary data
            
        Returns:
            str: Evaluation prompt
        """
        # Extract user request
        user_request = ""
        try:
            messages = json.loads(prompt_str)
            for message in messages[:-1]:
                if message['role'] == 'user':
                    user_request += message['content'] + "\n"
        except Exception as e:
            if "<|im_start|>user" in prompt_str:
                _, prompt_str = prompt_str.rsplit("<|im_start|>user", 1)
            elif "<｜User｜>" in prompt_str:
                _, prompt_str = prompt_str.rsplit("<｜User｜>", 1)
            elif "User:" in prompt_str:
                _, prompt_str = prompt_str.rsplit("User:", 1)

        if '【用户最新需求】：' in prompt_str:
            user_request += "【用户最新需求】：" + prompt_str.split('【用户最新需求】：')[-1].strip()
        elif '[The latest query of user]:' in prompt_str:
            user_request += "[The latest query of user]:" + prompt_str.split('[The latest query of user]:')[-1].strip()
        elif "[User Query]" in prompt_str:
            user_request += "[User Query]" + prompt_str.split('[User Query]')[-1].strip()
        elif "【用户需求】" in prompt_str:
            user_request += "【用户需求】" + prompt_str.split('【用户需求】')[-1].strip()
        elif "[用户最新查询]:" in prompt_str:
            user_request += "[用户最新查询]:" + prompt_str.split('[用户最新查询]:')[-1].strip()

        # Extract itinerary key information
        # itinerary_summary = self._extract_itinerary_summary(itinerary)
        user_request = user_request.replace("<|im_end|>", "").strip()

        if locale == "zh-CN":
            system_prompt = evaluation_system_prompt_zh
            prompt = evaluation_prompt_v2_zh.format(user_request=user_request, answer_text=answer_text)
        else:
            system_prompt = evaluation_system_prompt_en
            prompt = evaluation_prompt_v2_en.format(user_request=user_request, answer_text=answer_text)

        # Call LLM for evaluation
        messages = [
            {
                "role": "system",
                "content": system_prompt
            },
            {
                "role": "user", 
                "content": prompt
            }
        ]

        return messages
    
    def _extract_itinerary_summary(self, itinerary: Dict) -> str:
        """
        Extract itinerary key information summary
        
        Args:
            itinerary: Itinerary data
            
        Returns:
            str: Itinerary summary
        """
        try:
            summary_parts = []
            
            # Extract basic information
            if "days" in itinerary:
                total_days = len(itinerary["days"])
                summary_parts.append(f"总天数: {total_days}天")
            
            # Extract destination information
            destinations = set()
            if "days" in itinerary:
                for day_info in itinerary["days"]:
                    if "attractions" in day_info:
                        for attraction in day_info["attractions"]:
                            if "name" in attraction:
                                destinations.add(attraction["name"])
            
            if destinations:
                summary_parts.append(f"主要景点: {', '.join(list(destinations)[:5])}")
            
            # Extract accommodation information
            hotels = []
            if "days" in itinerary:
                for day_info in itinerary["days"]:
                    if "accommodations" in day_info:
                        for hotel in day_info["accommodations"]:
                            if "name" in hotel:
                                hotels.append(hotel["name"])
            
            if hotels:
                summary_parts.append(f"住宿: {', '.join(hotels[:3])}")
            
            return "\n".join(summary_parts) if summary_parts else "Unable to extract itinerary information"
            
        except Exception as e:
            return f"Failed to extract itinerary information: {str(e)}"
    
    def _parse_evaluation_response(self, response: str) -> Dict[str, Any]:
        """
        Parse LLM evaluation response
        
        Args:
            response: LLM response string
            
        Returns:
            Dict: Parsed evaluation result
        """
        try:
            # Try to parse JSON directly
            if isinstance(response, str):
                if "```json" in response:
                    response = response.replace("```json", "").replace("```", "").strip()
                result = json.loads(response)
            else:
                result = response
            
            # Verify necessary fields
            
            if "detailed_feedback" not in result:
                result["detailed_feedback"] = "Evaluation completed but missing detailed feedback"
            
            if "final_score" not in result:
                result["final_score"] = 0      
            return result
            
        except json.JSONDecodeError as e:
            # JSON parsing failed, return default result
            return {
                "final_score": 0.5,
                "detailed_feedback": f"Failed to parse LLM response: {str(e)}, original response: {response[:200]}...",
                "parse_error": True
            }
        except Exception as e:
            return {
                "final_score": 0,
                "detailed_feedback": f"Failed to process evaluation result: {str(e)}",
                "error": True
            } 