"""
ChunkHive REST API
==================

FastAPI server exposing the full retrieval pipeline.
"""

from fastapi import FastAPI, HTTPException
from fastapi.middleware.cors import CORSMiddleware
from pydantic import BaseModel
from pathlib import Path
from typing import List, Optional
import logging

from chunkhive.retrieval.vector_store import VectorStore
from chunkhive.retrieval.retrieval_engine import RetrievalEngine

logger = logging.getLogger(__name__)

# =============================================================================
# REQUEST/RESPONSE MODELS
# =============================================================================

class SearchRequest(BaseModel):
    query: str
    index_path: str
    top_k: int = 5
    expand: bool = True

class ChunkResult(BaseModel):
    score: float
    confidence: float
    name: Optional[str]
    file_path: str
    chunk_type: str
    code: str

class SearchResponse(BaseModel):
    query: str
    results: List[ChunkResult]
    total_results: int

class QuestionRequest(BaseModel):
    question: str
    index_path: str
    context_size: int = 5

class QuestionResponse(BaseModel):
    question: str
    answer: str
    sources: List[str]

# =============================================================================
# API INITIALIZATION
# =============================================================================

app = FastAPI(
    title="ChunkHive API",
    description="Semantic code search with multi-signal ranking",
    version="0.3.1"
)

# Add CORS
app.add_middleware(
    CORSMiddleware,
    allow_origins=["*"],
    allow_credentials=True,
    allow_methods=["*"],
    allow_headers=["*"],
)

# Cache loaded indexes
_loaded_indexes = {}

def get_engine(index_path: str) -> RetrievalEngine:
    """Get or create retrieval engine for index."""
    if index_path not in _loaded_indexes:
        logger.info(f"Loading index: {index_path}")
        store = VectorStore(index_path=Path(index_path))
        store.load()
        engine = RetrievalEngine(
            vector_store=store,
            model_name="minilm",
            enable_expansion=True
        )
        _loaded_indexes[index_path] = engine
    return _loaded_indexes[index_path]

# =============================================================================
# ENDPOINTS
# =============================================================================

@app.get("/")
async def root():
    return {
        "service": "ChunkHive API",
        "version": "0.3.0",
        "status": "operational"
    }

@app.get("/health")
async def health():
    return {"status": "healthy", "loaded_indexes": len(_loaded_indexes)}

@app.post("/search", response_model=SearchResponse)
async def search(request: SearchRequest):
    """
    Semantic code search with multi-signal ranking.
    
    Returns ranked chunks with context expansion.
    """
    try:
        engine = get_engine(request.index_path)
        
        results = engine.search(
            query=request.query,
            top_k=request.top_k
        )
        
        # Format results
        formatted_results = []
        for r in results:
            chunk = r["chunk"]
            formatted_results.append(ChunkResult(
                score=r["score"],
                confidence=r["confidence"],
                name=chunk.ast.name,
                file_path=chunk.file_path,
                chunk_type=chunk.chunk_type,
                code=chunk.code
            ))
        
        return SearchResponse(
            query=request.query,
            results=formatted_results,
            total_results=len(results)
        )
        
    except FileNotFoundError:
        raise HTTPException(status_code=404, detail="Index not found")
    except Exception as e:
        logger.error(f"Search error: {e}")
        raise HTTPException(status_code=500, detail=str(e))

@app.post("/ask", response_model=QuestionResponse)
async def ask_question(request: QuestionRequest):
    """
    Ask questions about code using Claude + retrieval.
    
    Uses semantic search to find relevant code, then Claude to answer.
    """
    try:
        # Search for relevant code
        engine = get_engine(request.index_path)
        results = engine.search(
            query=request.question,
            top_k=request.context_size
        )
        
        if not results:
            return QuestionResponse(
                question=request.question,
                answer="No relevant code found.",
                sources=[]
            )
        
        # Build context
        context_parts = []
        sources = []
        
        for r in results:
            chunk = r["chunk"]
            context_parts.append(
                f"# {chunk.file_path}:{chunk.ast.name}\n{chunk.code}"
            )
            sources.append(f"{chunk.file_path}:{chunk.ast.name}")
        
        context = "\n\n".join(context_parts)
        
        # Call Claude (requires anthropic package)
        try:
            import anthropic
            
            client = anthropic.Anthropic()
            response = client.messages.create(
                model="claude-sonnet-4-20250514",
                max_tokens=1024,
                messages=[{
                    "role": "user",
                    "content": f"""Here is code from a repository:

{context}

Question: {request.question}

Please answer based on the code provided above."""
                }]
            )
            
            answer = response.content[0].text
            
        except ImportError:
            answer = "Claude integration not available. Install: pip install anthropic"
        
        return QuestionResponse(
            question=request.question,
            answer=answer,
            sources=sources
        )
        
    except Exception as e:
        logger.error(f"Q&A error: {e}")
        raise HTTPException(status_code=500, detail=str(e))

# =============================================================================
# RUN SERVER
# =============================================================================

if __name__ == "__main__":
    import uvicorn
    uvicorn.run(app, host="0.0.0.0", port=8000)