"""
Episodic Memory Service

处理情景记忆相关的业务逻辑，包括情景记忆总览、详情查询等。
"""

from datetime import datetime, timedelta
from typing import Any, Dict, List, Optional, Tuple

import pytz
from app.core.logging_config import get_logger
from app.services.memory_base_service import MemoryBaseService

logger = get_logger(__name__)


class MemoryEpisodicService(MemoryBaseService):
    """情景记忆服务类"""
    
    def __init__(self):
        super().__init__()
        logger.info("MemoryEpisodicService initialized")
    
    async def _get_title_and_type(
        self,
        summary_id: str,
        end_user_id: str
    ) -> Tuple[str, str]:
        """
        读取情景记忆的标题(title)和类型(type)
        
        仅负责读取已存在的title和type，不进行生成
        title从name属性读取，type从memory_type属性读取
        
        Args:
            summary_id: Summary节点的ID
            end_user_id: 终端用户ID (end_user_id)
            
        Returns:
            (标题, 类型)元组，如果不存在则返回默认值
        """
        try:
            # 查询Summary节点的name(作为title)和memory_type(作为type)
            query = """
            MATCH (s:MemorySummary)
            WHERE elementId(s) = $summary_id AND s.end_user_id = $end_user_id
            RETURN s.name AS title, s.memory_type AS type
            """
            
            result = await self.neo4j_connector.execute_query(
                query,
                summary_id=summary_id,
                end_user_id=end_user_id
            )
            
            if not result or len(result) == 0:
                logger.warning(f"未找到 summary_id={summary_id} 的节点")
                return ("未知标题", "其他")
            
            record = result[0]
            title = record.get("title") or "未命名"
            episodic_type = record.get("type") or "其他"
            
            return (title, episodic_type)
            
        except Exception as e:
            logger.error(f"读取标题和类型时出错: {str(e)}", exc_info=True)
            return ("错误", "其他")
    
    async def _extract_involved_objects(
        self,
        summary_id: str,
        end_user_id: str
    ) -> List[str]:
        """
        提取情景记忆涉及的前3个最重要实体
        
        Args:
            summary_id: Summary节点的ID
            end_user_id: 终端用户ID (end_user_id)
            
        Returns:
            前3个实体的name属性列表
        """
        try:
            # 查询Summary节点指向的Statement节点,再查询Statement指向的ExtractedEntity节点
            # 按activation_value降序排序,返回前3个
            query = """
            MATCH (s:MemorySummary)
            WHERE elementId(s) = $summary_id AND s.end_user_id = $end_user_id
            MATCH (s)-[:DERIVED_FROM_STATEMENT]->(stmt:Statement)
            MATCH (stmt)-[:REFERENCES_ENTITY]->(entity:ExtractedEntity)
            WHERE entity.activation_value IS NOT NULL
            RETURN DISTINCT entity.name AS name, entity.activation_value AS activation
            ORDER BY activation DESC
            LIMIT 3
            """
            
            result = await self.neo4j_connector.execute_query(
                query,
                summary_id=summary_id,
                end_user_id=end_user_id
            )
            
            # 提取实体名称
            involved_objects = [record["name"] for record in result if record.get("name")]
            
            logger.info(f"成功提取 summary_id={summary_id} 的涉及对象: {involved_objects}")
            
            return involved_objects
            
        except Exception as e:
            logger.error(f"提取涉及对象时出错: {str(e)}", exc_info=True)
            return []
    
    async def _extract_content_records(
        self,
        summary_id: str,
        end_user_id: str
    ) -> List[str]:
        """
        提取情景记忆的内容记录
        
        Args:
            summary_id: Summary节点的ID
            end_user_id: 终端用户ID (end_user_id)
            
        Returns:
            所有Statement节点的statement属性内容列表
        """
        try:
            # 查询Summary节点指向的所有Statement节点
            query = """
            MATCH (s:MemorySummary)
            WHERE elementId(s) = $summary_id AND s.end_user_id = $end_user_id
            MATCH (s)-[:DERIVED_FROM_STATEMENT]->(stmt:Statement)
            WHERE stmt.statement IS NOT NULL AND stmt.statement <> ''
            RETURN stmt.statement AS statement
            """
            
            result = await self.neo4j_connector.execute_query(
                query,
                summary_id=summary_id,
                end_user_id=end_user_id
            )
            
            # 提取statement内容
            content_records = [record["statement"] for record in result if record.get("statement")]
            
            logger.info(f"成功提取 summary_id={summary_id} 的内容记录,共 {len(content_records)} 条")
            
            return content_records
            
        except Exception as e:
            logger.error(f"提取内容记录时出错: {str(e)}", exc_info=True)
            return []
    
    def _calculate_time_filter(self, time_range: str) -> Optional[str]:
        """
        根据时间范围计算过滤的起始时间
        
        Args:
            time_range: 时间范围 (all/today/this_week/this_month)
            
        Returns:
            ISO格式的时间字符串，如果是"all"则返回None
        """
        if time_range == "all":
            return None
        
        # 获取当前时间（UTC）
        now = datetime.now(pytz.UTC)
        
        if time_range == "today":
            # 今天的开始时间（00:00:00）
            start_time = now.replace(hour=0, minute=0, second=0, microsecond=0)
        elif time_range == "this_week":
            # 本周的开始时间（周一00:00:00）
            days_since_monday = now.weekday()
            start_time = (now - timedelta(days=days_since_monday)).replace(
                hour=0, minute=0, second=0, microsecond=0
            )
        elif time_range == "this_month":
            # 本月的开始时间（1号00:00:00）
            start_time = now.replace(day=1, hour=0, minute=0, second=0, microsecond=0)
        else:
            return None
        
        # 返回ISO格式字符串
        return start_time.isoformat()
    
    async def get_episodic_memory_overview(
        self,
        end_user_id: str,
        time_range: str = "all",
        episodic_type: str = "all",
        title_keyword: Optional[str] = None
    ) -> Dict[str, Any]:
        """
        获取情景记忆总览信息
        
        Args:
            end_user_id: 终端用户ID
            time_range: 时间范围筛选
            episodic_type: 情景类型筛选
            title_keyword: 标题关键词（可选，用于模糊搜索）
        """
        try:
            logger.info(
                f"开始查询 end_user_id={end_user_id} 的情景记忆总览, "
                f"time_range={time_range}, episodic_type={episodic_type}, title_keyword={title_keyword}"
            )
            
            # 1. 先查询所有情景记忆的总数（不受筛选条件限制）
            total_all_query = """
            MATCH (s:MemorySummary)
            WHERE s.end_user_id = $end_user_id
            RETURN count(s) AS total_all
            """
            total_all_result = await self.neo4j_connector.execute_query(
                total_all_query, 
                end_user_id=end_user_id
            )
            total_all = total_all_result[0]["total_all"] if total_all_result else 0
            
            # 2. 计算时间范围的起始时间戳
            time_filter = self._calculate_time_filter(time_range)
            
            # 3. 构建Cypher查询
            query = """
            MATCH (s:MemorySummary)
            WHERE s.end_user_id = $end_user_id
            """
            
            # 添加时间范围过滤
            if time_filter:
                query += " AND s.created_at >= $time_filter"
            
            # 添加标题关键词过滤（如果提供了title_keyword）
            if title_keyword:
                query += " AND toLower(s.name) CONTAINS toLower($title_keyword)"
            
            query += """
            RETURN elementId(s) AS id, 
                   s.created_at AS created_at,
                   s.memory_type AS type,
                   s.name AS title
            ORDER BY s.created_at DESC
            """
            
            params = {"end_user_id": end_user_id}
            if time_filter:
                params["time_filter"] = time_filter
            if title_keyword:
                params["title_keyword"] = title_keyword
            
            result = await self.neo4j_connector.execute_query(query, **params)
            
            # 4. 如果没有数据，返回空列表
            if not result:
                logger.info(f"end_user_id={end_user_id} 没有情景记忆数据")
                return {
                    "total": 0,
                    "total_all": total_all,
                    "episodic_memories": []
                }
            
            # 5. 对每个节点读取标题和类型，并应用类型筛选
            episodic_memories = []
            for record in result:
                summary_id = record["id"]
                created_at_str = record.get("created_at")
                memory_type = record.get("type", "其他")
                title = record.get("title") or "未命名"  # 直接从查询结果获取标题
                
                # 应用情景类型筛选
                if episodic_type != "all":
                    # 检查类型是否匹配
                    # 注意：Neo4j 中存储的 memory_type 现在应该是英文格式（如 "conversation", "project_work"）
                    # 但为了兼容旧数据，我们也支持中文格式的匹配
                    type_mapping = {
                        "conversation": "对话",
                        "project_work": "项目/工作",
                        "learning": "学习",
                        "decision": "决策",
                        "important_event": "重要事件"
                    }
                    
                    # 获取对应的中文类型（用于兼容旧数据）
                    chinese_type = type_mapping.get(episodic_type)
                    
                    # 检查类型是否匹配（支持新的英文格式和旧的中文格式）
                    if memory_type != episodic_type and memory_type != chinese_type:
                        continue
                
                # 使用基类方法转换时间戳
                created_at_timestamp = self.parse_timestamp(created_at_str)
                
                episodic_memories.append({
                    "id": summary_id,
                    "title": title,
                    "type": memory_type,
                    "created_at": created_at_timestamp
                })
            
            logger.info(
                f"成功获取 end_user_id={end_user_id} 的情景记忆总览,"
                f"筛选后 {len(episodic_memories)} 条，总共 {total_all} 条"
            )
            
            return {
                "total": len(episodic_memories),
                "total_all": total_all,
                "episodic_memories": episodic_memories
            }
            
        except Exception as e:
            logger.error(f"获取情景记忆总览时出错: {str(e)}", exc_info=True)
            raise
    
    async def get_episodic_memory_details(
        self,
        end_user_id: str,
        summary_id: str
    ) -> Dict[str, Any]:
        """
        获取单个情景记忆的详细信息
        
        """
        try:
            logger.info(f"开始查询 end_user_id={end_user_id}, summary_id={summary_id} 的情景记忆详情")
            
            # 1. 查询指定的MemorySummary节点
            query = """
            MATCH (s:MemorySummary)
            WHERE elementId(s) = $summary_id AND s.end_user_id = $end_user_id
            RETURN elementId(s) AS id, s.created_at AS created_at
            """
            
            result = await self.neo4j_connector.execute_query(
                query,
                summary_id=summary_id,
                end_user_id=end_user_id
            )
            
            # 2. 如果节点不存在，返回错误
            if not result or len(result) == 0:
                logger.warning(f"未找到 summary_id={summary_id} 的情景记忆")
                raise ValueError(f"情景记忆不存在: summary_id={summary_id}")
            
            # 3. 获取基本信息
            record = result[0]
            created_at_str = record.get("created_at")
            
            # 使用基类方法转换时间戳
            created_at_timestamp = self.parse_timestamp(created_at_str)
            
            # 4. 调用_get_title_and_type读取标题和类型
            title, episodic_type = await self._get_title_and_type(
                summary_id=summary_id,
                end_user_id=end_user_id
            )
            
            # 5. 调用_extract_involved_objects提取涉及对象
            involved_objects = await self._extract_involved_objects(
                summary_id=summary_id,
                end_user_id=end_user_id
            )
            
            # 6. 调用_extract_content_records提取内容记录
            content_records = await self._extract_content_records(
                summary_id=summary_id,
                end_user_id=end_user_id
            )
            
            # 7. 使用基类方法提取情绪
            emotion = await self.extract_episodic_emotion(
                summary_id=summary_id,
                end_user_id=end_user_id
            )
            
            # 8. 返回完整的详情信息
            details = {
                "id": summary_id,
                "created_at": created_at_timestamp,
                "involved_objects": involved_objects,
                "episodic_type": episodic_type,
                "content_records": content_records,
                "emotion": emotion
            }
            
            logger.info(f"成功获取 summary_id={summary_id} 的情景记忆详情")
            
            return details
            
        except ValueError:
            # 重新抛出ValueError，让Controller层处理
            raise
        except Exception as e:
            logger.error(f"获取情景记忆详情时出错: {str(e)}", exc_info=True)
            raise


# 创建全局服务实例（供控制器层使用）
memory_episodic_service = MemoryEpisodicService()
