from abc import ABC, abstractmethod
from typing import List
import os
import requests
import json

class BaseEmbedding(ABC):
    """Abstract base class for embedding models"""

    @abstractmethod
    def embed_text(self, text: str) -> List[float]:
        """Embed a single text string"""
        pass

    @abstractmethod
    def embed_batch(self, texts: List[str]) -> List[List[float]]:
        """Embed a batch of texts"""
        pass

class GeminiEmbedding(BaseEmbedding):
    """Google Gemini embedding model"""

    def __init__(self, api_key: str, model: str = "text-embedding-004"):
        self.api_key = api_key
        self.model = model
        self.base_url = "https://generativelanguage.googleapis.com/v1beta/models"

    def embed_text(self, text: str) -> List[float]:
        """Embed a single text using Gemini API"""
        url = f"{self.base_url}/{self.model}:embedContent"

        headers = {
            "Content-Type": "application/json",
        }

        data = {
            "model": f"models/{self.model}",
            "content": {
                "parts": [{"text": text}]
            }
        }

        response = requests.post(
            f"{url}?key={self.api_key}",
            headers=headers,
            json=data
        )

        if response.status_code == 200:
            result = response.json()
            return result["embedding"]["values"]
        else:
            raise Exception(f"Embedding API error: {response.status_code} - {response.text}")

    def embed_batch(self, texts: List[str]) -> List[List[float]]:
        """Embed multiple texts"""
        embeddings = []
        for text in texts:
            embedding = self.embed_text(text)
            embeddings.append(embedding)
        return embeddings

class SimpleEmbedding(BaseEmbedding):
    """Simple fallback embedding using basic text features"""

    def __init__(self):
        # This is a fallback for when heavy dependencies aren't available
        pass

    def embed_text(self, text: str) -> List[float]:
        """Create a simple embedding based on text features"""
        # Simple bag-of-words style embedding (for testing only)
        import hashlib

        # Create a simple 384-dimensional embedding
        text_hash = hashlib.md5(text.encode()).hexdigest()

        # Convert hash to numeric values
        embedding = []
        for i in range(0, len(text_hash), 2):
            hex_pair = text_hash[i:i+2]
            embedding.append(int(hex_pair, 16) / 255.0 - 0.5)

        # Pad to 384 dimensions
        while len(embedding) < 384:
            embedding.extend(embedding[:min(len(embedding), 384 - len(embedding))])

        return embedding[:384]

    def embed_batch(self, texts: List[str]) -> List[List[float]]:
        """Embed multiple texts"""
        return [self.embed_text(text) for text in texts]

def get_embedding_model(config) -> BaseEmbedding:
    """Factory function to get the appropriate embedding model"""
    try:
        # Try to use Gemini embedding first
        return GeminiEmbedding(config.gemini_api_key)
    except Exception as e:
        print(f"Warning: Could not initialize Gemini embedding: {e}")
        print("Falling back to simple embedding for testing...")
        return SimpleEmbedding()