"""
clawID REST API routes.

POST  /v1/embed           — embed watermark, returns watermarked image
POST  /v1/detect          — detect watermark, returns metadata JSON
GET   /v1/asset/{clawid}  — look up asset record from store
DELETE /v1/asset/{clawid} — remove asset record from store
GET   /health             — liveness check
"""

import io
import json
import tempfile
import os

from fastapi import APIRouter, Depends, File, Form, HTTPException, Request, UploadFile
from fastapi.responses import StreamingResponse
from PIL import Image

from ..core.embed import embed as _embed
from ..core.detect import detect as _detect
from .models import AssetResponse, DeleteResponse, DetectResponse, HealthResponse
from .. import __version__

router = APIRouter()


# ── dependency: pull store from app state ────────────────────────────────────

def _store(request: Request):
    return getattr(request.app.state, "store", None)


# ── embed ─────────────────────────────────────────────────────────────────────

@router.post(
    "/v1/embed",
    summary="Embed a clawID watermark into an image",
    response_class=StreamingResponse,
    responses={
        200: {
            "content": {"image/png": {}},
            "description": "Watermarked image. clawid UUID is in the X-ClawID header.",
        }
    },
)
async def embed_endpoint(
    image: UploadFile = File(..., description="Image to watermark (JPEG or PNG)"),
    uid: str | None = Form(None, description="Creator / user ID"),
    platform: str | None = Form(None, description="Platform name, e.g. hawky.ai"),
    asset_id: str | None = Form(None, description="Asset or generation ID"),
    mode: str = Form("invisible", description="invisible | visible | both"),
    extra_metadata: str = Form("{}", description="Additional metadata as JSON string"),
    store=Depends(_store),
):
    """
    Embed a clawID watermark into an image.

    Returns the watermarked image as PNG binary.
    The assigned `clawid` UUID is in the `X-ClawID` response header.
    If a store backend is configured, the metadata is also persisted.
    """
    # Parse metadata
    try:
        metadata = json.loads(extra_metadata)
    except json.JSONDecodeError:
        raise HTTPException(status_code=422, detail="extra_metadata must be valid JSON")

    if uid:
        metadata["uid"] = uid
    if platform:
        metadata["platform"] = platform
    if asset_id:
        metadata["asset_id"] = asset_id

    if not metadata:
        raise HTTPException(
            status_code=422,
            detail="Provide at least one of: uid, platform, asset_id, extra_metadata",
        )

    # Read uploaded image
    img_bytes = await image.read()
    try:
        pil_img = Image.open(io.BytesIO(img_bytes)).convert("RGB")
    except Exception:
        raise HTTPException(status_code=422, detail="Cannot parse uploaded file as an image")

    # Embed watermark
    out_path = tempfile.mktemp(suffix=".png")
    try:
        final_meta = _embed(pil_img, out_path, metadata, mode=mode)

        if store is not None:
            store.save(final_meta["clawid"], final_meta)

        with open(out_path, "rb") as f:
            img_data = f.read()
    except ValueError as exc:
        raise HTTPException(status_code=422, detail=str(exc))
    finally:
        if os.path.exists(out_path):
            os.unlink(out_path)

    return StreamingResponse(
        io.BytesIO(img_data),
        media_type="image/png",
        headers={
            "X-ClawID": final_meta["clawid"],
            "X-ClawID-Metadata": json.dumps(final_meta),
        },
    )


# ── detect ────────────────────────────────────────────────────────────────────

@router.post("/v1/detect", response_model=DetectResponse, summary="Detect a clawID watermark")
async def detect_endpoint(
    image: UploadFile = File(..., description="Image to analyse"),
    store=Depends(_store),
):
    """
    Detect a clawID watermark in an image.

    If a store is configured and the watermark contains a `clawid`,
    the response merges the embedded payload with the full DB record.
    """
    img_bytes = await image.read()
    try:
        pil_img = Image.open(io.BytesIO(img_bytes)).convert("RGB")
    except Exception:
        raise HTTPException(status_code=422, detail="Cannot parse uploaded file as an image")

    result = _detect(pil_img)

    if result is None:
        return DetectResponse(detected=False)

    # Enrich from store if available
    if store is not None and result.get("clawid"):
        db_meta = store.get(result["clawid"])
        if db_meta:
            result = {**result, **db_meta}

    return DetectResponse(detected=True, clawid=result.get("clawid"), metadata=result)


# ── asset lookup ──────────────────────────────────────────────────────────────

@router.get(
    "/v1/asset/{clawid}",
    response_model=AssetResponse,
    summary="Look up an asset by clawid",
)
def get_asset(clawid: str, store=Depends(_store)):
    if store is None:
        raise HTTPException(status_code=503, detail="No store configured on this server")
    metadata = store.get(clawid)
    if metadata is None:
        raise HTTPException(status_code=404, detail=f"Asset '{clawid}' not found")
    return AssetResponse(clawid=clawid, metadata=metadata)


@router.delete(
    "/v1/asset/{clawid}",
    response_model=DeleteResponse,
    summary="Delete an asset record",
)
def delete_asset(clawid: str, store=Depends(_store)):
    if store is None:
        raise HTTPException(status_code=503, detail="No store configured on this server")
    deleted = store.delete(clawid)
    if not deleted:
        raise HTTPException(status_code=404, detail=f"Asset '{clawid}' not found")
    return DeleteResponse(deleted=True, clawid=clawid)


# ── health ────────────────────────────────────────────────────────────────────

@router.get("/health", response_model=HealthResponse, summary="Liveness check")
def health(store=Depends(_store)):
    store_name = type(store).__name__ if store else None
    return HealthResponse(status="ok", version=__version__, store=store_name)
