from fastapi import FastAPI, HTTPException
from fastapi.responses import FileResponse
from fastapi.middleware.cors import CORSMiddleware
from pydantic import BaseModel
from pathlib import Path

from llama_index.core import VectorStoreIndex, SimpleDirectoryReader, Settings
from llama_index.llms.anthropic import Anthropic
from llama_index.embeddings.huggingface import HuggingFaceEmbedding

PDF_DIR = Path("pdfs")

app = FastAPI(title="LlamaIndex Q&A")

app.add_middleware(
    CORSMiddleware,
    allow_origins=["*"],
    allow_methods=["*"],
    allow_headers=["*"],
)

# Configure LlamaIndex to use Claude and a local embedding model
Settings.llm = Anthropic(model="claude-sonnet-4-6")
Settings.embed_model = HuggingFaceEmbedding(model_name="BAAI/bge-small-en-v1.5")


# Build the index once at startup
def build_index() -> VectorStoreIndex:
    if not PDF_DIR.exists() or not any(PDF_DIR.iterdir()):
        raise RuntimeError(
            f"No documents found in '{PDF_DIR}'. Add PDF files and restart."
        )
    documents = SimpleDirectoryReader(str(PDF_DIR)).load_data()
    return VectorStoreIndex.from_documents(documents)


try:
    _index = build_index()
    _query_engine = _index.as_query_engine(streaming=False)
    _ready = True
    print(f"Index built successfully from '{PDF_DIR}'.")
except RuntimeError as e:
    _ready = False
    _query_engine = None
    print(f"WARNING: {e}")


class Question(BaseModel):
    question: str


class Answer(BaseModel):
    answer: str


@app.get("/", response_class=FileResponse)
def serve_ui():
    return FileResponse("index.html", media_type="text/html")


@app.get("/health")
def health():
    return {"status": "ok", "index_ready": _ready}


@app.post("/ask", response_model=Answer)
def ask(body: Question):
    if not _ready or _query_engine is None:
        raise HTTPException(
            status_code=503,
            detail="Index not ready. Make sure the 'pdfs' folder contains documents and restart the server.",
        )
    if not body.question.strip():
        raise HTTPException(status_code=400, detail="Question must not be empty.")
    response = _query_engine.query(body.question)
    return Answer(answer=str(response))
