import importlib
import os
import unittest
from unittest.mock import patch

from analogai.foundation.common.design_patterns.singleton import Singleton
from analogai.foundation.common.utils.env_utils import load_envs_in_order
from analogai.foundation.settings import config


class TestEmbeddingServiceFunctionality(unittest.TestCase):
    def setUp(self):
        self._env_backup = dict(os.environ)
        load_envs_in_order()

    def tearDown(self):
        os.environ.clear()
        os.environ.update(self._env_backup)
        from analogai.foundation.infrastructure.services import embedding_service

        Singleton._instances.pop(embedding_service.EmbeddingService, None)

    def _reload_embedding_modules(self):
        from analogai.foundation.infrastructure.embeddings import provider_factory
        from analogai.foundation.infrastructure.services import embedding_service
        from analogai.foundation import settings

        importlib.reload(settings)
        importlib.reload(provider_factory)
        importlib.reload(embedding_service)
        return settings.config, provider_factory, embedding_service

    def test_embedding_provider_encode(self):
        _config, _provider_factory, embedding_service = self._reload_embedding_modules()
        environment = _config.get("ENVIRONMENT")
        use_vector_search = environment not in {"test", "testing"} and bool(
            _config.get("vector.enabled", True)
        )
        if not use_vector_search:
            self.skipTest("USE_VECTOR_SEARCH is false; skipping embedding tests")

        if str(_config.get("embed.type", "local")).strip().lower() == "local":
            try:
                import sentence_transformers  # noqa: F401
            except Exception as exc:
                self.fail(f"sentence_transformers is required for local embeddings: {exc}")

            os.environ.setdefault("EMBEDDING_MODEL_NAME", "all-MiniLM-L6-v2")
        elif str(_config.get("embed.type", "local")).strip().lower() == "api":
            provider = str(_config.get("embed.provider", "")).strip().lower()
            if provider not in {"openai", "azure_openai", "azure_foundry", "azure"}:
                self.fail(
                    "EMBEDDING_PROVIDER must be one of: openai, azure_openai, azure_foundry, azure"
                )
            if not _config.get("embed.model", ""):
                self.fail("EMBEDDING_MODEL_NAME must be set for API embeddings")
            if provider in {"openai"} and not _config.get("OPENAI_API_KEY", ""):
                self.fail("OPENAI_API_KEY is required for OpenAI embeddings")
            if provider in {"azure", "azure_openai"} and (
                not _config.get("AZURE_OPENAI_ENDPOINT", "")
                or not _config.get("AZURE_OPENAI_API_KEY", "")
            ):
                self.fail("AZURE_OPENAI_ENDPOINT and AZURE_OPENAI_API_KEY are required")
            if provider in {"azure_foundry"} and (
                not _config.get("AZURE_AI_FOUNDRY_ENDPOINT", "")
                or not _config.get("AZURE_AI_FOUNDRY_API_KEY", "")
            ):
                self.fail("AZURE_AI_FOUNDRY_ENDPOINT and AZURE_AI_FOUNDRY_API_KEY are required")
        else:
            self.fail("EMBEDDING_TYPE must be 'local' or 'api'")

        Singleton._instances.pop(embedding_service.EmbeddingService, None)
        service = embedding_service.EmbeddingService()
        vector = service.encode("hello")
        self.assertTrue(len(vector) > 0)

    def test_embedding_provider_batch_encode(self):
        _config, _provider_factory, embedding_service = self._reload_embedding_modules()
        environment = _config.get("ENVIRONMENT")
        use_vector_search = environment not in {"test", "testing"} and bool(
            _config.get("vector.enabled", True)
        )
        if not use_vector_search:
            self.skipTest("USE_VECTOR_SEARCH is false; skipping embedding tests")

        Singleton._instances.pop(embedding_service.EmbeddingService, None)
        service = embedding_service.EmbeddingService()
        batch = service.encode_batch(["a", "b"])
        self.assertEqual(len(batch), 2)
        self.assertTrue(len(batch[0]) > 0)


if __name__ == "__main__":
    unittest.main()
