import os
import shutil
import time
import logging
from typing import Optional
from fastapi import FastAPI, File, UploadFile, Form, HTTPException
from starlette.background import BackgroundTask
from fastapi.responses import JSONResponse
from fastapi.middleware.cors import CORSMiddleware
import service
from config import UPLOAD_FOLDER, PORT, HOST

logger = logging.getLogger("centralized_clip_service")

app = FastAPI(
    title="Centralized CLIP Vector Search Microservice",
    description="Centralized REST API microservice for visual search, image vector similarity, zero-shot validation, and FAISS indexing.",
    version="1.0.0"
)

# Enable CORS for all origins (can be accessed by PHP/Symfony/web applications)
app.add_middleware(
    CORSMiddleware,
    allow_origins=["*"],
    allow_credentials=True,
    allow_methods=["*"],
    allow_headers=["*"],
)

def cleanup_temp_file(file_path: str):
    if os.path.exists(file_path):
        try:
            os.remove(file_path)
            logger.info(f"Cleaned up temporary file: {file_path}")
        except Exception as e:
            logger.warning(f"Could not remove temporary file {file_path}: {e}")

@app.get("/")
@app.get("/health")
@app.get("/status")
def health_check():
    """
    Health check and index metadata endpoint.
    """
    status = service.get_status()
    return JSONResponse(content={
        "service": "Centralized CLIP Vector Search Microservice",
        "status": "online",
        "details": status
    })

@app.post("/search")
@app.post("/search-image")
async def search_image(
    file: UploadFile = File(...),
    top_k: int = Form(10),
    validate_jewelry: bool = Form(True)
):
    """
    Perform visual vector search on uploaded image.
    Returns matches as [[filename, score], ...]
    """
    start_time = time.time()
    if not file.filename:
        raise HTTPException(status_code=400, detail="Empty filename uploaded.")

    temp_filename = f"query_{int(time.time() * 1000)}_{file.filename}"
    temp_path = os.path.join(UPLOAD_FOLDER, temp_filename)

    try:
        with open(temp_path, "wb") as buffer:
            shutil.copyfileobj(file.file, buffer)

        logger.info(f"Received query image '{file.filename}', top_k={top_k}, validate={validate_jewelry}")
        
        matches = service.match_image(
            query_path=temp_path,
            top_k=top_k,
            validate_jewelry=validate_jewelry
        )

        elapsed = time.time() - start_time
        logger.info(f"Search executed in {elapsed:.3f}s. Found {len(matches)} matches.")

        return JSONResponse(
            content={"matches": matches},
            background=BackgroundTask(cleanup_temp_file, temp_path)
        )

    except ValueError as ve:
        cleanup_temp_file(temp_path)
        logger.warning(f"Validation failure for '{file.filename}': {ve}")
        return JSONResponse(
            status_code=400,
            content={"error": str(ve)}
        )
    except Exception as e:
        cleanup_temp_file(temp_path)
        logger.error(f"Search request failure: {e}", exc_info=True)
        return JSONResponse(
            status_code=500,
            content={"error": f"Internal search error: {str(e)}"}
        )

@app.post("/add-image")
async def add_image(file: UploadFile = File(...)):
    """
    Incrementally add a new design image vector to the FAISS index.
    """
    if not file.filename:
        raise HTTPException(status_code=400, detail="Empty filename uploaded.")

    temp_filename = f"add_{int(time.time() * 1000)}_{file.filename}"
    temp_path = os.path.join(UPLOAD_FOLDER, temp_filename)

    try:
        with open(temp_path, "wb") as buffer:
            shutil.copyfileobj(file.file, buffer)

        added = service.add_image_to_index(temp_path, original_filename=file.filename)
        cleanup_temp_file(temp_path)

        if added:
            return JSONResponse(content={
                "success": True,
                "message": f"Successfully indexed product image '{file.filename}'."
            })
        else:
            return JSONResponse(content={
                "success": False,
                "message": f"Product '{file.filename}' was skipped or already indexed."
            })

    except Exception as e:
        cleanup_temp_file(temp_path)
        logger.error(f"Incremental add failure: {e}", exc_info=True)
        return JSONResponse(
            status_code=500,
            content={"success": False, "error": str(e)}
        )

@app.post("/reindex")
async def reindex_gallery(gallery_dir: Optional[str] = Form(None)):
    """
    Trigger batch index rebuild for a gallery directory.
    """
    target_dir = gallery_dir if gallery_dir else service.DEFAULT_GALLERY_DIR
    logger.info(f"Triggering batch index rebuild for: {target_dir}")

    success, msg = service.rebuild_index(gallery_dir=target_dir)
    if success:
        return JSONResponse(content={"success": True, "message": msg})
    else:
        return JSONResponse(status_code=500, content={"success": False, "error": msg})

if __name__ == "__main__":
    import uvicorn
    logger.info(f"Starting Centralized FastAPI Microservice on http://{HOST}:{PORT}...")
    uvicorn.run("main:app", host=HOST, port=PORT, reload=False)
