"""PaddleOCR Remote Service — PP-OCRv4 on x86_64 (CPU)."""

import io
import logging
import os
import threading

import numpy as np
from fastapi import FastAPI, File, Header, HTTPException, UploadFile
from PIL import Image

logging.basicConfig(level=logging.INFO)
logger = logging.getLogger(__name__)

app = FastAPI(title="PaddleOCR Service")

_engine = None
_ready = False
_loading = False
API_KEY = os.environ.get("PADDLEOCR_API_KEY", "")


def _load_model():
    """Load PaddleOCR model in background thread."""
    global _engine, _ready
    try:
        logger.info("Importing paddleocr...")
        from paddleocr import PaddleOCR

        logger.info("Loading PaddleOCR model (PP-OCRv4, lang=en)...")
        _engine = PaddleOCR(
            lang="en",
            use_angle_cls=True,
            show_log=False,
            enable_mkldnn=False,
            use_gpu=False,
        )
        logger.info("PaddleOCR model loaded — running warmup...")
        # Warmup with tiny image to trigger any lazy init
        dummy = np.ones((30, 100, 3), dtype=np.uint8) * 255
        _engine.ocr(dummy)
        _ready = True
        logger.info("PaddleOCR ready to serve")
    except Exception as e:
        logger.error(f"Failed to load PaddleOCR: {e}", exc_info=True)


@app.on_event("startup")
def startup_load_model():
    """Start model loading in background so health check passes immediately."""
    global _loading
    _loading = True
    threading.Thread(target=_load_model, daemon=True).start()
    logger.info("Model loading started in background thread")


@app.get("/health")
def health():
    if _ready:
        return {"status": "ok", "model": "PP-OCRv4"}
    if _loading:
        return {"status": "loading"}
    return {"status": "error"}


@app.post("/ocr")
async def ocr(
    file: UploadFile = File(...),
    x_api_key: str = Header(default=""),
):
    if API_KEY and x_api_key != API_KEY:
        raise HTTPException(status_code=401, detail="Invalid API key")

    if not _ready:
        raise HTTPException(status_code=503, detail="Model still loading")

    img_bytes = await file.read()
    img = Image.open(io.BytesIO(img_bytes)).convert("RGB")
    img_np = np.array(img)

    try:
        result = _engine.ocr(img_np)
    except Exception as e:
        logger.error(f"OCR failed: {e}", exc_info=True)
        raise HTTPException(status_code=500, detail=f"OCR failed: {e}")

    if not result or not result[0]:
        return {"words": [], "image_width": img_np.shape[1], "image_height": img_np.shape[0]}

    words = []
    for line in result[0]:
        box, (text, conf) = line[0], line[1]
        x_min = min(p[0] for p in box)
        y_min = min(p[1] for p in box)
        x_max = max(p[0] for p in box)
        y_max = max(p[1] for p in box)
        words.append({
            "text": str(text).strip(),
            "left": int(x_min),
            "top": int(y_min),
            "width": int(x_max - x_min),
            "height": int(y_max - y_min),
            "conf": round(float(conf) * 100, 1),
        })

    return {
        "words": words,
        "image_width": img_np.shape[1],
        "image_height": img_np.shape[0],
    }
