"""CCIP / region observability API (#114) — read-only, analysis-shaped.

So the work can be checked through an API as the agent fills in vectors: overall
coverage (regions by kind, how many images have figure CCIP vectors, which
characters have enough reference examples to match on) + a per-image drill-down
(its regions + the CCIP character matches it would get). Mirrors the heads
metrics endpoint; no GPU, just reads what's stored.
"""

from quart import Blueprint, jsonify
from sqlalchemy import distinct, func, select

from ..extensions import get_session
from ..models import ImageRegion, Tag, TagKind
from ..models.tag import image_tag
from ..services.ml.ccip import match_image

ccip_bp = Blueprint("ccip", __name__, url_prefix="/api/ccip")

_FIGURE_KINDS = ("face", "figure")


@ccip_bp.route("/overview", methods=["GET"])
async def overview():
    async with get_session() as session:
        by_kind = dict(
            (
                await session.execute(
                    select(ImageRegion.kind, func.count()).group_by(ImageRegion.kind)
                )
            ).all()
        )
        images_with_figure_ccip = (
            await session.execute(
                select(func.count(distinct(ImageRegion.image_record_id)))
                .where(ImageRegion.kind.in_(_FIGURE_KINDS))
                .where(ImageRegion.ccip_embedding.is_not(None))
            )
        ).scalar_one()
        # Concept-crop (SigLIP bag) coverage — how far the back-catalogue embed
        # has progressed, so the max-over-bag scorer's reach is checkable.
        images_with_concept_siglip = (
            await session.execute(
                select(func.count(distinct(ImageRegion.image_record_id)))
                .where(ImageRegion.kind == "concept")
                .where(ImageRegion.siglip_embedding.is_not(None))
            )
        ).scalar_one()
        # Per-character reference counts (no vectors loaded) — which characters
        # have enough examples to match on.
        ref_rows = (
            await session.execute(
                select(image_tag.c.tag_id, Tag.name, func.count())
                .select_from(ImageRegion)
                .join(
                    image_tag,
                    image_tag.c.image_record_id == ImageRegion.image_record_id,
                )
                .join(Tag, Tag.id == image_tag.c.tag_id)
                .where(Tag.kind == TagKind.character)
                .where(ImageRegion.kind.in_(_FIGURE_KINDS))
                .where(ImageRegion.ccip_embedding.is_not(None))
                .group_by(image_tag.c.tag_id, Tag.name)
                .order_by(func.count().desc())
            )
        ).all()
        versions = [
            v for (v,) in (
                await session.execute(
                    select(distinct(ImageRegion.embedding_version))
                )
            ).all() if v
        ]
        auto_applied = (
            await session.execute(
                select(func.count()).select_from(image_tag).where(
                    image_tag.c.source == "ccip_auto"
                )
            )
        ).scalar_one()
    return jsonify({
        "regions_by_kind": by_kind,
        "images_with_figure_ccip": images_with_figure_ccip,
        "images_with_concept_siglip": images_with_concept_siglip,
        "characters_with_references": len(ref_rows),
        "character_references": [
            {"tag_id": t, "name": n, "n_refs": c} for (t, n, c) in ref_rows
        ],
        "embedding_versions": versions,
        "auto_applied": auto_applied,
    })


@ccip_bp.route("/images/<int:image_id>", methods=["GET"])
async def image_detail(image_id: int):
    """An image's stored regions + the CCIP character matches it would get —
    for spot-checking the agent's output + the matcher."""
    async with get_session() as session:
        regions = (
            await session.execute(
                select(ImageRegion)
                .where(ImageRegion.image_record_id == image_id)
                .order_by(ImageRegion.id)
            )
        ).scalars().all()
        matches = await match_image(session, image_id)
    return jsonify({
        "image_id": image_id,
        "regions": [
            {
                "id": r.id,
                "kind": r.kind,
                "bbox": [r.rx, r.ry, r.rw, r.rh],
                "frame_time": r.frame_time,
                "score": r.score,
                "detector_version": r.detector_version,
                "embedding_version": r.embedding_version,
                "has_ccip": r.ccip_embedding is not None,
                "has_siglip": r.siglip_embedding is not None,
            }
            for r in regions
        ],
        "ccip_matches": matches,
    })
