"""
RMI Alpha Tools — High-Value Revenue Tools
============================================
Three premium alpha tools that bots will pay for:
1. whale_copy_trade — Real-time copy trade engine
2. rug_predictor_live — 5-minute rug prediction
3. whale_cluster — Coordinated whale cluster detection

All tools use DataBus + DexScreener + RAG enrichment.
Price points: $0.10-$0.50 per call.

Author: RMI Development
Date: 2026-06-05
"""

import json
import logging
import os
import time
from datetime import UTC, datetime

from fastapi import APIRouter
from fastapi.responses import JSONResponse
from pydantic import BaseModel

logger = logging.getLogger("alpha_tools")

router = APIRouter(prefix="/api/v1/x402-tools", tags=["alpha-tools"])

# ── Data Source Helpers ──────────────────────────────────────────


async def fetch_dexscreener(path: str, params: dict | None = None) -> dict | None:
    """Fetch from DexScreener API."""
    import aiohttp

    url = f"https://api.dexscreener.com/latest/dex/{path}"
    try:
        async with aiohttp.ClientSession(timeout=aiohttp.ClientTimeout(total=10)) as session:
            async with session.get(url, params=params) as resp:
                if resp.status == 200:
                    return await resp.json()
    except Exception as e:
        logger.warning(f"DexScreener fetch failed: {e}")
    return None


async def fetch_geckoterminal(path: str) -> dict | None:
    """Fetch from GeckoTerminal API."""
    import aiohttp

    url = f"https://api.geckoterminal.com/api/v2/{path}"
    headers = {"Accept": "application/json"}
    try:
        async with aiohttp.ClientSession(timeout=aiohttp.ClientTimeout(total=10)) as session:
            async with session.get(url, headers=headers) as resp:
                if resp.status == 200:
                    return await resp.json()
    except Exception as e:
        logger.warning(f"GeckoTerminal fetch failed: {e}")
    return None


async def fetch_helius(path: str, params: dict | None = None) -> dict | None:
    """Fetch from Helius API (Solana)."""
    import aiohttp

    api_key = os.getenv("HELIUS_API_KEY", "")
    if not api_key:
        return None

    url = f"https://api.helius.xyz/v0/{path}?api-key={api_key}"
    try:
        async with aiohttp.ClientSession(timeout=aiohttp.ClientTimeout(total=10)) as session:
            async with session.get(url, params=params) as resp:
                if resp.status == 200:
                    return await resp.json()
    except Exception as e:
        logger.warning(f"Helius fetch failed: {e}")
    return None


async def whale_copy_trade(req: WhaleCopyTradeRequest):
    """Real-time copy trade engine.

    Input a smart money wallet, get their exact last 24h trades with
    entry/exit prices, current PnL, and suggested follow trades.

    Price: $0.25/call
    """
    address = req.address.lower()
    chain = req.chain
    lookback = req.lookback_hours
    min_usd = req.min_trade_usd

    trades = []
    wallet_info = {}

    if chain == "solana":
        # Fetch recent transactions from Helius
        txns = await fetch_helius(
            f"addresses/{address}/transactions",
            {"type": "TRANSFER", "limit": 100},
        )
        if txns:
            for tx in txns[:50]:
                # Parse transfer data
                timestamp = tx.get("timestamp", 0)
                if timestamp < (time.time() - lookback * 3600):
                    continue

                # Extract token and amount
                transfers = tx.get("transfers", [])
                for transfer in transfers:
                    token = transfer.get("mint", "")
                    amount = transfer.get("tokenAmount", 0)
                    if not token or amount == 0:
                        continue

                    # Get token price
                    token_price = await _get_token_price(token, "solana")
                    usd_value = amount * (token_price or 0)

                    if usd_value >= min_usd:
                        trades.append(
                            {
                                "token": token,
                                "amount": amount,
                                "usd_value": round(usd_value, 2),
                                "price": token_price,
                                "type": "buy" if transfer.get("fromUserAccount") == address else "sell",
                                "timestamp": datetime.fromtimestamp(timestamp, tz=UTC).isoformat(),
                                "tx_hash": tx.get("signature", ""),
                            }
                        )

        # Get wallet token balance
        balance_data = await fetch_helius(f"addresses/{address}/balances")
        if balance_data:
            wallet_info["tokens"] = balance_data.get("total", 0)
            wallet_info["nfts"] = balance_data.get("nfts", 0)

    elif chain in ("base", "ethereum", "bsc", "arbitrum"):
        # For EVM chains, use DexScreener to find recent pairs
        search = await fetch_dexscreener("search", {"q": address})
        if search and search.get("pairs"):
            for pair in search["pairs"][:20]:
                txns = pair.get("txns", {})
                h24 = txns.get("h24", {})
                if h24.get("buys", 0) > 0 or h24.get("sells", 0) > 0:
                    trades.append(
                        {
                            "token": pair.get("baseToken", {}).get("address", ""),
                            "pair_address": pair.get("pairAddress", ""),
                            "price_usd": pair.get("priceUsd"),
                            "volume_24h": pair.get("volume", {}).get("h24", 0),
                            "buys_24h": h24.get("buys", 0),
                            "sells_24h": h24.get("sells", 0),
                            "liquidity": pair.get("liquidity", {}).get("usd", 0),
                        }
                    )

    # Calculate PnL for trades
    pnl_summary = _calculate_pnl(trades)

    # Generate copy trade suggestions
    suggestions = _generate_copy_suggestions(trades, wallet_info, lookback)

    return JSONResponse(
        content={
            "tool": "whale_copy_trade",
            "address": address,
            "chain": chain,
            "lookback_hours": lookback,
            "trades": trades[:30],  # Limit to 30
            "total_trades": len(trades),
            "pnl_summary": pnl_summary,
            "suggestions": suggestions,
            "wallet_info": wallet_info,
            "status": "ok" if trades else "no_data",
            "message": f"Found {len(trades)} trades >= ${min_usd:.0f} in {lookback}h"
            if trades
            else f"No trades >= ${min_usd:.0f} found in {lookback}h",
        }
    )


def _calculate_pnl(trades: list[dict]) -> dict:
    """Calculate PnL summary from trades."""
    buys = [t for t in trades if t.get("type") == "buy"]
    sells = [t for t in trades if t.get("type") == "sell"]

    total_bought = sum(t.get("usd_value", 0) for t in buys)
    total_sold = sum(t.get("usd_value", 0) for t in sells)

    # Group by token
    token_pnl = {}
    for t in trades:
        token = t.get("token", "unknown")
        if token not in token_pnl:
            token_pnl[token] = {"bought": 0, "sold": 0, "trades": 0}
        token_pnl[token]["trades"] += 1
        if t.get("type") == "buy":
            token_pnl[token]["bought"] += t.get("usd_value", 0)
        else:
            token_pnl[token]["sold"] += t.get("usd_value", 0)

    return {
        "total_bought_usd": round(total_bought, 2),
        "total_sold_usd": round(total_sold, 2),
        "net_flow_usd": round(total_sold - total_bought, 2),
        "buy_count": len(buys),
        "sell_count": len(sells),
        "unique_tokens": len(token_pnl),
        "top_tokens": sorted(
            [{"token": k, **v} for k, v in token_pnl.items()],
            key=lambda x: x["bought"],
            reverse=True,
        )[:5],
    }


def _generate_copy_suggestions(trades: list[dict], wallet_info: dict, lookback: int) -> list[dict]:
    """Generate copy trade suggestions based on wallet activity."""
    suggestions = []

    # Find tokens the wallet is accumulating (more buys than sells)
    token_activity = {}
    for t in trades:
        token = t.get("token", "")
        if not token:
            continue
        if token not in token_activity:
            token_activity[token] = {"buys": 0, "sells": 0, "total_usd": 0}
        if t.get("type") == "buy":
            token_activity[token]["buys"] += 1
        else:
            token_activity[token]["sells"] += 1
        token_activity[token]["total_usd"] += t.get("usd_value", 0)

    for token, activity in token_activity.items():
        if activity["buys"] > activity["sells"] and activity["total_usd"] > 5000:
            suggestions.append(
                {
                    "token": token,
                    "action": "accumulate",
                    "confidence": min(activity["buys"] * 0.2, 0.9),
                    "reason": f"Wallet bought {activity['buys']} times, sold {activity['sells']} times",
                    "total_volume_usd": round(activity["total_usd"], 2),
                }
            )

    return suggestions[:10]


async def _get_token_price(address: str, chain: str) -> float | None:
    """Get current token price from DexScreener."""
    if chain == "solana":
        result = await fetch_dexscreener(f"tokens/{address}")
        if result and result.get("pairs"):
            return float(result["pairs"][0].get("priceNative", 0))
    return None


# ── Tool 2: Live Rug Predictor ───────────────────────────────────


class RugPredictorLiveRequest(BaseModel):
    address: str
    chain: str = "solana"
    lookback_minutes: int = 30


@router.post("/rug_predictor_live")
async def rug_predictor_live(req: RugPredictorLiveRequest):
    """Live rug predictor — analyzes tokens in their first 5-30 minutes.

    Watches new tokens in real-time, scores them, and alerts before the rug.

    Price: $0.50/call
    """
    address = req.address.lower()
    chain = req.chain

    # Fetch token data from multiple sources
    pair_data = await fetch_dexscreener(f"tokens/{address}")
    if not pair_data or not pair_data.get("pairs"):
        return JSONResponse(
            content={
                "tool": "rug_predictor_live",
                "address": address,
                "chain": chain,
                "status": "no_data",
                "message": "Token not found on DexScreener",
                "rug_score": 0,
                "verdict": "UNKNOWN",
            }
        )

    pair = pair_data["pairs"][0]
    signals = []
    rug_score = 0

    # ── Signal 1: Liquidity Analysis ──────────────────────────────
    liquidity_usd = pair.get("liquidity", {}).get("usd", 0)
    if liquidity_usd < 1000:
        signals.append(
            {
                "signal": "low_liquidity",
                "severity": "critical",
                "message": f"Liquidity only ${liquidity_usd:.0f} — extremely vulnerable to rug",
                "weight": 25,
            }
        )
        rug_score += 25
    elif liquidity_usd < 5000:
        signals.append(
            {
                "signal": "low_liquidity",
                "severity": "high",
                "message": f"Liquidity ${liquidity_usd:.0f} — high risk",
                "weight": 15,
            }
        )
        rug_score += 15

    # ── Signal 2: LP Lock Status ──────────────────────────────────
    lp_locked = pair.get("lockInfo", {}).get("locked", False)
    if not lp_locked:
        signals.append(
            {
                "signal": "lp_not_locked",
                "severity": "critical",
                "message": "Liquidity pool is NOT locked — creator can remove at any time",
                "weight": 20,
            }
        )
        rug_score += 20

    # ── Signal 3: Price Action ────────────────────────────────────
    price_change = pair.get("priceChange", {})
    h1_change = price_change.get("h1", 0)
    price_change.get("m5", 0)

    if h1_change < -50:
        signals.append(
            {
                "signal": "price_crash",
                "severity": "critical",
                "message": f"Price down {h1_change}% in 1 hour — active rug in progress",
                "weight": 25,
            }
        )
        rug_score += 25

    # ── Signal 4: Volume/Liquidity Ratio ─────────────────────────
    volume_24h = pair.get("volume", {}).get("h24", 0)
    if liquidity_usd > 0:
        vol_liq_ratio = volume_24h / liquidity_usd
        if vol_liq_ratio > 10:
            signals.append(
                {
                    "signal": "extreme_volume",
                    "severity": "high",
                    "message": f"Volume/Liquidity ratio {vol_liq_ratio:.1f}x — suspicious activity",
                    "weight": 10,
                }
            )
            rug_score += 10

    # ── Signal 5: Transaction Count ───────────────────────────────
    txns = pair.get("txns", {})
    h1_txns = txns.get("h1", {})
    buys = h1_txns.get("buys", 0)
    sells = h1_txns.get("sells", 0)

    if buys > 0 and sells > 0:
        sell_ratio = sells / (buys + sells)
        if sell_ratio > 0.8:
            signals.append(
                {
                    "signal": "mass_selling",
                    "severity": "high",
                    "message": f"{sell_ratio * 100:.0f}% of transactions are sells — panic selling",
                    "weight": 15,
                }
            )
            rug_score += 15

    # ── Signal 6: Pair Age ────────────────────────────────────────
    pair_created_at = pair.get("pairCreatedAt", 0)
    if pair_created_at:
        age_hours = (time.time() * 1000 - pair_created_at) / (1000 * 3600)
        if age_hours < 1:
            signals.append(
                {
                    "signal": "brand_new_pair",
                    "severity": "medium",
                    "message": f"Pair is only {age_hours * 60:.0f} minutes old — highest risk window",
                    "weight": 10,
                }
            )
            rug_score += 10

    # ── Determine Verdict ─────────────────────────────────────────
    if rug_score >= 70:
        verdict = "CRITICAL_RUG"
        action = "AVOID — High probability of active or imminent rug"
    elif rug_score >= 50:
        verdict = "HIGH_RISK"
        action = "AVOID — Multiple red flags detected"
    elif rug_score >= 30:
        verdict = "MEDIUM_RISK"
        action = "CAUTION — Some warning signs, monitor closely"
    elif rug_score >= 15:
        verdict = "LOW_RISK"
        action = "MONITOR — Minor concerns but mostly clean"
    else:
        verdict = "SAFE"
        action = "Relatively clean — standard risk management applies"

    return JSONResponse(
        content={
            "tool": "rug_predictor_live",
            "address": address,
            "chain": chain,
            "rug_score": min(rug_score, 100),
            "verdict": verdict,
            "action": action,
            "signals": signals,
            "token_info": {
                "name": pair.get("baseToken", {}).get("name", ""),
                "symbol": pair.get("baseToken", {}).get("symbol", ""),
                "price_usd": pair.get("priceUsd"),
                "liquidity_usd": liquidity_usd,
                "volume_24h": volume_24h,
                "price_change_1h": h1_change,
                "txns_1h": {"buys": buys, "sells": sells},
                "lp_locked": lp_locked,
                "pair_age_hours": round(age_hours, 2) if pair_created_at else None,
            },
            "timestamp": datetime.now(UTC).isoformat(),
            "status": "ok",
        }
    )


# ── Tool 3: Whale Cluster Detection ──────────────────────────────


class WhaleClusterRequest(BaseModel):
    address: str
    chain: str = "solana"
    min_cluster_size: int = 3
    similarity_threshold: float = 0.7


@router.post("/whale_cluster")
async def whale_cluster(req: WhaleClusterRequest):
    """Identify coordinated whale clusters.

    Group wallets that move together: same funding source, same timing,
    same token sets. Identifies wash trading, coordinated pumps,
    and insider networks.

    Price: $0.30/call
    """
    address = req.address.lower()
    chain = req.chain
    min_size = req.min_cluster_size
    threshold = req.similarity_threshold

    r = get_redis()
    cluster_data = {
        "seed_wallet": address,
        "chain": chain,
        "clusters": [],
        "total_related_wallets": 0,
        "risk_assessment": "unknown",
    }

    # Step 1: Get wallets that interacted with the same tokens
    same_token_wallets = await _find_shared_token_wallets(address, chain, r)

    # Step 2: Check for shared funding sources
    funding_clusters = await _find_shared_funding(address, chain, r)

    # Step 3: Check timing correlation
    timing_clusters = await _find_timing_correlation(address, chain, r)

    # Combine and score
    wallet_scores = {}

    for wallet, score in same_token_wallets.items():
        wallet_scores[wallet] = wallet_scores.get(wallet, 0) + score * 0.4

    for wallet, score in funding_clusters.items():
        wallet_scores[wallet] = wallet_scores.get(wallet, 0) + score * 0.4

    for wallet, score in timing_clusters.items():
        wallet_scores[wallet] = wallet_scores.get(wallet, 0) + score * 0.2

    # Filter by threshold
    cluster_wallets = [
        {"wallet": w, "similarity": round(s, 3)} for w, s in wallet_scores.items() if s >= threshold and w != address
    ]
    cluster_wallets.sort(key=lambda x: x["similarity"], reverse=True)

    # Group into clusters by similarity
    clusters = []
    used = set()
    for cw in cluster_wallets:
        if cw["wallet"] in used:
            continue
        cluster = {"members": [cw["wallet"]], "avg_similarity": cw["similarity"]}
        used.add(cw["wallet"])
        for other in cluster_wallets:
            if other["wallet"] not in used and abs(other["similarity"] - cw["similarity"]) < 0.1:
                cluster["members"].append(other["wallet"])
                used.add(other["wallet"])

        if len(cluster["members"]) >= min_size - 1:  # -1 because seed wallet
            cluster["members"].insert(0, address)  # Add seed wallet
            cluster["size"] = len(cluster["members"])
            cluster["avg_similarity"] = round(
                sum(wallet_scores.get(w, 0) for w in cluster["members"]) / len(cluster["members"]),
                3,
            )
            clusters.append(cluster)

    # Risk assessment
    if any(c["size"] >= 5 for c in clusters):
        cluster_data["risk_assessment"] = "high"
        cluster_data["risk_message"] = "Large coordinated cluster detected — possible wash trading or insider network"
    elif any(c["size"] >= 3 for c in clusters):
        cluster_data["risk_assessment"] = "medium"
        cluster_data["risk_message"] = "Medium cluster detected — wallets showing coordinated behavior"
    else:
        cluster_data["risk_assessment"] = "low"
        cluster_data["risk_message"] = "No significant clusters detected"

    cluster_data["clusters"] = clusters
    cluster_data["total_related_wallets"] = len(cluster_wallets)
    cluster_data["status"] = "ok"

    return JSONResponse(content=cluster_data)


async def _find_shared_token_wallets(address: str, chain: str, r) -> dict[str, float]:
    """Find wallets that traded the same tokens."""
    # Get tokens this wallet traded
    token_key = f"rmi:wallet:{address}:{chain}:tokens"
    tokens = r.smembers(token_key) if r else set()

    if not tokens:
        # Fetch from DexScreener as fallback
        result = await fetch_dexscreener("search", {"q": address})
        if result and result.get("pairs"):
            tokens = {p.get("baseToken", {}).get("address", "") for p in result["pairs"][:20]}

    # For each token, find other wallets
    shared = {}
    for token in tokens:
        if not token:
            continue
        # Check Redis cache of recent traders for this token
        traders_key = f"rmi:token:{token}:{chain}:traders"
        traders = r.smembers(traders_key) if r else set()

        for trader in traders:
            if trader != address:
                shared[trader] = shared.get(trader, 0) + 1

    # Normalize
    max_shared = max(shared.values()) if shared else 1
    return {w: s / max_shared for w, s in shared.items()}


async def _find_shared_funding(address: str, chain: str, r) -> dict[str, float]:
    """Find wallets funded from the same source."""
    # Check if we have funding data cached
    funding_key = f"rmi:wallet:{address}:{chain}:funding"
    funding_source = r.get(funding_key) if r else None

    if funding_source:
        # Find other wallets funded from same source
        other_key = f"rmi:funding:{chain}:{funding_source}:wallets"
        other_wallets = r.smembers(other_key) if r else set()
        return {w: 0.9 for w in other_wallets if w != address}

    return {}


async def _find_timing_correlation(address: str, chain: str, r) -> dict[str, float]:
    """Find wallets with correlated trading timing."""
    # Get recent trade timestamps
    timing_key = f"rmi:wallet:{address}:{chain}:timing"
    timing_data = r.get(timing_key) if r else None

    if timing_data:
        json.loads(timing_data)
        # Find wallets with similar timing patterns
        correlation_key = f"rmi:timing:{chain}:correlations"
        correlations = r.hgetall(correlation_key) if r else {}

        correlated = {}
        for wallet, corr_score in correlations.items():
            if float(corr_score) > 0.5:
                correlated[wallet] = float(corr_score)

        return correlated

    return {}


# ── Tool Pricing Registration ────────────────────────────────────


# These tools register their prices in the canonical tool prices dict
def register_alpha_tool_prices():
    """Register alpha tool prices with the enforcement system."""
    try:
        from app.routers.x402_enforcement import TOOL_PRICES

        TOOL_PRICES.update(
            {
                "whale_copy_trade": {
                    "price_usd": 0.25,
                    "price_atoms": "250000",
                    "category": "alpha",
                    "trial_free": 1,
                    "description": "Real-time copy trade engine — find smart money trades with entry/exit prices, PnL, and follow suggestions",
                },
                "rug_predictor_live": {
                    "price_usd": 0.50,
                    "price_atoms": "500000",
                    "category": "security",
                    "trial_free": 1,
                    "description": "Live rug predictor — analyzes tokens in first 5-30 minutes with 6-signal rug probability scoring",
                },
                "whale_cluster": {
                    "price_usd": 0.30,
                    "price_atoms": "300000",
                    "category": "intelligence",
                    "trial_free": 1,
                    "description": "Coordinated whale cluster detection — identify wash trading, insider networks, and pump groups",
                },
            }
        )
    except Exception as e:
        logger.warning(f"Failed to register alpha tool prices: {e}")


# Register on import
register_alpha_tool_prices()
