"""
tests/test_detector.py — Unit tests for the thin Litmus SDK client.

These tests mock requests.post so no real network calls are made.
"""

import os
import pytest
from unittest.mock import patch, MagicMock

from litmus_ai import LitmusDetector, LitmusResult
from litmus_ai.exceptions import LitmusAuthError, LitmusAPIError


# ── Fixtures ──────────────────────────────────────────────────────────────────

@pytest.fixture(autouse=True)
def set_api_key(monkeypatch):
    """Inject a fake API key for all tests."""
    monkeypatch.setenv("LITMUS_API_KEY", "lm-testkey123")


def _mock_response(status_code=200, json_data=None):
    mock = MagicMock()
    mock.status_code = status_code
    mock.ok = (status_code == 200)
    mock.json.return_value = json_data or {
        "score": 0.87,
        "is_hallucination": False,
        "details": {"metric": "context-grounding", "claim_scores": []}
    }
    mock.text = str(json_data)
    return mock


# ── Instantiation tests ───────────────────────────────────────────────────────

def test_detector_instantiation():
    detector = LitmusDetector()
    assert detector.type == "context-grounding"


def test_detector_invalid_type():
    with pytest.raises(ValueError, match="Invalid type"):
        LitmusDetector(type="nonexistent-type")


def test_detector_missing_api_key(monkeypatch):
    monkeypatch.delenv("LITMUS_API_KEY", raising=False)
    with pytest.raises(LitmusAuthError, match="LITMUS_API_KEY is not set"):
        LitmusDetector()


# ── Check request tests ────────────────────────────────────────────────────────

def test_check_sends_correct_payload():
    with patch("litmus_ai.detector.requests.post") as mock_post:
        mock_post.return_value = _mock_response()
        detector = LitmusDetector(type="context-grounding")
        detector.check(context="The sky is blue.", output="The sky is blue.")

        mock_post.assert_called_once()
        _, kwargs = mock_post.call_args
        payload = kwargs["json"]
        assert payload["type"] == "context-grounding"
        assert payload["context"] == "The sky is blue."
        assert payload["output"] == "The sky is blue."
        assert kwargs["headers"]["X-API-Key"] == "lm-testkey123"


def test_check_returns_litmus_result():
    with patch("litmus_ai.detector.requests.post") as mock_post:
        mock_post.return_value = _mock_response(json_data={
            "score": 0.91,
            "is_hallucination": False,
            "details": {}
        })
        detector = LitmusDetector()
        result = detector.check("context", "output")
        assert isinstance(result, LitmusResult)
        assert result.score == 0.91
        assert result.is_hallucination is False


def test_check_hallucination_true():
    with patch("litmus_ai.detector.requests.post") as mock_post:
        mock_post.return_value = _mock_response(json_data={
            "score": 0.2,
            "is_hallucination": True,
            "details": {}
        })
        detector = LitmusDetector()
        result = detector.check("context", "output")
        assert result.is_hallucination is True


def test_check_instruction_drift_requires_query():
    detector = LitmusDetector(type="instruction-drift")
    with pytest.raises(ValueError, match="query is required"):
        detector.check(context="ctx", output="out")


def test_check_instruction_drift_with_query():
    with patch("litmus_ai.detector.requests.post") as mock_post:
        mock_post.return_value = _mock_response()
        detector = LitmusDetector(type="instruction-drift")
        result = detector.check(context="ctx", output="out", query="Why?")
        assert isinstance(result, LitmusResult)


# ── Auth / error tests ────────────────────────────────────────────────────────

def test_check_401_raises_auth_error():
    with patch("litmus_ai.detector.requests.post") as mock_post:
        mock_post.return_value = _mock_response(status_code=401)
        detector = LitmusDetector()
        with pytest.raises(LitmusAuthError):
            detector.check("ctx", "out")


def test_check_500_raises_api_error():
    with patch("litmus_ai.detector.requests.post") as mock_post:
        mock_post.return_value = _mock_response(status_code=500)
        detector = LitmusDetector()
        with pytest.raises(LitmusAPIError) as exc_info:
            detector.check("ctx", "out")
        assert exc_info.value.status_code == 500
