"""
题目管理服务测试模块

测试ManagementService功能：
- 单个题目的CRUD操作
- 批量操作（创建、更新、删除）
- 统计和分析
- 数据验证
"""

import pytest
from unittest.mock import Mock, MagicMock, patch
from typing import List

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


class TestManagementService:
    """题目管理服务测试"""
    
    @pytest.fixture
    def mock_db_manager(self):
        """模拟数据库管理器"""
        db_manager = Mock(spec=DatabaseManager)
        return db_manager
    
    @pytest.fixture
    def mock_embedding_service(self):
        """模拟Embedding服务"""
        embedding_service = Mock(spec=EmbeddingService)
        embedding_service.embed_text = Mock(
            return_value=[0.1, 0.2, 0.3, 0.4, 0.5]
        )
        embedding_service.get_cache_stats = Mock(
            return_value={
                "cache_size": 100,
                "hits": 50,
                "misses": 20
            }
        )
        return embedding_service
    
    @pytest.fixture
    def management_service(self, mock_db_manager, mock_embedding_service):
        """创建管理服务实例"""
        return ManagementService(
            db_manager=mock_db_manager,
            embedding_service=mock_embedding_service,
            max_workers=2,
            logger=get_logger()
        )
    
    # -------------------------------------------------------------------------
    # 单个题目CRUD操作测试
    # -------------------------------------------------------------------------
    
    def test_create_question(self, management_service, mock_db_manager, mock_embedding_service):
        """测试创建题目"""
        # 准备测试数据
        question_data = QuestionCreateDTO(
            title="Python基础题目",
            content="这是一个Python基础题目",
            question_type="单选",
            category="Python",
            difficulty="简单",
            tags=["Python", "基础"],
            answer="A",
            status="已发布"
        )
        
        # 设置模拟返回值
        mock_db_manager.create_question = Mock(return_value="test-id-123")
        mock_embedding_service.embed_text = Mock(
            return_value=[0.1, 0.2, 0.3]
        )
        
        # 执行创建
        result = management_service.create_question(question_data)
        
        # 验证结果
        assert result == "test-id-123"
        mock_embedding_service.embed_text.assert_called_once()
        mock_db_manager.create_question.assert_called_once()
    
    def test_get_question(self, management_service, mock_db_manager):
        """测试获取题目详情"""
        # 准备模拟数据
        expected_question = {
            "question_id": "test-id-123",
            "title": "Python基础题目",
            "content": "这是一个Python基础题目",
            "question_type": "单选",
            "category": "Python",
            "difficulty": "简单"
        }
        
        mock_db_manager.get_question = Mock(return_value=expected_question)
        
        # 获取题目
        result = management_service.get_question("test-id-123", include_answer=True)
        
        # 验证结果
        assert result == expected_question
        mock_db_manager.get_question.assert_called_once_with(
            question_id="test-id-123",
            include_answer=True
        )
    
    def test_get_question_not_found(self, management_service, mock_db_manager):
        """测试获取不存在的题目"""
        mock_db_manager.get_question = Mock(return_value=None)
        
        result = management_service.get_question("nonexistent-id")
        
        assert result is None
    
    def test_update_question(self, management_service, mock_db_manager, mock_embedding_service):
        """测试更新题目"""
        # 准备更新数据
        updates = QuestionUpdateDTO(
            title="更新后的标题",
            difficulty="中等"
        )
        
        mock_db_manager.update_question = Mock(return_value=True)
        mock_embedding_service.embed_text = Mock(
            return_value=[0.1, 0.2, 0.3]
        )
        
        # 执行更新
        result = management_service.update_question("test-id-123", updates)
        
        # 验证结果
        assert result is True
        mock_db_manager.update_question.assert_called_once()
    
    def test_update_question_with_content(
        self, 
        management_service, 
        mock_db_manager, 
        mock_embedding_service
    ):
        """测试更新题目内容（需要重新生成向量）"""
        updates = QuestionUpdateDTO(
            content="新的题目内容"
        )
        
        mock_db_manager.update_question = Mock(return_value=True)
        mock_embedding_service.embed_text = Mock(
            return_value=[0.2, 0.3, 0.4]
        )
        
        result = management_service.update_question("test-id-123", updates)
        
        # 验证向量已生成
        assert result is True
        mock_embedding_service.embed_text.assert_called_once()
    
    def test_delete_question(self, management_service, mock_db_manager):
        """测试删除题目"""
        mock_db_manager.delete_question = Mock(return_value=True)
        
        result = management_service.delete_question("test-id-123", soft_delete=True)
        
        assert result is True
        mock_db_manager.delete_question.assert_called_once_with(
            question_id="test-id-123",
            soft_delete=True
        )
    
    def test_list_questions(self, management_service, mock_db_manager):
        """测试列表查询"""
        questions = [
            {"question_id": "id1", "title": "题目1"},
            {"question_id": "id2", "title": "题目2"},
        ]
        
        mock_db_manager.list_questions = Mock(return_value=(questions, 100))
        
        result_questions, total = management_service.list_questions(
            page=1,
            page_size=20
        )
        
        assert result_questions == questions
        assert total == 100
    
    # -------------------------------------------------------------------------
    # 批量操作测试
    # -------------------------------------------------------------------------
    
    def test_batch_create_questions(
        self,
        management_service,
        mock_db_manager,
        mock_embedding_service
    ):
        """测试批量创建题目"""
        questions_data = [
            QuestionCreateDTO(
                title=f"题目{i}",
                content=f"内容{i}",
                question_type="单选",
                category="Python",
                difficulty="简单"
            )
            for i in range(3)
        ]
        
        # 设置模拟返回值
        question_ids = ["id1", "id2", "id3"]
        mock_db_manager.create_question = Mock(
            side_effect=question_ids
        )
        
        # 执行批量创建
        result = management_service.batch_create_questions(questions_data)
        
        # 验证结果
        assert result["total"] == 3
        assert result["successful"] == 3
        assert result["failed"] == 0
        assert len(result["created_ids"]) == 3
    
    def test_batch_create_questions_partial_failure(
        self,
        management_service,
        mock_db_manager,
        mock_embedding_service
    ):
        """测试批量创建部分失败"""
        questions_data = [
            QuestionCreateDTO(
                title=f"题目{i}",
                content=f"内容{i}",
                question_type="单选",
                category="Python",
                difficulty="简单"
            )
            for i in range(2)
        ]
        
        # 第一个成功，第二个失败
        mock_db_manager.create_question = Mock(
            side_effect=["id1", Exception("创建失败")]
        )
        
        result = management_service.batch_create_questions(questions_data)
        
        # 验证结果
        assert result["total"] == 2
        assert result["successful"] == 1
        assert result["failed"] == 1
        assert len(result["errors"]) == 1
    
    def test_batch_update_questions(
        self,
        management_service,
        mock_db_manager
    ):
        """测试批量更新题目"""
        updates_list = [
            ("id1", QuestionUpdateDTO(title="更新1")),
            ("id2", QuestionUpdateDTO(title="更新2")),
            ("id3", QuestionUpdateDTO(title="更新3")),
        ]
        
        mock_db_manager.update_question = Mock(return_value=True)
        
        result = management_service.batch_update_questions(updates_list)
        
        assert result["total"] == 3
        assert result["successful"] == 3
        assert result["failed"] == 0
    
    def test_batch_delete_questions(
        self,
        management_service,
        mock_db_manager
    ):
        """测试批量删除题目"""
        question_ids = ["id1", "id2", "id3"]
        
        mock_db_manager.delete_question = Mock(return_value=True)
        
        result = management_service.batch_delete_questions(question_ids)
        
        assert result["total"] == 3
        assert result["successful"] == 3
        assert result["failed"] == 0
    
    # -------------------------------------------------------------------------
    # 统计和维护测试
    # -------------------------------------------------------------------------
    
    def test_get_statistics(self, management_service, mock_db_manager, mock_embedding_service):
        """测试获取统计数据"""
        stats = {
            "total_questions": 100,
            "by_difficulty": {"简单": 30, "中等": 50, "困难": 20}
        }
        
        mock_db_manager.get_statistics = Mock(return_value=stats)
        mock_embedding_service.get_cache_stats = Mock(
            return_value={"hits": 100}
        )
        
        result = management_service.get_statistics()
        
        assert result["total_questions"] == 100
        assert "embedding_cache_stats" in result
    
    def test_check_data_consistency(self, management_service, mock_db_manager):
        """测试数据一致性检查"""
        consistency_report = {
            "sqlite_count": 100,
            "chroma_count": 100,
            "consistent": True
        }
        
        mock_db_manager.check_data_consistency = Mock(
            return_value=consistency_report
        )
        
        result = management_service.check_data_consistency()
        
        assert result["consistent"] is True
    
    # -------------------------------------------------------------------------
    # 边界情况测试
    # -------------------------------------------------------------------------
    
    def test_batch_create_empty_list(self, management_service):
        """测试批量创建空列表"""
        result = management_service.batch_create_questions([])
        
        assert result["total"] == 0
        assert result["successful"] == 0
        assert result["failed"] == 0
    
    def test_batch_update_empty_list(self, management_service):
        """测试批量更新空列表"""
        result = management_service.batch_update_questions([])
        
        assert result["total"] == 0
        assert result["successful"] == 0
        assert result["failed"] == 0
    
    def test_batch_delete_empty_list(self, management_service):
        """测试批量删除空列表"""
        result = management_service.batch_delete_questions([])
        
        assert result["total"] == 0
        assert result["successful"] == 0
        assert result["failed"] == 0
    
    def test_list_questions_invalid_pagination(self, management_service, mock_db_manager):
        """测试无效分页参数"""
        questions = []
        mock_db_manager.list_questions = Mock(return_value=(questions, 0))
        
        # 无效的页码和数量
        result_questions, total = management_service.list_questions(
            page=-1,
            page_size=200
        )
        
        # 应该使用默认值重试
        assert mock_db_manager.list_questions.called
    
    def test_update_question_no_changes(self, management_service, mock_db_manager):
        """测试没有更新字段的更新"""
        updates = QuestionUpdateDTO()
        
        mock_db_manager.update_question = Mock(return_value=False)
        
        result = management_service.update_question("test-id", updates)
        
        # 应该返回False（没有字段需要更新）
        assert result is False
    
    # -------------------------------------------------------------------------
    # 异常处理测试
    # -------------------------------------------------------------------------
    
    def test_create_question_failure(
        self,
        management_service,
        mock_db_manager,
        mock_embedding_service
    ):
        """测试创建题目异常"""
        question_data = QuestionCreateDTO(
            title="测试题目",
            content="测试内容",
            question_type="单选",
            category="Python",
            difficulty="简单"
        )
        
        mock_db_manager.create_question = Mock(
            side_effect=Exception("数据库错误")
        )
        
        with pytest.raises(Exception, match="数据库错误"):
            management_service.create_question(question_data)
    
    def test_get_question_exception(self, management_service, mock_db_manager):
        """测试获取题目异常"""
        mock_db_manager.get_question = Mock(
            side_effect=Exception("查询失败")
        )
        
        with pytest.raises(Exception, match="查询失败"):
            management_service.get_question("test-id")
    
    def test_delete_question_not_found(self, management_service, mock_db_manager):
        """测试删除不存在的题目"""
        mock_db_manager.delete_question = Mock(
            side_effect=Exception("题目不存在")
        )
        
        with pytest.raises(Exception, match="题目不存在"):
            management_service.delete_question("nonexistent-id")


class TestManagementServiceIntegration:
    """集成测试"""
    
    def test_create_and_get_question(self):
        """测试创建和获取题目的完整流程"""
        # 这是集成测试，需要真实的服务实例
        # 具体实现取决于是否有测试数据库
        pass
    
    def test_batch_operations_workflow(self):
        """测试批量操作的完整工作流"""
        pass

