"""
Unit tests for NeuralDLP Python SDK

Tests individual components without requiring a running API.
"""
import pytest
from unittest.mock import Mock, patch
from neuraldlp import NeuralDLP
from neuraldlp.exceptions import (
    AuthenticationError,
    RateLimitError,
    ValidationError,
    NotFoundError,
    NeuralDLPError
)


class TestClient:
    """Test client initialization and configuration"""
    
    def test_client_initialization(self):
        """Client should initialize with correct defaults"""
        client = NeuralDLP(api_key="test_key")
        
        assert client.api_key == "test_key"
        assert "localhost" in client.base_url or "api.neuraldlp.com" in client.base_url
        assert client.timeout == 30
    
    def test_client_custom_config(self):
        """Client should accept custom configuration"""
        client = NeuralDLP(
            api_key="custom_key",
            base_url="https://custom.api.com",
            timeout=60
        )
        
        assert client.api_key == "custom_key"
        assert client.base_url == "https://custom.api.com"
        assert client.timeout == 60
    
    def test_client_strips_trailing_slash(self):
        """Base URL should have trailing slash removed"""
        client = NeuralDLP(
            api_key="test",
            base_url="https://api.example.com/"
        )
        
        assert not client.base_url.endswith("/")


class TestErrorHandling:
    """Test error handling logic"""
    
    @pytest.fixture
    def client(self):
        return NeuralDLP(api_key="test_key")
    
    def test_401_raises_authentication_error(self, client):
        """401 status should raise AuthenticationError"""
        mock_response = Mock()
        mock_response.status_code = 401
        
        with pytest.raises(AuthenticationError):
            client._handle_error(mock_response)
    
    def test_429_raises_rate_limit_error(self, client):
        """429 status should raise RateLimitError"""
        mock_response = Mock()
        mock_response.status_code = 429
        
        with pytest.raises(RateLimitError):
            client._handle_error(mock_response)
    
    def test_422_raises_validation_error(self, client):
        """422 status should raise ValidationError"""
        mock_response = Mock()
        mock_response.status_code = 422
        mock_response.text = "Invalid input"
        
        with pytest.raises(ValidationError):
            client._handle_error(mock_response)
    
    def test_404_raises_not_found_error(self, client):
        """404 status should raise NotFoundError"""
        mock_response = Mock()
        mock_response.status_code = 404
        mock_response.text = "Not found"
        
        with pytest.raises(NotFoundError):
            client._handle_error(mock_response)
    
    def test_500_raises_neuraldlp_error(self, client):
        """5xx status should raise NeuralDLPError"""
        mock_response = Mock()
        mock_response.status_code = 500
        
        with pytest.raises(NeuralDLPError):
            client._handle_error(mock_response)


class TestModels:
    """Test data model classes"""
    
    def test_entity_from_dict(self):
        """Entity should create from dictionary"""
        from neuraldlp.models import Entity
        
        data = {
            "type": "EMAIL",
            "value": "test@example.com",
            "start": 0,
            "end": 16,
            "confidence": 0.99
        }
        
        entity = Entity.from_dict(data)
        
        assert entity.type == "EMAIL"
        assert entity.value == "test@example.com"
        assert entity.start == 0
        assert entity.end == 16
        assert entity.confidence == 0.99
    
    def test_entity_to_dict(self):
        """Entity should serialize to dictionary"""
        from neuraldlp.models import Entity
        
        entity = Entity(
            type="SSN",
            value="123-45-6789",
            start=10,
            end=21,
            confidence=0.95
        )
        
        data = entity.to_dict()
        
        assert data["type"] == "SSN"
        assert data["value"] == "123-45-6789"
        assert data["start"] == 10
        assert data["end"] == 21
        assert data["confidence"] == 0.95
    
    def test_inspection_result_is_safe(self):
        """InspectionResult.is_safe() should check risk score"""
        from neuraldlp.models import InspectionResult
        
        # Safe content
        safe_result = InspectionResult(
            request_id="req_123",
            risk_score=25,
            entities=[],
            threats=[],
            matched_policies=[],
            recommended_action="ALLOW",
            processing_time_ms=10.0
        )
        
        assert safe_result.is_safe() is True
        
        # Risky content
        risky_result = InspectionResult(
            request_id="req_456",
            risk_score=75,
            entities=[],
            threats=[],
            matched_policies=[],
            recommended_action="BLOCK",
            processing_time_ms=10.0
        )
        
        assert risky_result.is_safe() is False
    
    def test_inspection_result_should_tokenize(self):
        """InspectionResult.should_tokenize() should check action"""
        from neuraldlp.models import InspectionResult
        
        result = InspectionResult(
            request_id="req_123",
            risk_score=50,
            entities=[],
            threats=[],
            matched_policies=[],
            recommended_action="TOKENIZE",
            processing_time_ms=10.0
        )
        
        assert result.should_tokenize() is True
    
    def test_inspection_result_is_blocked(self):
        """InspectionResult.is_blocked() should check action"""
        from neuraldlp.models import InspectionResult
        
        result = InspectionResult(
            request_id="req_123",
            risk_score=95,
            entities=[],
            threats=[],
            matched_policies=[],
            recommended_action="BLOCK",
            processing_time_ms=10.0
        )
        
        assert result.is_blocked() is True


class TestExceptions:
    """Test exception classes"""
    
    def test_base_exception(self):
        """NeuralDLPError should be base exception"""
        error = NeuralDLPError("Test error")
        
        assert isinstance(error, Exception)
        assert str(error) == "Test error"
    
    def test_authentication_error(self):
        """AuthenticationError should inherit from NeuralDLPError"""
        error = AuthenticationError("Invalid key")
        
        assert isinstance(error, NeuralDLPError)
        assert isinstance(error, Exception)
    
    def test_rate_limit_error(self):
        """RateLimitError should inherit from NeuralDLPError"""
        error = RateLimitError("Too many requests")
        
        assert isinstance(error, NeuralDLPError)
    
    def test_validation_error(self):
        """ValidationError should inherit from NeuralDLPError"""
        error = ValidationError("Invalid input")
        
        assert isinstance(error, NeuralDLPError)
    
    def test_not_found_error(self):
        """NotFoundError should inherit from NeuralDLPError"""
        error = NotFoundError("Resource not found")
        
        assert isinstance(error, NeuralDLPError)
