from rights_filter.analysis.risk_scoring import RiskScorer
from rights_filter.domain.records import Evidence, EvidenceSource, ScoreResult


def test_face_presence_alone_requires_medium_review_without_becoming_high_risk():
    scorer = RiskScorer()
    result = scorer.score(
        [
            Evidence(
                source=EvidenceSource.FACE_PERSON,
                reason="Face/person detected",
                confidence=0.8,
                data={"face_count": 1},
            )
        ]
    )

    assert 30 <= result.score < 70
    assert result.band == "medium"


def test_operator_false_positive_evidence_is_not_scored():
    result = RiskScorer().score(
        [
            Evidence(
                source=EvidenceSource.FACE_PERSON,
                reason="Face/person detected",
                confidence=0.8,
                data={"operator_status": "false_positive"},
            ),
            Evidence(
                source=EvidenceSource.WEB_DETECTION,
                reason="Matching image URL found",
                confidence=0.9,
                data={"url": "https://example.com/official-character", "operator_status": "irrelevant"},
            ),
        ]
    )

    assert result.score == 0
    assert result.band == "low"
    assert result.reasons == []


def test_character_web_evidence_can_create_high_risk_for_ai_or_fanart():
    scorer = RiskScorer()
    result = scorer.score(
        [
            Evidence(
                source=EvidenceSource.WEB_DETECTION,
                reason="Web entity matched character",
                confidence=0.94,
                data={"entity": "유명 웹툰 캐릭터", "category": "character"},
            ),
            Evidence(
                source=EvidenceSource.WEB_DETECTION,
                reason="Matching image URL found",
                confidence=0.9,
                data={"url": "https://example.com/official-character"},
            ),
        ]
    )

    assert result.score >= 70
    assert result.band == "high"
    assert "Web entity matched character" in result.reasons


def test_failure_reason_does_not_lower_existing_high_risk_score():
    scorer = RiskScorer()
    high_without_failure = scorer.score(
        [
            Evidence(
                source=EvidenceSource.FINGERPRINT,
                reason="Prior rejected image similarity 0.96",
                confidence=0.96,
                data={"similarity": 0.96},
            )
        ]
    )
    with_failure = scorer.score(
        [
            Evidence(
                source=EvidenceSource.FINGERPRINT,
                reason="Prior rejected image similarity 0.96",
                confidence=0.96,
                data={"similarity": 0.96},
            ),
            Evidence(
                source=EvidenceSource.FAILURE,
                reason="External API failed",
                confidence=1.0,
                data={},
            ),
        ]
    )

    assert with_failure.score >= high_without_failure.score
    assert "External API failed" in with_failure.reasons
    assert isinstance(with_failure, ScoreResult)


def test_promoted_naver_search_evidence_can_raise_review_risk():
    result = RiskScorer().score(
        [
            Evidence(
                source=EvidenceSource.NAVER_SEARCH,
                reason="Naver result linked named work",
                confidence=0.8,
                data={
                    "promoted": True,
                    "promotion_reason": "named person/work search evidence",
                },
            )
        ]
    )

    assert result.band == "medium"
    assert result.score >= 35
    assert "Naver result linked named work" in result.reasons


def test_llm_summary_does_not_directly_affect_score():
    result = RiskScorer().score(
        [
            Evidence(
                source=EvidenceSource.LLM_SUMMARY,
                reason="Assistant thinks this is famous",
                confidence=1.0,
                data={"verified": False},
            )
        ]
    )

    assert result.score == 0
    assert result.band == "low"
    assert result.reasons == []


def test_google_best_guess_label_alone_does_not_create_risk_reason():
    result = RiskScorer().score(
        [
            Evidence(
                source=EvidenceSource.WEB_DETECTION,
                reason="Best guess label gentleman",
                confidence=0.6,
                data={"label": "gentleman"},
            )
        ]
    )

    assert result.score == 0
    assert result.band == "low"
    assert result.reasons == []


def test_multiple_google_visual_similar_results_do_not_stack_into_high_risk():
    result = RiskScorer().score(
        [
            Evidence(
                source=EvidenceSource.FACE_PERSON,
                reason="Face/person detected",
                confidence=0.8,
                data={"face_count": 1},
            ),
            *[
                Evidence(
                    source=EvidenceSource.WEB_DETECTION,
                    reason="Google visually similar image found",
                    confidence=0.55,
                    data={"match": "visual", "url": f"https://example.test/{index}.jpg"},
                )
                for index in range(10)
            ],
        ]
    )

    assert result.band == "medium"
    assert result.score < 70


def _fingerprint(similarity: float, reason: str = "Prior rejected image similarity") -> Evidence:
    return Evidence(
        source=EvidenceSource.FINGERPRINT,
        reason=reason,
        confidence=similarity,
        data={"similarity": similarity},
    )


def test_score_of_exactly_30_is_medium_not_low():
    # A single weak fingerprint contributes +30 — the medium boundary.
    result = RiskScorer().score([_fingerprint(0.5)])
    assert result.score == 30
    assert result.band == "medium"


def test_score_just_below_70_is_medium():
    # Face (+35) + weak fingerprint (+30) = 65.
    result = RiskScorer().score(
        [
            Evidence(source=EvidenceSource.FACE_PERSON, reason="Face/person detected", confidence=0.8, data={"face_count": 1}),
            _fingerprint(0.5),
        ]
    )
    assert result.score == 65
    assert result.band == "medium"


def test_score_of_exactly_70_is_high_not_medium():
    # Face (+35) + partial web detection (+35) = 70 — the high boundary.
    result = RiskScorer().score(
        [
            Evidence(source=EvidenceSource.FACE_PERSON, reason="Face/person detected", confidence=0.8, data={"face_count": 1}),
            Evidence(source=EvidenceSource.WEB_DETECTION, reason="Partial match", confidence=0.9, data={"match": "partial"}),
        ]
    )
    assert result.score == 70
    assert result.band == "high"


def test_score_is_clamped_to_100():
    # Strong fingerprint (+80) + full web detection (+45) = 125 -> clamped to 100.
    result = RiskScorer().score(
        [
            _fingerprint(0.95),
            Evidence(source=EvidenceSource.WEB_DETECTION, reason="Full match", confidence=0.9, data={"match": "full"}),
        ]
    )
    assert result.score == 100
    assert result.band == "high"
