"""
Qdrant Vector Database Service
Manages idea storage and similarity search using Qdrant
"""
import httpx
from typing import List, Dict, Optional, Any
from pydantic import BaseModel
from src.utils import initialize_a_logger
import ollama
import uuid
from datetime import datetime

class Idea(BaseModel):
    """Idea model for storage"""
    id: str
    title: str
    description: str
    category: Optional[str] = None
    created_at: str
    embedding: Optional[List[float]] = None

class QdrantService:
    """Service for managing ideas in Qdrant vector database"""
    
    def __init__(self, qdrant_url: Optional[str] = None, collection_name: str = "ump_ideas"):
        # Try Docker service name first, fallback to localhost
        import os
        self.qdrant_url = qdrant_url or os.getenv("QDRANT_URL", "http://localhost:6333")
        self.collection_name = collection_name
        self.logger = initialize_a_logger('./logs/QdrantService.log')
        self.embedding_model = "embeddinggemma:300m"
        
    async def initialize_collection(self):
        """Initialize Qdrant collection if it doesn't exist"""
        try:
            # Check if collection exists
            async with httpx.AsyncClient() as client:
                response = await client.get(
                    f"{self.qdrant_url}/collections/{self.collection_name}"
                )
                if response.status_code == 200:
                    self.logger.info(f"Collection {self.collection_name} already exists")
                    return
                
                # Create collection if it doesn't exist
                if response.status_code == 404:
                    self.logger.info(f"Creating collection {self.collection_name}")
                    # First, get embedding dimension by generating a test embedding
                    try:
                        test_embedding = await self.generate_embedding("test")
                        vector_size = len(test_embedding)
                        self.logger.info(f"Detected embedding dimension: {vector_size}")
                    except Exception as e:
                        self.logger.warning(f"Could not detect embedding size, using default: {e}")
                        vector_size = 768  # Default fallback
                    
                    create_response = await client.put(
                        f"{self.qdrant_url}/collections/{self.collection_name}",
                        json={
                            "vectors": {
                                "size": vector_size,
                                "distance": "Cosine"
                            }
                        }
                    )
                    if create_response.status_code in [200, 201]:
                        self.logger.info(f"Collection {self.collection_name} created successfully")
                    else:
                        self.logger.error(f"Failed to create collection: {create_response.text}")
        except Exception as e:
            self.logger.error(f"Error initializing collection: {e}", exc_info=True)
    
    async def generate_embedding(self, text: str) -> List[float]:
        """Generate vector embedding for text using Ollama"""
        try:
            # Generate embedding directly with text string
            response = ollama.embeddings(
                model=self.embedding_model,
                prompt=text
            )
            embedding = response.get("embedding", [])
            if not embedding:
                raise ValueError("Empty embedding returned")
            return embedding
        except Exception as e:
            self.logger.error(f"Error generating embedding: {e}", exc_info=True)
            raise
    
    async def add_idea(self, title: str, description: str, category: Optional[str] = None) -> Dict[str, Any]:
        """Add a new idea to the vector database"""
        try:
            # Generate embedding for the idea (combine title and description)
            idea_text = f"{title}\n{description}"
            embedding = await self.generate_embedding(idea_text)
            
            # Create idea object
            idea_id = str(uuid.uuid4())
            idea = Idea(
                id=idea_id,
                title=title,
                description=description,
                category=category,
                created_at=datetime.now().isoformat(),
                embedding=embedding
            )
            
            # Store in Qdrant
            async with httpx.AsyncClient() as client:
                response = await client.put(
                    f"{self.qdrant_url}/collections/{self.collection_name}/points",
                    json={
                        "points": [{
                            "id": idea_id,
                            "vector": embedding,
                            "payload": {
                                "title": title,
                                "description": description,
                                "category": category,
                                "created_at": idea.created_at
                            }
                        }]
                    }
                )
                
                if response.status_code in [200, 201]:
                    self.logger.info(f"Idea {idea_id} added successfully")
                    return {
                        "id": idea_id,
                        "title": title,
                        "description": description,
                        "category": category,
                        "created_at": idea.created_at,
                        "status": "success"
                    }
                else:
                    error_msg = f"Failed to add idea: {response.text}"
                    self.logger.error(error_msg)
                    raise Exception(error_msg)
                    
        except Exception as e:
            self.logger.error(f"Error adding idea: {e}", exc_info=True)
            raise
    
    async def search_similar_ideas(self, query_text: str, limit: int = 5, score_threshold: float = 0.5) -> List[Dict[str, Any]]:
        """Search for similar ideas using vector similarity"""
        try:
            # Generate embedding for query
            query_embedding = await self.generate_embedding(query_text)
            
            # Search in Qdrant
            async with httpx.AsyncClient() as client:
                response = await client.post(
                    f"{self.qdrant_url}/collections/{self.collection_name}/points/search",
                    json={
                        "vector": query_embedding,
                        "limit": limit,
                        "score_threshold": score_threshold,
                        "with_payload": True
                    }
                )
                
                if response.status_code == 200:
                    results = response.json()
                    similar_ideas = []
                    for result in results.get("result", []):
                        payload = result.get("payload", {})
                        similar_ideas.append({
                            "id": result.get("id"),
                            "title": payload.get("title", ""),
                            "description": payload.get("description", ""),
                            "category": payload.get("category"),
                            "created_at": payload.get("created_at"),
                            "similarity_score": result.get("score", 0.0)
                        })
                    self.logger.info(f"Found {len(similar_ideas)} similar ideas")
                    return similar_ideas
                else:
                    error_msg = f"Failed to search ideas: {response.text}"
                    self.logger.error(error_msg)
                    return []
                    
        except Exception as e:
            self.logger.error(f"Error searching ideas: {e}", exc_info=True)
            return []
    
    async def get_all_ideas(self, limit: int = 100) -> List[Dict[str, Any]]:
        """Get all ideas from the database"""
        try:
            async with httpx.AsyncClient() as client:
                response = await client.post(
                    f"{self.qdrant_url}/collections/{self.collection_name}/points/scroll",
                    json={
                        "limit": limit,
                        "with_payload": True
                    }
                )
                
                if response.status_code == 200:
                    data = response.json()
                    ideas = []
                    for point in data.get("result", {}).get("points", []):
                        payload = point.get("payload", {})
                        ideas.append({
                            "id": point.get("id"),
                            "title": payload.get("title", ""),
                            "description": payload.get("description", ""),
                            "category": payload.get("category"),
                            "created_at": payload.get("created_at")
                        })
                    return ideas
                else:
                    return []
        except Exception as e:
            self.logger.error(f"Error getting all ideas: {e}", exc_info=True)
            return []
    
    async def delete_idea(self, idea_id: str) -> bool:
        """Delete an idea from the database"""
        try:
            async with httpx.AsyncClient() as client:
                response = await client.post(
                    f"{self.qdrant_url}/collections/{self.collection_name}/points/delete",
                    json={
                        "points": [idea_id]
                    }
                )
                
                if response.status_code in [200, 201]:
                    self.logger.info(f"Idea {idea_id} deleted successfully")
                    return True
                else:
                    self.logger.error(f"Failed to delete idea: {response.text}")
                    return False
        except Exception as e:
            self.logger.error(f"Error deleting idea: {e}", exc_info=True)
            return False

# Global instance
_qdrant_service: Optional[QdrantService] = None

def get_qdrant_service() -> QdrantService:
    """Get or create Qdrant service instance"""
    global _qdrant_service
    if _qdrant_service is None:
        _qdrant_service = QdrantService()
    return _qdrant_service
