from typing import Optional, Dict, Any, List, Union
from enum import Enum
from datetime import datetime
from pydantic import BaseModel, Field, validator
from uuid import UUID, uuid4


class ModelType(str, Enum):
    TEXT = "text"
    TEXT_GENERATION = "text-generation"
    IMAGE_GENERATION = "image-generation"
    CODE_GENERATION = "code-generation"
    CHAT = "chat"
    EMBEDDING = "embedding"
    SPEECH_TO_TEXT = "speech-to-text"
    TEXT_TO_SPEECH = "text-to-speech"


class ProviderType(str, Enum):
    OPENAI = "openai"
    ANTHROPIC = "anthropic"
    HUGGINGFACE = "huggingface"
    COHERE = "cohere"
    LOCAL = "local"


class Request(BaseModel):
    id: UUID = Field(default_factory=uuid4)
    model: str
    provider: ProviderType
    type: ModelType
    prompt: str
    parameters: Dict[str, Any] = Field(default_factory=dict)
    metadata: Dict[str, Any] = Field(default_factory=dict)
    created_at: datetime = Field(default_factory=datetime.utcnow)


class Response(BaseModel):
    request_id: UUID
    content: Union[str, List[str], Dict[str, Any]]
    metadata: Dict[str, Any] = Field(default_factory=dict)
    created_at: datetime = Field(default_factory=datetime.utcnow)


class CacheEntry(BaseModel):
    request: Request
    response: Response
    similarity_score: float
    cached_at: datetime = Field(default_factory=datetime.utcnow)


class ProviderConfig(BaseModel):
    api_key: str
    base_url: Optional[str] = None
    timeout: float = 10.0
    max_retries: int = 3


class CacheConfig(BaseModel):
    enabled: bool = True
    max_size: int = 1000
    similarity_threshold: float = 0.8
    ttl_seconds: Optional[int] = None


class ModelConfig(BaseModel):
    provider: ProviderType
    model_name: str
    cache: CacheConfig = Field(default_factory=CacheConfig)
    provider_config: ProviderConfig
    temperature: float = 0.7
    max_tokens: Optional[int] = None
    top_p: float = 1.0
    frequency_penalty: float = 0.0
    presence_penalty: float = 0.0


class BatchRequest(BaseModel):
    requests: List[Request]
    batch_size: Optional[int] = 10
    max_concurrency: int = 5


class BatchResponse(BaseModel):
    results: List[Response]
    failed_requests: List[Request]
    total_time: float


class VectorData(BaseModel):
    vectors: List[List[float]]
    ids: List[str]
    metadata: List[Dict[str, Any]] = Field(default_factory=list)


class SimilarityResult(BaseModel):
    request_id: UUID
    similar_entries: List[CacheEntry]
    scores: List[float]
    best_match: Optional[CacheEntry] = None
    best_score: Optional[float] = None