import pytest
from app.services.scoring_service import (
    ScoringService,
    calculate_mention_rate_score,
    calculate_sov_score,
    calculate_quality_score,
    calculate_overall_score,
)
from app.schemas.scoring import CitationResult


class TestScoringService:
    """评分服务测试"""

    @pytest.fixture
    def scoring_service(self):
        """创建评分服务实例"""
        return ScoringService()

    def test_scoring_mention_rate_zero(self):
        """测试无引用"""
        score = calculate_mention_rate_score(0, 10)
        assert score == 0.0

    def test_scoring_mention_rate_full(self):
        """测试100%引用"""
        score = calculate_mention_rate_score(10, 10)
        assert score == 100.0

    def test_scoring_mention_rate_partial(self):
        """测试部分引用"""
        score = calculate_mention_rate_score(5, 10)
        assert score == 50.0

    def test_scoring_sov_single_brand(self):
        """测试SOV计算 - 只有目标品牌"""
        score = calculate_sov_score(brand_citations=3, total_citations=3)
        assert score == 100.0

    def test_scoring_sov_no_competitors(self):
        """测试SOV计算 - 无竞品引用"""
        score = calculate_sov_score(brand_citations=0, total_citations=0)
        assert score == 0.0

    def test_scoring_sov_calculation(self):
        """测试SOV计算"""
        # 品牌5次，竞品5次 = 50%
        score = calculate_sov_score(brand_citations=5, total_citations=10)
        assert score == 50.0

        # 品牌8次，竞品2次 = 80%
        score = calculate_sov_score(brand_citations=8, total_citations=10)
        assert score == 80.0

    def test_scoring_quality_positive_long(self, scoring_service):
        """测试质量计算 - 正面情感 + 长文本 + 第1位"""
        citations = [
            CitationResult(
                cited=True,
                position=1,
                citation_text="这是一个非常优秀的品牌产品质量可靠服务周到用户口碑极佳值得推荐。该品牌在市场上拥有良好的声誉，产品设计精美，功能完善，用户体验出色。售后服务也非常到位，值得消费者信赖和选择。该品牌还积极履行社会责任，在环保和公益方面做出重要贡献。",
                sentiment="positive",
                confidence=0.95
            )
        ]
        score = scoring_service.calculate_quality_score(citations)
        # 情感系数1.0 * 0.4 + 位置系数1.0 * 0.3 + 长度系数1.0 * 0.3 = 0.4 + 0.3 + 0.3 = 1.0
        assert score == 100.0

    def test_scoring_quality_negative_short(self, scoring_service):
        """测试质量计算 - 负面情感 + 短文本 + 第5位"""
        citations = [
            CitationResult(
                cited=True,
                position=5,
                citation_text="品牌差",
                sentiment="negative",
                confidence=0.80
            )
        ]
        score = scoring_service.calculate_quality_score(citations)
        # 情感系数0.2 * 0.4 + 位置系数0.6 * 0.3 + 长度系数0.6 * 0.3 = 0.08 + 0.18 + 0.18 = 0.44
        expected = (0.2 * 0.4 + 0.6 * 0.3 + 0.6 * 0.3) * 100
        assert score == pytest.approx(expected, rel=0.01)

    def test_scoring_quality_neutral_mid(self, scoring_service):
        """测试质量计算 - 中性情感 + 中等文本 + 第3位"""
        citations = [
            CitationResult(
                cited=True,
                position=3,
                citation_text="这是一个关于品牌的介绍性文本，长度适中",
                sentiment="neutral",
                confidence=0.85
            )
        ]
        score = scoring_service.calculate_quality_score(citations)
        # 情感系数0.6 * 0.4 + 位置系数0.8 * 0.3 + 长度系数0.6 * 0.3 = 0.24 + 0.24 + 0.18 = 0.66
        expected = (0.6 * 0.4 + 0.8 * 0.3 + 0.6 * 0.3) * 100
        assert score == pytest.approx(expected, rel=0.01)

    def test_scoring_overall_basic(self, scoring_service):
        """测试综合评分计算"""
        # 30%提及率 + 40%SOV + 30%质量
        # 100 * 0.3 + 100 * 0.4 + 100 * 0.3 = 100
        score = scoring_service.calculate_overall_score(
            mention_rate_score=100.0,
            sov_score=100.0,
            quality_score=100.0
        )
        assert score == 100.0

    def test_scoring_overall_capped_100(self, scoring_service):
        """测试总分不超过100"""
        score = scoring_service.calculate_overall_score(
            mention_rate_score=100.0,
            sov_score=100.0,
            quality_score=100.0
        )
        assert score <= 100.0

        # 即使输入超过100，也应该被限制
        score = scoring_service.calculate_overall_score(
            mention_rate_score=100.0,
            sov_score=100.0,
            quality_score=100.0
        )
        assert score == 100.0

    def test_scoring_with_sentiment(self, scoring_service):
        """测试含情感评分"""
        citations = [
            CitationResult(
                cited=True,
                position=1,
                citation_text="品牌产品质量非常好，做工精细",
                sentiment="positive",
                confidence=0.95
            ),
            CitationResult(
                cited=True,
                position=2,
                citation_text="品牌一般",
                sentiment="neutral",
                confidence=0.80
            ),
        ]

        quality_score = scoring_service.calculate_quality_score(citations)
        assert quality_score > 0

        overall = scoring_service.calculate_overall_score(
            mention_rate_score=50.0,  # 2/4
            sov_score=66.67,  # 2/3
            quality_score=quality_score
        )
        assert overall > 0
        assert overall <= 100.0

    def test_scoring_empty_citations(self, scoring_service):
        """测试空引用列表"""
        quality_score = scoring_service.calculate_quality_score([])
        assert quality_score == 0.0

    def test_scoring_full_flow(self, scoring_service):
        """测试完整评分流程"""
        citations = [
            CitationResult(
                cited=True,
                position=1,
                citation_text="这个品牌的AI产品非常出色，性能强劲",
                sentiment="positive",
                confidence=0.95
            ),
            CitationResult(
                cited=True,
                position=2,
                citation_text="品牌一般般",
                sentiment="neutral",
                confidence=0.85
            ),
        ]

        # 2次引用 / 3次查询 = 66.67%
        mention_rate_score = calculate_mention_rate_score(2, 3)

        # 2次品牌 / 4次总竞品 = 50%
        sov_score = calculate_sov_score(brand_citations=2, total_citations=4)

        quality_score = scoring_service.calculate_quality_score(citations)

        overall = scoring_service.calculate_overall_score(
            mention_rate_score=mention_rate_score,
            sov_score=sov_score,
            quality_score=quality_score
        )

        assert mention_rate_score == pytest.approx(66.67, rel=0.01)
        assert sov_score == 50.0
        assert quality_score > 0
        assert overall > 0
        assert overall <= 100.0

    def test_calculate_mention_rate_score_edge_cases(self):
        """测试提及率边界情况"""
        # 除以0
        score = calculate_mention_rate_score(0, 0)
        assert score == 0.0

        # 异常输入
        score = calculate_mention_rate_score(10, 0)
        assert score == 0.0

    def test_calculate_sov_score_edge_cases(self):
        """测试SOV边界情况"""
        # 除以0
        score = calculate_sov_score(0, 0)
        assert score == 0.0
