"""T27B HTTP routes — CatalogService endpoints.

Per v4.0 §T27. The thin HTTP layer over app.catalog.service.CatalogService.
"""
from __future__ import annotations

from typing import Any

from fastapi import APIRouter, HTTPException
from pydantic import BaseModel, Field

from app.catalog.models import Chain
from app.catalog.service import get_catalog

router = APIRouter(prefix="/api/v1/catalog", tags=["catalog"])


# ── Request models ───────────────────────────────────────────────
class RagIngestRequest(BaseModel):
    content: str = Field(..., min_length=1)
    collection: str = "scam_intel"
    doc_id: str | None = None
    metadata: dict[str, Any] = Field(default_factory=dict)


class RagSearchRequest(BaseModel):
    query: str = Field(..., min_length=1)
    collection: str = "scam_intel"
    top_k: int = Field(default=5, ge=1, le=50)


class ResolveEntityRequest(BaseModel):
    wallet_id: str
    max_chains: int = Field(default=5, ge=1, le=20)


class FindRiskyTokensRequest(BaseModel):
    min_rug_count: int = Field(default=1, ge=1)
    chain: str | None = None
    limit: int = Field(default=50, ge=1, le=200)


class AttachRagRequest(BaseModel):
    chain: str
    address: str
    qdrant_point_id: str


# ── Health / introspection ───────────────────────────────────────
@router.get("/stats")
async def stats() -> dict:
    """Catalog stats: which stores are reachable + entity counts."""
    return await get_catalog().stats()


@router.get("/probe")
async def probe() -> dict:
    """Probe which stores are reachable from this container."""
    return await get_catalog().probe_stores()


# ── Token endpoints ─────────────────────────────────────────────
@router.get("/tokens/{chain}/{address}")
async def get_token(chain: str, address: str) -> dict:
    """Get a token by chain+address. Returns full Token model + provenance."""
    try:
        c = Chain(chain)
    except ValueError:
        raise HTTPException(400, f"unknown chain: {chain}")
    tok = await get_catalog().get_token(c, address)
    if not tok:
        raise HTTPException(404, "token not found")
    return tok.model_dump(mode="json")


@router.get("/tokens/{chain}/{address}/risk")
async def get_token_risk(chain: str, address: str) -> dict:
    """Recipe 3 — Real-time risk score. Composes Redis + Postgres + Neo4j."""
    try:
        c = Chain(chain)
    except ValueError:
        raise HTTPException(400, f"unknown chain: {chain}")
    return await get_catalog().get_token_risk(c, address)


@router.post("/tokens/risky-by-deployer")
async def risky_tokens(req: FindRiskyTokensRequest) -> dict:
    """Recipe 1 — Find tokens deployed by wallets with rug history."""
    chain_enum = None
    if req.chain:
        try:
            chain_enum = Chain(req.chain)
        except ValueError:
            raise HTTPException(400, f"unknown chain: {req.chain}")
    tokens = await get_catalog().find_tokens_by_deployer_history(
        min_rug_count=req.min_rug_count, chain=chain_enum, limit=req.limit
    )
    return {
        "count": len(tokens),
        "tokens": [t.model_dump(mode="json") for t in tokens],
    }


# ── Wallet endpoints ─────────────────────────────────────────────
@router.get("/wallets/{chain}/{address}")
async def get_wallet(chain: str, address: str) -> dict:
    try:
        c = Chain(chain)
    except ValueError:
        raise HTTPException(400, f"unknown chain: {chain}")
    w = await get_catalog().get_wallet(c, address)
    if not w:
        raise HTTPException(404, "wallet not found")
    return w.model_dump(mode="json")


# ── Entity resolution (Recipe 5) ────────────────────────────────
@router.post("/entities/resolve")
async def resolve_entity(req: ResolveEntityRequest) -> dict:
    """Cross-chain entity resolution via Neo4j Cypher."""
    return await get_catalog().resolve_entity(req.wallet_id, req.max_chains)


# ── RAG bridge endpoints ────────────────────────────────────────
@router.post("/rag/search")
async def rag_search(req: RagSearchRequest) -> dict:
    """Search the RAG system. Returns ranked hits with RRF scores."""
    hits = await get_catalog().rag_search(
        query=req.query, collection=req.collection, top_k=req.top_k
    )
    return {"count": len(hits), "hits": hits}


@router.post("/rag/ingest")
async def rag_ingest(req: RagIngestRequest) -> dict:
    """Ingest content into RAG. Returns qdrant_point_id for cross-store linking."""
    return await get_catalog().rag_ingest(
        content=req.content,
        collection=req.collection,
        doc_id=req.doc_id,
        metadata=req.metadata,
    )


@router.post("/tokens/{chain}/{address}/attach-rag")
async def attach_rag(chain: str, address: str, req: AttachRagRequest) -> dict:
    """Link an existing RAG embedding (Qdrant point) to a Token row."""
    try:
        c = Chain(chain)
    except ValueError:
        raise HTTPException(400, f"unknown chain: {chain}")
    ok = await get_catalog().attach_rag_to_token(c, address, req.qdrant_point_id)
    if not ok:
        raise HTTPException(404, "token not found or update failed")
    return {"ok": True, "chain": chain, "address": address, "rag_embedding_id": req.qdrant_point_id}
