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

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

import pytest
from unittest.mock import patch, MagicMock


class TestOpenAIEmbeddingsProviderMetadata:
    """Tests for OpenAIEmbeddingsProvider class metadata."""

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

        assert OpenAIEmbeddingsProvider.provider_name == "OpenAI"

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

        assert OpenAIEmbeddingsProvider.provider_key == "OPENAI"

    def test_requires_api_key(self):
        """Test that OpenAI requires API key."""
        from local_deep_research.embeddings.providers.implementations.openai import (
            OpenAIEmbeddingsProvider,
        )

        assert OpenAIEmbeddingsProvider.requires_api_key is True

    def test_supports_local(self):
        """Test that OpenAI does not support local."""
        from local_deep_research.embeddings.providers.implementations.openai import (
            OpenAIEmbeddingsProvider,
        )

        assert OpenAIEmbeddingsProvider.supports_local is False

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

        assert (
            OpenAIEmbeddingsProvider.default_model == "text-embedding-3-small"
        )


class TestOpenAIEmbeddingsProviderCreateEmbeddings:
    """Tests for OpenAIEmbeddingsProvider.create_embeddings method."""

    def test_create_embeddings_with_api_key(self):
        """Test creating embeddings with API key provided."""
        from local_deep_research.embeddings.providers.implementations.openai import (
            OpenAIEmbeddingsProvider,
        )

        mock_embeddings = MagicMock()

        # Mock get_setting_from_snapshot to return None for other settings
        with patch(
            "local_deep_research.embeddings.providers.implementations.openai.get_setting_from_snapshot",
            return_value=None,
        ):
            with patch(
                "langchain_openai.OpenAIEmbeddings",
                return_value=mock_embeddings,
            ) as mock_class:
                result = OpenAIEmbeddingsProvider.create_embeddings(
                    model="text-embedding-3-small",
                    api_key="test-api-key",
                )

                assert result is mock_embeddings
                mock_class.assert_called_once()
                call_kwargs = mock_class.call_args[1]
                assert call_kwargs["model"] == "text-embedding-3-small"
                assert call_kwargs["openai_api_key"] == "test-api-key"

    def test_create_embeddings_missing_api_key_raises(self):
        """Test that missing API key raises ValueError."""
        from local_deep_research.embeddings.providers.implementations.openai import (
            OpenAIEmbeddingsProvider,
        )

        with patch(
            "local_deep_research.embeddings.providers.implementations.openai.get_setting_from_snapshot",
            return_value=None,
        ):
            with pytest.raises(ValueError, match="API key not configured"):
                OpenAIEmbeddingsProvider.create_embeddings()

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

        mock_embeddings = MagicMock()
        settings = {"embeddings.openai.api_key": "snapshot-key"}

        def mock_get_setting(key, default=None, settings_snapshot=None):
            if key == "embeddings.openai.api_key":
                return "snapshot-key"
            return default

        with patch(
            "local_deep_research.embeddings.providers.implementations.openai.get_setting_from_snapshot",
            side_effect=mock_get_setting,
        ):
            with patch(
                "langchain_openai.OpenAIEmbeddings",
                return_value=mock_embeddings,
            ):
                result = OpenAIEmbeddingsProvider.create_embeddings(
                    settings_snapshot=settings
                )

                assert result is mock_embeddings

    def test_create_embeddings_with_base_url(self):
        """Test creating embeddings with custom base URL."""
        from local_deep_research.embeddings.providers.implementations.openai import (
            OpenAIEmbeddingsProvider,
        )

        mock_embeddings = MagicMock()

        with patch(
            "local_deep_research.embeddings.providers.implementations.openai.get_setting_from_snapshot",
            return_value=None,
        ):
            with patch(
                "langchain_openai.OpenAIEmbeddings",
                return_value=mock_embeddings,
            ) as mock_class:
                OpenAIEmbeddingsProvider.create_embeddings(
                    api_key="test-key",
                    base_url="https://custom.openai.com",
                )

                call_kwargs = mock_class.call_args[1]
                assert (
                    call_kwargs["openai_api_base"]
                    == "https://custom.openai.com"
                )

    def test_create_embeddings_with_dimensions(self):
        """Test creating embeddings with custom dimensions for v3 model."""
        from local_deep_research.embeddings.providers.implementations.openai import (
            OpenAIEmbeddingsProvider,
        )

        mock_embeddings = MagicMock()

        with patch(
            "local_deep_research.embeddings.providers.implementations.openai.get_setting_from_snapshot",
            return_value=None,
        ):
            with patch(
                "langchain_openai.OpenAIEmbeddings",
                return_value=mock_embeddings,
            ) as mock_class:
                OpenAIEmbeddingsProvider.create_embeddings(
                    model="text-embedding-3-small",
                    api_key="test-key",
                    dimensions=256,
                )

                call_kwargs = mock_class.call_args[1]
                assert call_kwargs["dimensions"] == 256

    def test_create_embeddings_dimensions_ignored_for_non_v3_model(self):
        """Test that dimensions are ignored for non-v3 models."""
        from local_deep_research.embeddings.providers.implementations.openai import (
            OpenAIEmbeddingsProvider,
        )

        mock_embeddings = MagicMock()

        with patch(
            "local_deep_research.embeddings.providers.implementations.openai.get_setting_from_snapshot",
            return_value=None,
        ):
            with patch(
                "langchain_openai.OpenAIEmbeddings",
                return_value=mock_embeddings,
            ) as mock_class:
                OpenAIEmbeddingsProvider.create_embeddings(
                    model="text-embedding-ada-002",
                    api_key="test-key",
                    dimensions=256,
                )

                call_kwargs = mock_class.call_args[1]
                assert "dimensions" not in call_kwargs


class TestOpenAIEmbeddingsProviderIsAvailable:
    """Tests for OpenAIEmbeddingsProvider.is_available method."""

    def test_is_available_with_api_key(self):
        """Test that provider is available when API key is set."""
        from local_deep_research.embeddings.providers.implementations.openai import (
            OpenAIEmbeddingsProvider,
        )

        with patch(
            "local_deep_research.embeddings.providers.implementations.openai.get_setting_from_snapshot",
            return_value="test-api-key",
        ):
            assert OpenAIEmbeddingsProvider.is_available() is True

    def test_is_available_without_api_key(self):
        """Test that provider is not available without API key."""
        from local_deep_research.embeddings.providers.implementations.openai import (
            OpenAIEmbeddingsProvider,
        )

        with patch(
            "local_deep_research.embeddings.providers.implementations.openai.get_setting_from_snapshot",
            return_value=None,
        ):
            assert OpenAIEmbeddingsProvider.is_available() is False

    def test_is_available_with_empty_api_key(self):
        """Test that provider is not available with empty API key."""
        from local_deep_research.embeddings.providers.implementations.openai import (
            OpenAIEmbeddingsProvider,
        )

        with patch(
            "local_deep_research.embeddings.providers.implementations.openai.get_setting_from_snapshot",
            return_value="",
        ):
            assert OpenAIEmbeddingsProvider.is_available() is False

    def test_is_available_exception_returns_false(self):
        """Test that exception during availability check returns False."""
        from local_deep_research.embeddings.providers.implementations.openai import (
            OpenAIEmbeddingsProvider,
        )

        with patch(
            "local_deep_research.embeddings.providers.implementations.openai.get_setting_from_snapshot",
            side_effect=Exception("Settings error"),
        ):
            assert OpenAIEmbeddingsProvider.is_available() is False


class TestOpenAIEmbeddingsProviderGetAvailableModels:
    """Tests for OpenAIEmbeddingsProvider.get_available_models method."""

    def test_get_available_models_success(self):
        """Test getting available models from OpenAI API."""
        from local_deep_research.embeddings.providers.implementations.openai import (
            OpenAIEmbeddingsProvider,
        )

        mock_model1 = MagicMock()
        mock_model1.id = "text-embedding-3-small"
        mock_model2 = MagicMock()
        mock_model2.id = "text-embedding-3-large"
        mock_model3 = MagicMock()
        mock_model3.id = "gpt-4"  # Not an embedding model

        mock_response = MagicMock()
        mock_response.data = [mock_model1, mock_model2, mock_model3]

        mock_client = MagicMock()
        mock_client.models.list.return_value = mock_response

        with patch(
            "local_deep_research.embeddings.providers.implementations.openai.get_setting_from_snapshot",
            return_value="test-api-key",
        ):
            with patch(
                "openai.OpenAI",
                return_value=mock_client,
            ):
                models = OpenAIEmbeddingsProvider.get_available_models()

                # Should only return embedding models
                assert len(models) == 2
                assert models[0]["value"] == "text-embedding-3-small"
                assert models[1]["value"] == "text-embedding-3-large"

    def test_get_available_models_no_api_key(self):
        """Test getting models returns empty list when no API key."""
        from local_deep_research.embeddings.providers.implementations.openai import (
            OpenAIEmbeddingsProvider,
        )

        with patch(
            "local_deep_research.embeddings.providers.implementations.openai.get_setting_from_snapshot",
            return_value=None,
        ):
            models = OpenAIEmbeddingsProvider.get_available_models()
            assert models == []

    def test_get_available_models_api_error(self):
        """Test getting models returns empty list on API error."""
        from local_deep_research.embeddings.providers.implementations.openai import (
            OpenAIEmbeddingsProvider,
        )

        with patch(
            "local_deep_research.embeddings.providers.implementations.openai.get_setting_from_snapshot",
            return_value="test-api-key",
        ):
            with patch(
                "openai.OpenAI",
                side_effect=Exception("API error"),
            ):
                models = OpenAIEmbeddingsProvider.get_available_models()
                assert models == []
