from fastapi import FastAPI, File, UploadFile
from fastapi.responses import JSONResponse
from anime_face_detector import create_detector
import numpy as np
import cv2
import os
import json
from datetime import datetime
from pathlib import Path

app = FastAPI(title="Anime Face Detector API")

# Create output directory
OUTPUT_DIR = Path("/app/api/outputs")
OUTPUT_DIR.mkdir(exist_ok=True)

# Load detector once at startup
detector = None

@app.on_event("startup")
async def startup_event():
    global detector
    detector = create_detector("yolov3", device="cuda:0")

@app.get("/")
async def root():
    return {"message": "Anime Face Detector API", "status": "running"}

@app.get("/health")
async def health():
    return {"status": "healthy", "detector_loaded": detector is not None}

@app.post("/detect")
async def detect_face(file: UploadFile = File(...)):
    try:
        if detector is None:
            return JSONResponse(
                status_code=503,
                content={"error": "Detector not initialized yet"}
            )
        
        image_bytes = await file.read()

        # Decode image
        nparr = np.frombuffer(image_bytes, np.uint8)
        img = cv2.imdecode(nparr, cv2.IMREAD_COLOR)
        
        if img is None:
            return JSONResponse(
                status_code=400,
                content={"error": "Invalid image file"}
            )

        # Run detector
        preds = detector(img)

        # Convert output to JSON-safe structure
        result = []
        for pred in preds:
            # bbox contains [x1, y1, x2, y2, score]
            bbox = pred['bbox']
            bbox_coords = bbox[:4].tolist()
            score = float(bbox[4])
            
            # keypoints contains [[x, y, score], ...]
            keypoints = pred.get('keypoints', [])
            landmarks = [[float(pt[0]), float(pt[1]), float(pt[2])] for pt in keypoints]
            
            result.append({
                "bbox": bbox_coords,
                "confidence": score,
                "keypoints": landmarks
            })

        # Draw detection results on image (like Gradio demo)
        annotated_img = img.copy()
        for pred in preds:
            box = pred['bbox']
            box_coords, score = box[:4], box[4]
            box_coords = np.round(box_coords).astype(int)
            
            # Calculate line thickness based on image size
            lt = max(2, int(3 * (box_coords[2:] - box_coords[:2]).max() / 256))
            
            # Draw bounding box
            cv2.rectangle(annotated_img, 
                         tuple(box_coords[:2]), 
                         tuple(box_coords[2:]), 
                         (0, 255, 0), lt)
            
            # Draw keypoints
            pred_pts = pred['keypoints']
            for *pt, kp_score in pred_pts:
                # Color based on keypoint confidence
                if kp_score < 0.3:  # Low confidence
                    color = (0, 255, 255)  # Yellow
                else:
                    color = (0, 0, 255)  # Red
                pt = np.round(pt).astype(int)
                cv2.circle(annotated_img, tuple(pt), lt, color, cv2.FILLED)
        
        # Generate unique filename based on timestamp
        timestamp = datetime.now().strftime("%Y%m%d_%H%M%S_%f")
        original_filename = Path(file.filename).stem if file.filename else "image"
        
        # Save annotated image
        image_output_path = OUTPUT_DIR / f"{original_filename}_{timestamp}_annotated.jpg"
        cv2.imwrite(str(image_output_path), annotated_img)
        
        # Save JSON results
        json_output_path = OUTPUT_DIR / f"{original_filename}_{timestamp}_results.json"
        json_data = {
            "filename": file.filename,
            "timestamp": timestamp,
            "detections": result,
            "count": len(result)
        }
        with open(json_output_path, 'w') as f:
            json.dump(json_data, f, indent=2)

        return {
            "detections": result, 
            "count": len(result),
            "annotated_image": str(image_output_path),
            "json_file": str(json_output_path)
        }
    
    except Exception as e:
        return JSONResponse(
            status_code=500,
            content={"error": str(e)}
        )
