"""
题目管理服务

提供题目的增删改查、批量操作和数据导入等核心业务功能。
与数据库管理器和Embedding服务集成，实现完整的题目生命周期管理。
"""

import sys
import os

# 将项目根目录添加到 sys.path
project_root = os.path.abspath(os.path.join(os.path.dirname(__file__), '..', '..'))
if project_root not in sys.path:
    sys.path.insert(0, project_root)

from typing import Dict, List, Optional, Any, Tuple
from concurrent.futures import ThreadPoolExecutor, as_completed

from src.core.logger import get_logger
from src.database.models import (
    QuestionModel, 
    QuestionCreateDTO, 
    QuestionUpdateDTO, 
    QuestionSearchFilter
)
from src.database.database_manager import DatabaseManager
from src.services.embedding_service import EmbeddingService


class ManagementService:
    """
    题目管理服务
    
    提供题目的完整生命周期管理，包括：
    - 单个题目的CRUD操作
    - 批量操作（导入、删除、更新）
    - 数据验证和清理
    - 与Embedding服务的集成
    """
    
    def __init__(
        self,
        db_manager: DatabaseManager,
        embedding_service: EmbeddingService,
        max_workers: int = 4,
        logger=None
    ):
        """
        初始化题目管理服务
        
        Args:
            db_manager: 数据库管理器实例
            embedding_service: Embedding服务实例
            max_workers: 并发处理线程数
            logger: 日志记录器实例
        """
        self.db_manager = db_manager
        self.embedding_service = embedding_service
        self.max_workers = max_workers
        self.logger = logger or get_logger()
    
    # -------------------------------------------------------------------------
    # 单个题目的CRUD操作
    # -------------------------------------------------------------------------
    
    def create_question(self, question_data: QuestionCreateDTO) -> str:
        """
        创建单个题目
        
        Args:
            question_data: 题目创建数据
            
        Returns:
            str: 创建的题目ID
            
        Raises:
            ValueError: 数据验证失败
            Exception: 创建失败
        """
        try:
            # 数据已通过Pydantic验证，生成向量
            embedding = self.embedding_service.embed_text(question_data.content)
            
            # 通过数据库管理器创建题目
            question_id = self.db_manager.create_question(
                question_data=question_data,
                embedding=embedding
            )
            
            self.logger.info(f"成功创建题目: {question_id}")
            return question_id
            
        except ValueError as e:
            self.logger.error(f"题目数据验证失败: {e}")
            raise
        except Exception as e:
            self.logger.error(f"创建题目失败: {e}")
            raise
    
    def get_question(
        self, 
        question_id: str, 
        include_answer: bool = True
    ) -> Optional[Dict[str, Any]]:
        """
        获取题目详情
        
        Args:
            question_id: 题目ID
            include_answer: 是否包含答案和解析
            
        Returns:
            Optional[Dict]: 题目数据，不存在返回None
        """
        try:
            question = self.db_manager.get_question(
                question_id=question_id,
                include_answer=include_answer
            )
            
            if question is None:
                self.logger.warning(f"题目不存在: {question_id}")
                return None
            
            return question
            
        except Exception as e:
            self.logger.error(f"获取题目失败: {e}")
            raise
    
    def update_question(
        self, 
        question_id: str, 
        updates: QuestionUpdateDTO
    ) -> bool:
        """
        更新题目
        
        Args:
            question_id: 题目ID
            updates: 更新数据
            
        Returns:
            bool: 更新是否成功
            
        Raises:
            ValueError: 题目不存在或数据无效
            Exception: 更新失败
        """
        try:
            update_dict = updates.model_dump(exclude_none=True)
            
            if not update_dict:
                self.logger.warning("没有字段需要更新")
                return False
            
            # 如果更新了内容，生成新的向量
            new_embedding = None
            if 'content' in update_dict:
                new_embedding = self.embedding_service.embed_text(update_dict['content'])
            
            # 通过数据库管理器更新
            result = self.db_manager.update_question(
                question_id=question_id,
                updates=updates,
                new_embedding=new_embedding
            )
            
            if result:
                self.logger.info(f"成功更新题目: {question_id}")
            
            return result
            
        except ValueError as e:
            self.logger.error(f"题目更新验证失败: {e}")
            raise
        except Exception as e:
            self.logger.error(f"更新题目失败: {e}")
            raise
    
    def delete_question(
        self, 
        question_id: str, 
        soft_delete: bool = True
    ) -> bool:
        """
        删除题目
        
        Args:
            question_id: 题目ID
            soft_delete: 是否软删除（标记为已归档）
            
        Returns:
            bool: 删除是否成功
        """
        try:
            result = self.db_manager.delete_question(
                question_id=question_id,
                soft_delete=soft_delete
            )
            
            if result:
                delete_type = "软删除" if soft_delete else "硬删除"
                self.logger.info(f"成功{delete_type}题目: {question_id}")
            
            return result
            
        except Exception as e:
            self.logger.error(f"删除题目失败: {e}")
            raise
    
    def list_questions(
        self,
        filters: Optional[QuestionSearchFilter] = None,
        page: int = 1,
        page_size: int = 20,
        sort_by: str = "created_at",
        sort_order: str = "DESC"
    ) -> Tuple[List[Dict[str, Any]], int]:
        """
        查询题目列表
        
        Args:
            filters: 过滤条件
            page: 页码
            page_size: 每页数量
            sort_by: 排序字段
            sort_order: 排序方向(DESC/ASC)
            
        Returns:
            Tuple[List[Dict], int]: (题目列表, 总数量)
        """
        try:
            # 验证分页参数
            if page < 1:
                page = 1
            if page_size < 1 or page_size > 100:
                page_size = 20
            
            questions, total = self.db_manager.list_questions(
                filters=filters,
                page=page,
                page_size=page_size,
                sort_by=sort_by,
                sort_order=sort_order
            )
            
            self.logger.info(f"查询题目列表: 第{page}页, 共{total}个结果")
            return questions, total
            
        except Exception as e:
            self.logger.error(f"查询题目列表失败: {e}")
            raise
    
    # -------------------------------------------------------------------------
    # 批量操作
    # -------------------------------------------------------------------------
    
    def batch_create_questions(
        self, 
        questions_data: List[QuestionCreateDTO]
    ) -> Dict[str, Any]:
        """
        批量创建题目
        
        Args:
            questions_data: 题目数据列表
            
        Returns:
            Dict: 包含成功/失败统计和详细信息
        """
        if not questions_data:
            return {
                "total": 0,
                "successful": 0,
                "failed": 0,
                "created_ids": [],
                "errors": []
            }
        
        result = {
            "total": len(questions_data),
            "successful": 0,
            "failed": 0,
            "created_ids": [],
            "errors": []
        }
        
        try:
            # 使用线程池并发处理
            with ThreadPoolExecutor(max_workers=self.max_workers) as executor:
                # 提交所有任务
                future_to_index = {
                    executor.submit(
                        self._create_question_safe, 
                        question_data
                    ): idx 
                    for idx, question_data in enumerate(questions_data)
                }
                
                # 收集结果
                for future in as_completed(future_to_index):
                    idx = future_to_index[future]
                    try:
                        question_id = future.result()
                        result["created_ids"].append(question_id)
                        result["successful"] += 1
                    except Exception as e:
                        result["failed"] += 1
                        result["errors"].append({
                            "index": idx,
                            "data": questions_data[idx].model_dump(),
                            "error": str(e)
                        })
            
            self.logger.info(
                f"批量创建完成: 成功{result['successful']}, "
                f"失败{result['failed']}/{result['total']}"
            )
            
            return result
            
        except Exception as e:
            self.logger.error(f"批量创建题目失败: {e}")
            raise
    
    def batch_update_questions(
        self,
        updates_list: List[Tuple[str, QuestionUpdateDTO]]
    ) -> Dict[str, Any]:
        """
        批量更新题目
        
        Args:
            updates_list: [(question_id, updates), ...] 的列表
            
        Returns:
            Dict: 包含成功/失败统计信息
        """
        if not updates_list:
            return {
                "total": 0,
                "successful": 0,
                "failed": 0,
                "errors": []
            }
        
        result = {
            "total": len(updates_list),
            "successful": 0,
            "failed": 0,
            "errors": []
        }
        
        try:
            with ThreadPoolExecutor(max_workers=self.max_workers) as executor:
                future_to_index = {
                    executor.submit(
                        self._update_question_safe,
                        question_id,
                        updates
                    ): idx
                    for idx, (question_id, updates) in enumerate(updates_list)
                }
                
                for future in as_completed(future_to_index):
                    idx = future_to_index[future]
                    try:
                        success = future.result()
                        if success:
                            result["successful"] += 1
                    except Exception as e:
                        result["failed"] += 1
                        question_id, updates = updates_list[idx]
                        result["errors"].append({
                            "index": idx,
                            "question_id": question_id,
                            "error": str(e)
                        })
            
            self.logger.info(
                f"批量更新完成: 成功{result['successful']}, "
                f"失败{result['failed']}/{result['total']}"
            )
            
            return result
            
        except Exception as e:
            self.logger.error(f"批量更新题目失败: {e}")
            raise
    
    def batch_delete_questions(
        self,
        question_ids: List[str],
        soft_delete: bool = True
    ) -> Dict[str, Any]:
        """
        批量删除题目
        
        Args:
            question_ids: 题目ID列表
            soft_delete: 是否软删除
            
        Returns:
            Dict: 包含成功/失败统计信息
        """
        if not question_ids:
            return {
                "total": 0,
                "successful": 0,
                "failed": 0,
                "errors": []
            }
        
        result = {
            "total": len(question_ids),
            "successful": 0,
            "failed": 0,
            "errors": []
        }
        
        try:
            with ThreadPoolExecutor(max_workers=self.max_workers) as executor:
                future_to_index = {
                    executor.submit(
                        self.delete_question,
                        question_id,
                        soft_delete
                    ): idx
                    for idx, question_id in enumerate(question_ids)
                }
                
                for future in as_completed(future_to_index):
                    idx = future_to_index[future]
                    try:
                        success = future.result()
                        if success:
                            result["successful"] += 1
                    except Exception as e:
                        result["failed"] += 1
                        result["errors"].append({
                            "index": idx,
                            "question_id": question_ids[idx],
                            "error": str(e)
                        })
            
            delete_type = "软删除" if soft_delete else "硬删除"
            self.logger.info(
                f"批量{delete_type}完成: 成功{result['successful']}, "
                f"失败{result['failed']}/{result['total']}"
            )
            
            return result
            
        except Exception as e:
            self.logger.error(f"批量删除题目失败: {e}")
            raise
    
    # -------------------------------------------------------------------------
    # 辅助方法
    # -------------------------------------------------------------------------
    
    def _create_question_safe(self, question_data: QuestionCreateDTO) -> str:
        """
        安全的创建题目方法（用于并发）
        
        Args:
            question_data: 题目数据
            
        Returns:
            str: 创建的题目ID
        """
        return self.create_question(question_data)
    
    def _update_question_safe(
        self, 
        question_id: str, 
        updates: QuestionUpdateDTO
    ) -> bool:
        """
        安全的更新题目方法（用于并发）
        
        Args:
            question_id: 题目ID
            updates: 更新数据
            
        Returns:
            bool: 更新是否成功
        """
        return self.update_question(question_id, updates)
    
    # -------------------------------------------------------------------------
    # 统计和分析
    # -------------------------------------------------------------------------
    
    def get_statistics(self) -> Dict[str, Any]:
        """
        获取题目库的统计数据
        
        Returns:
            Dict: 统计数据
        """
        try:
            stats = self.db_manager.get_statistics()
            
            # 添加额外的统计信息
            stats['embedding_cache_stats'] = self.embedding_service.get_cache_stats()
            
            return stats
            
        except Exception as e:
            self.logger.error(f"获取统计数据失败: {e}")
            raise
    
    def check_data_consistency(self) -> Dict[str, Any]:
        """
        检查数据一致性
        
        Returns:
            Dict: 一致性检查报告
        """
        try:
            report = self.db_manager.check_data_consistency()
            return report
            
        except Exception as e:
            self.logger.error(f"数据一致性检查失败: {e}")
            raise
    
    # -------------------------------------------------------------------------
    # 数据维护
    # -------------------------------------------------------------------------
    
    def sync_to_embedding(self, question_ids: Optional[List[str]] = None):
        """
        同步数据到Embedding向量库
        
        如果ChromaDB中缺少某些题目的向量，则重新生成并同步。
        
        Args:
            question_ids: 要同步的题目ID列表，None表示检查所有
        """
        try:
            if question_ids is None:
                self.logger.warning("全量同步功能需要实现分页获取")
                return
            
            success_count = 0
            for question_id in question_ids:
                try:
                    # 交由数据库管理器负责从SQLite读取题目并重建/更新Chroma向量
                    self.db_manager.sync_sqlite_to_chroma([question_id])
                    success_count += 1
                except Exception as e:
                    self.logger.warning(f"同步题目{question_id}失败: {e}")
            
            self.logger.info(f"同步完成: 成功{success_count}/{len(question_ids)}")
            
        except Exception as e:
            self.logger.error(f"数据同步失败: {e}")
            raise
    
    def validate_all_questions(self) -> Dict[str, Any]:
        """
        验证所有题目的数据完整性
        
        检查是否存在数据不一致、缺失字段等问题。
        
        Returns:
            Dict: 验证报告
        """
        try:
            report = {
                "total_checked": 0,
                "valid": 0,
                "invalid": 0,
                "errors": []
            }
            
            # 获取所有题目（需要分页）
            page = 1
            page_size = 50
            
            while True:
                questions, total = self.db_manager.list_questions(
                    page=page,
                    page_size=page_size
                )
                
                if not questions:
                    break
                
                for question in questions:
                    report["total_checked"] += 1
                    
                    # 验证基本字段
                    try:
                        # 尝试重新构建模型进行验证
                        QuestionModel(**question)
                        report["valid"] += 1
                    except Exception as e:
                        report["invalid"] += 1
                        report["errors"].append({
                            "question_id": question.get("question_id"),
                            "error": str(e)
                        })
                
                if len(questions) < page_size:
                    break
                
                page += 1
            
            self.logger.info(
                f"数据验证完成: 总数{report['total_checked']}, "
                f"有效{report['valid']}, 无效{report['invalid']}"
            )
            
            return report
            
        except Exception as e:
            self.logger.error(f"数据验证失败: {e}")
            raise

