from __future__ import annotations

import pytest
from pydantic import ValidationError

from surfinguard.models import CheckResult, PrimitiveScore, HealthResponse
from surfinguard.enums import RiskLevel, RiskPrimitive


class TestCheckResult:
    def test_deserialize_from_camel_case(self):
        data = {
            "allow": True,
            "score": 3,
            "level": "CAUTION",
            "primitive": "MANIPULATION",
            "primitiveScores": [
                {"primitive": "MANIPULATION", "score": 3, "reasons": ["Suspicious"]}
            ],
            "reasons": ["Test reason"],
            "alternatives": None,
            "latencyMs": 1.5,
        }
        result = CheckResult.model_validate(data)
        assert result.allow is True
        assert result.score == 3
        assert result.level == RiskLevel.CAUTION
        assert result.primitive == RiskPrimitive.MANIPULATION
        assert len(result.primitive_scores) == 1
        assert result.primitive_scores[0].primitive == RiskPrimitive.MANIPULATION
        assert result.latency_ms == 1.5

    def test_deserialize_with_snake_case(self):
        data = {
            "allow": False,
            "score": 8,
            "level": "DANGER",
            "primitive": "DESTRUCTION",
            "primitive_scores": [
                {"primitive": "DESTRUCTION", "score": 8, "reasons": ["Bad"]}
            ],
            "reasons": ["Danger"],
            "latency_ms": 2.0,
        }
        result = CheckResult.model_validate(data)
        assert result.score == 8
        assert result.level == RiskLevel.DANGER

    def test_optional_fields_default(self):
        data = {
            "allow": True,
            "score": 0,
            "level": "SAFE",
            "primitive": None,
            "primitiveScores": [],
            "reasons": [],
            "latencyMs": 0.5,
        }
        result = CheckResult.model_validate(data)
        assert result.alternatives is None
        assert result.primitive is None

    def test_score_validation_min(self):
        with pytest.raises(ValidationError):
            CheckResult(
                allow=True, score=-1, level=RiskLevel.SAFE,
                primitive=None, primitive_scores=[], reasons=[], latency_ms=0
            )

    def test_score_validation_max(self):
        with pytest.raises(ValidationError):
            CheckResult(
                allow=True, score=11, level=RiskLevel.SAFE,
                primitive=None, primitive_scores=[], reasons=[], latency_ms=0
            )

    def test_enum_values_parsed(self):
        data = {
            "allow": False,
            "score": 7,
            "level": "DANGER",
            "primitive": "EXFILTRATION",
            "primitiveScores": [],
            "reasons": [],
            "latencyMs": 1.0,
        }
        result = CheckResult.model_validate(data)
        assert result.level == RiskLevel.DANGER
        assert result.primitive == RiskPrimitive.EXFILTRATION

    def test_all_primitives_parseable(self):
        for prim in RiskPrimitive:
            data = {
                "allow": False,
                "score": 5,
                "level": "CAUTION",
                "primitive": prim.value,
                "primitiveScores": [],
                "reasons": [],
                "latencyMs": 1.0,
            }
            result = CheckResult.model_validate(data)
            assert result.primitive == prim


class TestPrimitiveScore:
    def test_valid(self):
        ps = PrimitiveScore(primitive=RiskPrimitive.DESTRUCTION, score=8, reasons=["Bad"])
        assert ps.primitive == RiskPrimitive.DESTRUCTION
        assert ps.score == 8

    def test_score_clamped(self):
        with pytest.raises(ValidationError):
            PrimitiveScore(primitive=RiskPrimitive.DESTRUCTION, score=11, reasons=[])


class TestHealthResponse:
    def test_parse(self):
        data = {
            "ok": True,
            "version": "2.2.0",
            "analyzers": ["url", "command"],
            "auth": True,
            "llm": False,
            "uptime": 100,
        }
        h = HealthResponse.model_validate(data)
        assert h.ok is True
        assert h.version == "2.2.0"
        assert h.auth is True
        assert h.llm is False
