import logging

from openai import AsyncOpenAI, OpenAI

from config import OPENAI_API_KEY

logger = logging.getLogger(__name__)

__all__ = [
    "create_embedding",
    "create_embedding_async",
    "create_embeddings_async",
    "get_async_embedding_client",
    "get_embedding_client",
]


class EmbeddingClientManager:
    """
    Singleton Class quản lý OpenAI Embedding Client (Sync & Async).
    Supports both env key and user-specific keys.
    """

    def __init__(self):
        self._client: OpenAI | None = None
        self._async_client: AsyncOpenAI | None = None
        self._user_clients: dict[str, AsyncOpenAI] = {}  # Cache per user_id

    def get_client(self, api_key: str | None = None) -> OpenAI:
        """
        Sync Client lazy loading.
        
        Args:
            api_key: Optional API key. If provided, creates client with this key.
                    Otherwise uses env OPENAI_API_KEY.
        """
        key = api_key or OPENAI_API_KEY
        if not key:
            raise RuntimeError("CRITICAL: OPENAI_API_KEY chưa được thiết lập")
        
        # If using default key, cache the client
        if not api_key:
            if self._client is None:
                self._client = OpenAI(api_key=key)
            return self._client

        # For custom keys, create new client (not cached)
        return OpenAI(api_key=key)

    def get_async_client(self, api_key: str | None = None, user_id: str | None = None) -> AsyncOpenAI:
        """
        Async Client lazy loading.
        
        Args:
            api_key: Optional API key. If provided, uses this key.
                    Otherwise uses env OPENAI_API_KEY.
            user_id: Optional user ID for caching user-specific clients.
        
        Returns:
            AsyncOpenAI client
        """
        key = api_key or OPENAI_API_KEY
        if not key:
            raise RuntimeError("CRITICAL: OPENAI_API_KEY chưa được thiết lập")
        
        # If using default key, cache the default client
        if not api_key:
            if self._async_client is None:
                self._async_client = AsyncOpenAI(api_key=key)
            return self._async_client
        
        # For user-specific keys, cache per user_id
        if user_id and user_id in self._user_clients:
            return self._user_clients[user_id]
        
        client = AsyncOpenAI(api_key=key)
        if user_id:
            self._user_clients[user_id] = client
        return client




# NOTE:
# - TẠM THỜI KHÔNG DÙNG REDIS CACHE CHO EMBEDDING để tránh phụ thuộc Redis/aioredis.
# - Nếu cần bật lại cache, import `redis_cache` từ `common.cache`
#   và dùng như các đoạn code cũ (get_embedding / set_embedding).

# --- Singleton ---
_manager = EmbeddingClientManager()
get_embedding_client = _manager.get_client
get_async_embedding_client = _manager.get_async_client


def create_embedding(text: str) -> list[float]:
    """Sync embedding generation (No cache for sync to avoid overhead)"""
    try:
        client = get_embedding_client()
        response = client.embeddings.create(model="text-embedding-3-small", input=text)
        return response.data[0].embedding
    except Exception as e:
        logger.error(f"Error creating embedding (sync): {e}")
        return []


async def create_embedding_async(text: str, user_id: str | None = None) -> list[float]:
    """
    Async embedding generation (KHÔNG dùng cache).
    Nếu sau này cần cache lại, có thể thêm redis_cache.get_embedding / set_embedding.
    
    Args:
        text: Text to embed
        user_id: Optional user ID. If provided, will use user's API key if available.
    
    Returns:
        Embedding vector
    """
    try:
        api_key = None
        if user_id:
            # Try to get user's API key
            from common.memos_core.services import get_user_settings_service
            settings_service = get_user_settings_service()
            api_key = await settings_service.get_openai_api_key(user_id)
        
        client = _manager.get_async_client(api_key=api_key, user_id=user_id)
        response = await client.embeddings.create(model="text-embedding-3-small", input=text)
        embedding = response.data[0].embedding
        return embedding
    except Exception as e:
        logger.error(f"Error creating embedding (async): {e}")
        return []


async def create_embeddings_async(texts: list[str], user_id: str | None = None) -> list[list[float]]:
    """
    Batch async embedding generation with per-item Layer 2 Cache.
    
    Args:
        texts: List of texts to embed
        user_id: Optional user ID. If provided, will use user's API key if available.
    
    Returns:
        List of embedding vectors
    """
    try:
        if not texts:
            return []

        api_key = None
        if user_id:
            # Try to get user's API key
            from common.memos_core.services import get_user_settings_service
            settings_service = get_user_settings_service()
            api_key = await settings_service.get_openai_api_key(user_id)

        client = _manager.get_async_client(api_key=api_key, user_id=user_id)
        response = await client.embeddings.create(model="text-embedding-3-small", input=texts)

        # Giữ nguyên thứ tự embedding theo order input
        sorted_data = sorted(response.data, key=lambda x: x.index)
        results = [item.embedding for item in sorted_data]

        return results
    except Exception as e:
        logger.error(f"Error creating batch embeddings (async): {e}")
        return [[] for _ in texts]
