"""
Tests for embeddings/providers/implementations/sentence_transformers.py

Tests cover:
- SentenceTransformersProvider.create_embeddings()
- SentenceTransformersProvider.is_available()
- SentenceTransformersProvider.get_available_models()
- Class attributes and metadata
"""

from unittest.mock import patch, MagicMock


class TestSentenceTransformersProviderMetadata:
    """Tests for SentenceTransformersProvider class metadata."""

    def test_provider_name(self):
        """Test provider name is set correctly."""
        from local_deep_research.embeddings.providers.implementations.sentence_transformers import (
            SentenceTransformersProvider,
        )

        assert (
            SentenceTransformersProvider.provider_name
            == "Sentence Transformers"
        )

    def test_provider_key(self):
        """Test provider key is set correctly."""
        from local_deep_research.embeddings.providers.implementations.sentence_transformers import (
            SentenceTransformersProvider,
        )

        assert (
            SentenceTransformersProvider.provider_key == "SENTENCE_TRANSFORMERS"
        )

    def test_requires_api_key(self):
        """Test that Sentence Transformers does not require API key."""
        from local_deep_research.embeddings.providers.implementations.sentence_transformers import (
            SentenceTransformersProvider,
        )

        assert SentenceTransformersProvider.requires_api_key is False

    def test_supports_local(self):
        """Test that Sentence Transformers supports local."""
        from local_deep_research.embeddings.providers.implementations.sentence_transformers import (
            SentenceTransformersProvider,
        )

        assert SentenceTransformersProvider.supports_local is True

    def test_default_model(self):
        """Test default model is set."""
        from local_deep_research.embeddings.providers.implementations.sentence_transformers import (
            SentenceTransformersProvider,
        )

        assert SentenceTransformersProvider.default_model == "all-MiniLM-L6-v2"


class TestSentenceTransformersProviderAvailableModels:
    """Tests for AVAILABLE_MODELS constant."""

    def test_available_models_has_expected_models(self):
        """Test that AVAILABLE_MODELS contains expected models."""
        from local_deep_research.embeddings.providers.implementations.sentence_transformers import (
            SentenceTransformersProvider,
        )

        models = SentenceTransformersProvider.AVAILABLE_MODELS

        assert "all-MiniLM-L6-v2" in models
        assert "all-mpnet-base-v2" in models
        assert "multi-qa-MiniLM-L6-cos-v1" in models
        assert "paraphrase-multilingual-MiniLM-L12-v2" in models

    def test_available_models_have_dimensions(self):
        """Test that all models have dimensions metadata."""
        from local_deep_research.embeddings.providers.implementations.sentence_transformers import (
            SentenceTransformersProvider,
        )

        for (
            model_name,
            model_info,
        ) in SentenceTransformersProvider.AVAILABLE_MODELS.items():
            assert "dimensions" in model_info
            assert isinstance(model_info["dimensions"], int)

    def test_available_models_have_description(self):
        """Test that all models have description metadata."""
        from local_deep_research.embeddings.providers.implementations.sentence_transformers import (
            SentenceTransformersProvider,
        )

        for (
            model_name,
            model_info,
        ) in SentenceTransformersProvider.AVAILABLE_MODELS.items():
            assert "description" in model_info
            assert isinstance(model_info["description"], str)

    def test_available_models_have_max_seq_length(self):
        """Test that all models have max_seq_length metadata."""
        from local_deep_research.embeddings.providers.implementations.sentence_transformers import (
            SentenceTransformersProvider,
        )

        for (
            model_name,
            model_info,
        ) in SentenceTransformersProvider.AVAILABLE_MODELS.items():
            assert "max_seq_length" in model_info
            assert isinstance(model_info["max_seq_length"], int)


class TestSentenceTransformersProviderCreateEmbeddings:
    """Tests for SentenceTransformersProvider.create_embeddings method."""

    def test_create_embeddings_default_model(self):
        """Test creating embeddings with default model."""
        from local_deep_research.embeddings.providers.implementations.sentence_transformers import (
            SentenceTransformersProvider,
        )

        mock_embeddings = MagicMock()

        def mock_get_setting(key, default=None, settings_snapshot=None):
            # Return None to use default model
            return default

        with patch(
            "local_deep_research.embeddings.providers.implementations.sentence_transformers.get_setting_from_snapshot",
            side_effect=mock_get_setting,
        ):
            with patch(
                "langchain_community.embeddings.SentenceTransformerEmbeddings",
                return_value=mock_embeddings,
            ) as mock_class:
                result = SentenceTransformersProvider.create_embeddings()

                assert result is mock_embeddings
                mock_class.assert_called_once()
                call_kwargs = mock_class.call_args[1]
                # Default model should be used
                assert call_kwargs["model_name"] == "all-MiniLM-L6-v2"
                # CPU is default device
                assert call_kwargs["model_kwargs"]["device"] == "cpu"

    def test_create_embeddings_with_custom_model(self):
        """Test creating embeddings with custom model."""
        from local_deep_research.embeddings.providers.implementations.sentence_transformers import (
            SentenceTransformersProvider,
        )

        mock_embeddings = MagicMock()

        with patch(
            "langchain_community.embeddings.SentenceTransformerEmbeddings",
            return_value=mock_embeddings,
        ) as mock_class:
            SentenceTransformersProvider.create_embeddings(
                model="all-mpnet-base-v2"
            )

            call_kwargs = mock_class.call_args[1]
            assert call_kwargs["model_name"] == "all-mpnet-base-v2"

    def test_create_embeddings_with_device(self):
        """Test creating embeddings with specific device."""
        from local_deep_research.embeddings.providers.implementations.sentence_transformers import (
            SentenceTransformersProvider,
        )

        mock_embeddings = MagicMock()

        with patch(
            "local_deep_research.embeddings.providers.implementations.sentence_transformers.get_setting_from_snapshot",
            return_value=None,
        ):
            with patch(
                "langchain_community.embeddings.SentenceTransformerEmbeddings",
                return_value=mock_embeddings,
            ) as mock_class:
                SentenceTransformersProvider.create_embeddings(device="cuda")

                call_kwargs = mock_class.call_args[1]
                assert call_kwargs["model_kwargs"]["device"] == "cuda"

    def test_create_embeddings_default_device_cpu(self):
        """Test that default device is CPU."""
        from local_deep_research.embeddings.providers.implementations.sentence_transformers import (
            SentenceTransformersProvider,
        )

        mock_embeddings = MagicMock()

        def mock_get_setting(key, default=None, settings_snapshot=None):
            if key == "embeddings.sentence_transformers.device":
                return "cpu"
            return default

        with patch(
            "local_deep_research.embeddings.providers.implementations.sentence_transformers.get_setting_from_snapshot",
            side_effect=mock_get_setting,
        ):
            with patch(
                "langchain_community.embeddings.SentenceTransformerEmbeddings",
                return_value=mock_embeddings,
            ) as mock_class:
                SentenceTransformersProvider.create_embeddings()

                call_kwargs = mock_class.call_args[1]
                assert call_kwargs["model_kwargs"]["device"] == "cpu"

    def test_create_embeddings_with_settings_snapshot(self):
        """Test creating embeddings with settings snapshot."""
        from local_deep_research.embeddings.providers.implementations.sentence_transformers import (
            SentenceTransformersProvider,
        )

        mock_embeddings = MagicMock()
        # search.tool present => a public primary resolves PUBLIC_ONLY
        # => require_local stays off, so this model-reading test is not
        # diverted into the require-local download guard.
        settings = {
            "embeddings.sentence_transformers.model": "custom-model",
            "search.tool": "searxng",
        }

        def mock_get_setting(key, default=None, settings_snapshot=None):
            if key == "embeddings.sentence_transformers.model":
                return "custom-model"
            if key == "embeddings.sentence_transformers.device":
                return "cpu"
            return default

        with patch(
            "local_deep_research.embeddings.providers.implementations.sentence_transformers.get_setting_from_snapshot",
            side_effect=mock_get_setting,
        ):
            with patch(
                "langchain_community.embeddings.SentenceTransformerEmbeddings",
                return_value=mock_embeddings,
            ) as mock_class:
                SentenceTransformersProvider.create_embeddings(
                    settings_snapshot=settings
                )

                call_kwargs = mock_class.call_args[1]
                assert call_kwargs["model_name"] == "custom-model"


class TestSentenceTransformersProviderIsAvailable:
    """Tests for SentenceTransformersProvider.is_available method."""

    def test_is_available_always_true(self):
        """Test that Sentence Transformers is always available."""
        from local_deep_research.embeddings.providers.implementations.sentence_transformers import (
            SentenceTransformersProvider,
        )

        assert SentenceTransformersProvider.is_available() is True

    def test_is_available_with_settings_snapshot(self):
        """Test that is_available works with settings snapshot."""
        from local_deep_research.embeddings.providers.implementations.sentence_transformers import (
            SentenceTransformersProvider,
        )

        assert (
            SentenceTransformersProvider.is_available(
                settings_snapshot={"some": "settings"}
            )
            is True
        )


class TestSentenceTransformersProviderGetAvailableModels:
    """Tests for SentenceTransformersProvider.get_available_models method."""

    def test_get_available_models_returns_list(self):
        """Test that get_available_models returns a list."""
        from local_deep_research.embeddings.providers.implementations.sentence_transformers import (
            SentenceTransformersProvider,
        )

        models = SentenceTransformersProvider.get_available_models()
        assert isinstance(models, list)

    def test_get_available_models_has_correct_structure(self):
        """Test that models have value and label keys."""
        from local_deep_research.embeddings.providers.implementations.sentence_transformers import (
            SentenceTransformersProvider,
        )

        models = SentenceTransformersProvider.get_available_models()

        for model in models:
            assert "value" in model
            assert "label" in model
            assert isinstance(model["value"], str)
            assert isinstance(model["label"], str)

    def test_get_available_models_includes_dimensions_in_label(self):
        """Test that labels include dimension info."""
        from local_deep_research.embeddings.providers.implementations.sentence_transformers import (
            SentenceTransformersProvider,
        )

        models = SentenceTransformersProvider.get_available_models()

        for model in models:
            assert "d)" in model["label"]  # Dimensions indicator like "384d)"

    def test_get_available_models_matches_available_models_constant(self):
        """Test that returned models match AVAILABLE_MODELS."""
        from local_deep_research.embeddings.providers.implementations.sentence_transformers import (
            SentenceTransformersProvider,
        )

        models = SentenceTransformersProvider.get_available_models()
        model_values = [m["value"] for m in models]

        for (
            expected_model
        ) in SentenceTransformersProvider.AVAILABLE_MODELS.keys():
            assert expected_model in model_values
