"""
RugMaps API Router — RMI's interactive wallet visualization.
Self-contained engine, no BubbleMaps.com API dependency.
Connects to /api/v1/rugmaps/*
"""

import logging

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

logger = logging.getLogger(__name__)

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


class RugMapsRequest(BaseModel):
    center_wallet: str
    depth: int = 2
    min_strength: float = 0.1


def _get_rm():
    try:
        from app.bubble_maps import get_bubble_maps_pro

        return get_bubble_maps_pro()
    except ImportError as e:
        raise HTTPException(status_code=503, detail=f"Module unavailable: {e}")


@router.post("/map")
async def generate_rug_map(req: RugMapsRequest):
    """Generate interactive RugMap for a wallet (2-hop default)."""
    rm = _get_rm()
    try:
        result = await rm.generate_map(
            center_wallet=req.center_wallet, depth=min(req.depth, 5), min_strength=req.min_strength
        )
        return result.to_dict()
    except ValueError as e:
        raise HTTPException(status_code=400, detail=str(e))
    except Exception as e:
        raise HTTPException(status_code=500, detail=str(e)[:500])


@router.get("/analyze/{address}")
async def analyze_wallet(address: str, depth: int = Query(2, ge=1, le=5)):
    """Quick wallet analysis with RugMaps data."""
    rm = _get_rm()
    result = await rm.generate_map(center_wallet=address, depth=depth)
    d = result.to_dict()
    return {
        "address": address,
        "node_count": len(d.get("nodes", [])),
        "link_count": len(d.get("links", [])),
        "risk_level": d.get("risk_level", "unknown"),
        "risk_score": d.get("risk_score", 0),
        "stats": d.get("stats", {}),
        "top_counterparties": [n["address"][:12] + "..." for n in d.get("nodes", []) if n.get("layer") == 1][:10],
    }


@router.get("/entity/{address}")
async def get_entity_info(address: str):
    """Get entity information for an address."""
    rm = _get_rm()
    info = await rm._get_entity_info(address)
    risk, level = await rm._calculate_risk(address)
    return {"address": address, "entity": info, "risk_score": risk, "risk_level": level}


@router.get("/health")
async def rugmaps_health():
    return {"status": "ok", "service": "rugmaps-engine"}


@router.get("/token-graph")
async def token_holder_graph(
    token_address: str = Query(...),
    chain: str = Query("solana"),
    limit: int = Query(50, ge=5, le=200),
    skip_cache: bool = Query(False),
):
    """Generate a token holder graph with AI analysis and RAG caching.
    Uses DeepSeek Flash + our FAISS indexes + wallet labels + semantic cache."""
    import asyncio

    from app.rugmaps_ai import (
        generate_ai_analysis,
        generate_fallback_analysis,
        get_cached_analysis,
        get_token_holders,
        get_wallet_labels,
        search_similar_scams,
        set_cached_analysis,
    )

    # Check cache first (instant return for previously scanned tokens)
    if not skip_cache:
        cached = await get_cached_analysis(token_address, chain)
        if cached:
            logger.info(f"RugMaps cache HIT for {token_address[:12]}...")
            return {**cached, "from_cache": True}

    rm = _get_rm()

    # Get the bubble map concurrently with other data fetches
    try:
        result = await rm.generate_map(center_wallet=token_address, depth=3, min_strength=0.05)
        d = result.to_dict()
    except Exception as e:
        raise HTTPException(status_code=500, detail=f"Graph generation failed: {str(e)[:200]}")

    nodes = d.get("nodes", [])
    links = d.get("links", [])

    # Enrich nodes concurrently
    enriched_nodes = []
    addresses_for_labels = []
    for node in nodes[:limit]:
        addr = node.get("address") or node.get("id", "")
        addresses_for_labels.append(addr)
        enriched = dict(node)
        enriched["explorer_url"] = _get_explorer_url(chain, addr)
        enriched_nodes.append(enriched)

    # Fetch wallet labels and similar scams in parallel
    labels, similar_scams, holders = await asyncio.gather(
        get_wallet_labels(addresses_for_labels),
        search_similar_scams(token_address, chain),
        get_token_holders(token_address, chain),
        return_exceptions=True,
    )

    if isinstance(labels, Exception):
        labels = {}
    if isinstance(similar_scams, Exception):
        similar_scams = []
    if isinstance(holders, Exception):
        holders = []

    # Enrich nodes with labels
    for node in enriched_nodes:
        addr = node.get("address", "")
        label_data = labels.get(addr, {})
        entity = label_data.get("entity", {})
        node["label"] = entity.get("name") or entity.get("label") or node.get("label")
        node["entity_type"] = entity.get("type") or entity.get("entity_type")
        node["is_dev"] = entity.get("is_dev") or entity.get("type") == "developer"
        node["risk"] = label_data.get("risk_score") or node.get("risk_score", 0)
        node["tags"] = entity.get("tags") or []
        node["risk_level"] = label_data.get("risk_level", "unknown")

    # Generate AI analysis (DeepSeek Flash + fallback to our data engine)
    graph_data = {
        "node_count": len(enriched_nodes),
        "link_count": min(len(links), limit * 2),
        "risk_score": d.get("risk_score", 0),
        "risk_level": d.get("risk_level", "unknown"),
        "stats": d.get("stats", {}),
    }

    try:
        ai_analysis = await generate_ai_analysis(token_address, chain, graph_data, holders, labels, similar_scams)
    except Exception as e:
        logger.warning(f"AI analysis failed, using fallback: {e}")
        ai_analysis = generate_fallback_analysis(
            d.get("risk_score", 0),
            holders,
            labels,
            similar_scams,
            len(enriched_nodes),
            min(len(links), limit * 2),
        )

    response = {
        "token_address": token_address,
        "chain": chain,
        "nodes": enriched_nodes,
        "links": links[: limit * 2],
        **graph_data,
        "analysis": ai_analysis,
        "similar_scams": similar_scams[:5],
        "wallet_labels_count": len(labels),
        "from_cache": False,
    }

    # Cache for future requests
    set_cached_analysis(token_address, chain, response)

    # Auto-label all wallets in the graph (background, non-blocking)
    try:
        from app.auto_labeler import get_auto_labeler

        labeler = get_auto_labeler()
        for node in enriched_nodes:
            await labeler.observe_wallet(
                node["address"],
                chain,
                {"event": "scanned_in_graph", "token": token_address, "risk": node.get("risk", 0)},
            )
    except Exception:
        pass  # Auto-labeling is best-effort

    return response


def _get_explorer_url(chain: str, address: str) -> str:
    explorers = {
        "solana": "https://solscan.io/account/",
        "ethereum": "https://etherscan.io/address/",
        "base": "https://basescan.org/address/",
        "bsc": "https://bscscan.com/address/",
        "arbitrum": "https://arbiscan.io/address/",
        "optimism": "https://optimistic.etherscan.io/address/",
        "polygon": "https://polygonscan.com/address/",
    }
    base = explorers.get(chain, explorers["ethereum"])
    return base + address


# ── Auto-Labeler ──────────────────────────────────────────────


@router.post("/auto-label")
async def auto_label_wallet(request: dict):
    """Submit wallet observations for automatic labeling."""
    try:
        from app.auto_labeler import get_auto_labeler

        labeler = get_auto_labeler()

        address = request.get("address", "")
        chain = request.get("chain", "ethereum")
        events = request.get("events", [])

        all_labels = []
        for event in events:
            labels = await labeler.observe_wallet(address, chain, event)
            all_labels.extend(labels)

        return {
            "status": "ok",
            "address": address,
            "labels_applied": all_labels,
            "count": len(all_labels),
        }
    except Exception as e:
        raise HTTPException(status_code=500, detail=str(e)[:200])


@router.get("/auto-label/stats")
async def auto_label_stats():
    """Get auto-labeler statistics."""
    try:
        from app.auto_labeler import get_auto_labeler

        labeler = get_auto_labeler()
        return {"status": "ok", **labeler.get_stats()}
    except Exception as e:
        raise HTTPException(status_code=500, detail=str(e)[:200])
