"""
Pydantic models for RAG (Retrieval-Augmented Generation) metadata.
Handles automatic conversion between snake_case (backend) and camelCase (frontend).

This module is placed in common/ to be shared across different components
(agent tools, gateway, etc.) without creating cross-layer dependencies.
"""

from typing import Any, Dict, List, Optional
from pydantic import BaseModel, Field


class RAGSourceResponse(BaseModel):
    """Schema for RAG source with automatic snake_case to camelCase conversion"""
    citation_id: str = Field(..., alias="citationId", description="Unique citation ID")
    file_id: Optional[str] = Field(None, alias="fileId", description="File identifier")
    filename: Optional[str] = Field(None, description="Filename or title")
    title: Optional[str] = Field(None, description="Source title")
    source_type: Optional[str] = Field(None, alias="sourceType", description="Type of source (web, kb, etc.)")
    source_url: Optional[str] = Field(None, alias="sourceUrl", description="Source URL")
    url: Optional[str] = Field(None, description="Alternative URL field")
    content_preview: str = Field(..., alias="contentPreview", description="Preview of content")
    relevance_score: float = Field(..., alias="relevanceScore", description="Relevance score (0-1)")
    retrieved_at: Optional[str] = Field(None, alias="retrievedAt", description="Timestamp when retrieved")
    metadata: Dict[str, Any] = Field(default_factory=dict, description="Additional metadata")
    
    class Config:
        from_attributes = True
        populate_by_name = True  # Accept both snake_case and camelCase
        by_alias = True  # Serialize using aliases (camelCase)


class RAGQueryInfo(BaseModel):
    """Schema for query information in RAG metadata"""
    query: str = Field(..., description="Search query")
    timestamp: str = Field(..., description="Query timestamp")
    source_citation_ids: List[str] = Field(..., alias="sourceCitationIds", description="Citation IDs for this query")
    
    class Config:
        populate_by_name = True
        by_alias = True


class RAGMetadata(BaseModel):
    """Schema for RAG metadata"""
    queries: Optional[List[RAGQueryInfo]] = Field(None, description="Query breakdown for timeline")
    
    class Config:
        populate_by_name = True
        by_alias = True
        extra = "allow"  # Allow additional fields


class RAGSearchResultResponse(BaseModel):
    """Schema for RAG search result with automatic snake_case to camelCase conversion"""
    query: str = Field(..., description="Search query")
    title: Optional[str] = Field(None, description="Human-readable title for the research (generated by LLM)")
    search_type: str = Field(..., alias="searchType", description="Type of search (file_search, kb_search, deep_research, web_search)")
    turn_number: Optional[int] = Field(None, alias="turnNumber", description="Turn number for citation tracking")
    timestamp: str = Field(..., description="Search timestamp")
    sources: List[RAGSourceResponse] = Field(default_factory=list, description="List of sources")
    task_id: Optional[str] = Field(None, alias="taskId", description="Associated task ID")
    metadata: Optional[RAGMetadata] = Field(None, description="Additional metadata")
    
    class Config:
        from_attributes = True
        populate_by_name = True
        by_alias = True


def create_rag_source(
    citation_id: str,
    content_preview: str,
    relevance_score: float,
    file_id: Optional[str] = None,
    filename: Optional[str] = None,
    title: Optional[str] = None,
    source_type: Optional[str] = None,
    source_url: Optional[str] = None,
    url: Optional[str] = None,
    retrieved_at: Optional[str] = None,
    metadata: Optional[Dict[str, Any]] = None
) -> Dict[str, Any]:
    """
    Helper function to create a RAG source dict that will be automatically
    converted to camelCase when serialized through RAGSourceResponse.
    
    Returns a dict that can be passed to RAGSourceResponse for serialization.
    """
    source = RAGSourceResponse(
        citation_id=citation_id,
        file_id=file_id,
        filename=filename,
        title=title,
        source_type=source_type,
        source_url=source_url,
        url=url,
        content_preview=content_preview,
        relevance_score=relevance_score,
        retrieved_at=retrieved_at,
        metadata=metadata or {}
    )
    return source.model_dump(by_alias=True)


def create_rag_search_result(
    query: str,
    search_type: str,
    timestamp: str,
    sources: List[Dict[str, Any]],
    task_id: Optional[str] = None,
    turn_number: Optional[int] = None,
    metadata: Optional[Dict[str, Any]] = None,
    title: Optional[str] = None
) -> Dict[str, Any]:
    """
    Helper function to create a RAG search result dict that will be automatically
    converted to camelCase when serialized through RAGSearchResultResponse.
    
    Args:
        query: Search query
        search_type: Type of search (file_search, kb_search, deep_research, web_search)
        timestamp: Search timestamp
        sources: List of source dicts (will be converted to RAGSourceResponse)
        task_id: Optional task ID
        turn_number: Optional turn number
        metadata: Optional metadata dict
        title: Optional human-readable title (generated by LLM for deep research)
    
    Returns a dict with camelCase keys ready for frontend consumption.
    """
    # Convert source dicts to RAGSourceResponse for proper serialization
    source_responses = [RAGSourceResponse(**src) for src in sources]
    
    # Create metadata if provided
    rag_metadata = None
    if metadata:
        # Convert queries if present
        if "queries" in metadata:
            query_infos = [RAGQueryInfo(**q) for q in metadata["queries"]]
            rag_metadata = RAGMetadata(queries=query_infos, **{k: v for k, v in metadata.items() if k != "queries"})
        else:
            rag_metadata = RAGMetadata(**metadata)
    
    result = RAGSearchResultResponse(
        query=query,
        title=title,
        search_type=search_type,
        timestamp=timestamp,
        sources=source_responses,
        task_id=task_id,
        turn_number=turn_number,
        metadata=rag_metadata
    )
    
    return result.model_dump(by_alias=True)