import logging
import os
from fastapi import FastAPI, Request, status, HTTPException
from fastapi.middleware.cors import CORSMiddleware
from fastapi.staticfiles import StaticFiles
from fastapi.responses import JSONResponse, FileResponse
from fastapi.exceptions import RequestValidationError
from starlette.exceptions import HTTPException as StarletteHTTPException
from starlette.middleware.sessions import SessionMiddleware

logging.basicConfig(level=logging.INFO, format="%(asctime)s [%(levelname)s] %(name)s: %(message)s")
logger = logging.getLogger("chatbot.main")

import core.config as cfg
from routers import websocket, widget, api

app = FastAPI(
    title="AI Chatbot SaaS",
    description="Firebase-powered realtime SaaS dashboard with WebSocket chatbot.",
    version="2.0.0",
    docs_url="/docs",
    redoc_url="/redoc",
)

app.add_middleware(
    CORSMiddleware,
    allow_origins=cfg.ALLOWED_ORIGINS,
    allow_credentials=True,
    allow_methods=["*"],
    allow_headers=["*"],
)
app.add_middleware(SessionMiddleware, secret_key=cfg.JWT_SECRET_KEY if hasattr(cfg, 'JWT_SECRET_KEY') else "super-secret-default-key")

# Mount API routers
app.include_router(websocket.router)
app.include_router(widget.router)
app.include_router(api.router)

# Mount Static Files (Uploads, default logo)
os.makedirs("static", exist_ok=True)
app.mount("/static", StaticFiles(directory="static"), name="static")

@app.on_event("startup")
async def backfill_faq_embeddings():
    """Checks for FAQs lacking embeddings in Firestore and populates them."""
    try:
        from database.firebase_client import get_firestore
        from services.vector_service import get_provider_for_domain
        from services.ai_service import generate_embedding
        
        db = get_firestore()
        faq_docs = list(db.collection("faqs").stream())
        count = 0
        for doc in faq_docs:
            data = doc.to_dict()
            if not data.get("embedding"):
                domain_id = data.get("domain_id")
                if not domain_id:
                    continue
                provider = get_provider_for_domain(domain_id, db)
                text_to_embed = f"Question: {data.get('question', '')}\nAnswer: {data.get('answer', '')}"
                try:
                    embedding = await generate_embedding(text_to_embed, provider)
                    db.collection("faqs").document(doc.id).update({"embedding": embedding})
                    count += 1
                except Exception as ex:
                    logger.error(f"Failed to generate backfill embedding for FAQ {doc.id}: {ex}")
        if count > 0:
            logger.info(f"Successfully backfilled embeddings for {count} FAQs in Firestore.")
            
        # Check if ChromaDB collections are empty and reindex them if FAQs exist
        from services.vector_service import get_collection, reindex_domain
        domain_docs = list(db.collection("domains").stream())
        for d_doc in domain_docs:
            domain_id = d_doc.id
            try:
                collection = get_collection(domain_id, db)
                chroma_docs = collection.get()
                if len(chroma_docs.get('ids', [])) == 0:
                    faqs_count = len(list(db.collection("faqs").where("domain_id", "==", domain_id).limit(1).stream()))
                    if faqs_count > 0:
                        logger.info(f"Chroma collection for domain {domain_id} is empty. Triggering re-index...")
                        reindex_domain(domain_id, db)
            except Exception as re_err:
                logger.error(f"Failed to check/reindex Chroma for domain {domain_id}: {re_err}")
    except Exception as e:
        logger.error(f"Error during FAQ embedding backfill: {e}")


# Mount React frontend static assets if built
if os.path.exists("frontend/dist"):
    app.mount("/assets", StaticFiles(directory="frontend/dist/assets"), name="assets")

    @app.get("/{fallback_path:path}")
    async def serve_react_app(fallback_path: str):
        if fallback_path.startswith(("api/", "ws/", "widget/", "docs", "redoc", "openapi.json", "static/")):
            raise HTTPException(status_code=404, detail="Not Found")
        return FileResponse("frontend/dist/index.html")

@app.exception_handler(StarletteHTTPException)
async def http_exception_handler(request: Request, exc: StarletteHTTPException):
    return JSONResponse(status_code=exc.status_code, content={"success": False, "message": exc.detail})

@app.exception_handler(RequestValidationError)
async def validation_exception_handler(request: Request, exc: RequestValidationError):
    details = ", ".join([f"[{'->'.join(str(l) for l in e.get('loc',[]))}]: {e.get('msg')}" for e in exc.errors()])
    return JSONResponse(status_code=422, content={"success": False, "message": f"Validation failed: {details}"})

@app.exception_handler(Exception)
async def global_exception_handler(request: Request, exc: Exception):
    logger.critical(f"Unhandled error on {request.url.path}: {exc}", exc_info=True)
    return JSONResponse(status_code=500, content={"success": False, "message": "Internal server error."})
