"""
Tests for the TranslationProvider base class and schemas.
"""

import pytest
from abc import ABC

from services.providers.base import TranslationProvider
from services.providers.schemas import (
    TranslationRequest,
    TranslationResponse,
    BatchTranslationRequest,
    BatchTranslationResponse,
    ProviderHealthStatus,
)


class ConcreteTranslationProvider(TranslationProvider):
    """Concrete implementation for testing abstract base class."""

    def __init__(self, name: str = "test", available: bool = True):
        self._name = name
        self._available = available

    def translate_text(self, request: TranslationRequest) -> TranslationResponse:
        return TranslationResponse(
            translated_text=f"[{request.target_language}] {request.text}",
            provider_name=self._name,
            from_cache=False,
        )

    def get_name(self) -> str:
        return self._name

    def is_available(self) -> bool:
        return self._available


class TestSchemas:
    """Tests for Pydantic schema models."""

    def test_translation_request_defaults(self):
        """Test TranslationRequest with default values."""
        request = TranslationRequest(text="Hello", target_language="fr")
        assert request.text == "Hello"
        assert request.target_language == "fr"
        assert request.source_language == "auto"

    def test_translation_request_custom_source(self):
        """Test TranslationRequest with custom source language."""
        request = TranslationRequest(
            text="Hello", target_language="fr", source_language="en"
        )
        assert request.source_language == "en"

    def test_translation_response_defaults(self):
        """Test TranslationResponse with default values."""
        response = TranslationResponse(translated_text="Bonjour", provider_name="test")
        assert response.translated_text == "Bonjour"
        assert response.provider_name == "test"
        assert response.from_cache is False
        assert response.source_language is None
        assert response.error is None
        assert response.success is True

    def test_translation_response_with_error(self):
        """Test TranslationResponse with error."""
        response = TranslationResponse(
            translated_text="Hello",
            provider_name="test",
            error="API Error",
        )
        assert response.error == "API Error"
        assert response.success is False

    def test_translation_request_invalid_language(self):
        """Test TranslationRequest rejects invalid language codes."""
        with pytest.raises(ValueError):
            TranslationRequest(text="Hello", target_language="invalid123")

    def test_batch_translation_request(self):
        """Test BatchTranslationRequest."""
        request = BatchTranslationRequest(
            texts=["Hello", "World"], target_language="fr"
        )
        assert len(request.texts) == 2
        assert request.source_language == "auto"

    def test_batch_translation_response(self):
        """Test BatchTranslationResponse."""
        response = BatchTranslationResponse(
            translated_texts=["Bonjour", "Monde"],
            provider_name="test",
            from_cache_count=1,
        )
        assert len(response.translated_texts) == 2
        assert response.from_cache_count == 1

    def test_provider_health_status(self):
        """Test ProviderHealthStatus."""
        status = ProviderHealthStatus(name="test", available=True, latency_ms=50.5)
        assert status.name == "test"
        assert status.available is True
        assert status.latency_ms == 50.5
        assert status.error is None

    def test_provider_health_status_with_error(self):
        """Test ProviderHealthStatus with error."""
        status = ProviderHealthStatus(
            name="test", available=False, error="Connection refused"
        )
        assert status.available is False
        assert status.error == "Connection refused"


class TestTranslationProviderBaseClass:
    """Tests for the TranslationProvider abstract base class."""

    def test_is_abstract(self):
        """Test that TranslationProvider cannot be instantiated directly."""
        assert issubclass(TranslationProvider, ABC)

        with pytest.raises(TypeError):
            TranslationProvider()

    def test_concrete_implementation_works(self):
        """Test that a concrete implementation can be instantiated."""
        provider = ConcreteTranslationProvider()
        assert provider.get_name() == "test"
        assert provider.is_available() is True

    def test_translate_text(self):
        """Test translate_text method."""
        provider = ConcreteTranslationProvider()
        request = TranslationRequest(text="Hello", target_language="fr")
        response = provider.translate_text(request)

        assert response.translated_text == "[fr] Hello"
        assert response.provider_name == "test"

    def test_translate_batch_default_implementation(self):
        """Test default translate_batch implementation."""
        provider = ConcreteTranslationProvider()
        requests = [
            TranslationRequest(text="Hello", target_language="fr"),
            TranslationRequest(text="World", target_language="fr"),
        ]
        responses = provider.translate_batch(requests)

        assert len(responses) == 2
        assert responses[0].translated_text == "[fr] Hello"
        assert responses[1].translated_text == "[fr] World"

    def test_health_check_available(self):
        """Test health_check for available provider."""
        provider = ConcreteTranslationProvider(available=True)
        status = provider.health_check()

        assert status.name == "test"
        assert status.available is True
        assert status.error is None
        assert status.latency_ms is not None

    def test_health_check_unavailable(self):
        """Test health_check for unavailable provider."""
        provider = ConcreteTranslationProvider(available=False)
        status = provider.health_check()

        assert status.available is False
        assert status.error == "Provider not available"

    def test_get_name_abstract(self):
        """Test that get_name is abstract."""
        assert "get_name" in TranslationProvider.__abstractmethods__

    def test_is_available_abstract(self):
        """Test that is_available is abstract."""
        assert "is_available" in TranslationProvider.__abstractmethods__

    def test_translate_text_abstract(self):
        """Test that translate_text is abstract."""
        assert "translate_text" in TranslationProvider.__abstractmethods__
