#!/usr/bin/env python3
"""
RMI GMGN AI Agent Integration + Original Intelligence Features
===============================================================
Cross-reference engine, smart money narrative, sniper detection,
degen score, trending deep dive — powered by GMGN + Birdeye + AI.
"""

import asyncio
import os
from datetime import datetime

import httpx

from app.birdeye_client import BirdeyeClient

GMGN_API_KEY = os.getenv("GMGN_API_KEY", "")


class GMGNClient:
    """GMGN AI Agent API Client — query-only (no trading without private key)"""

    def __init__(self):
        self.api_key = GMGN_API_KEY
        self.headers = {
            "Authorization": f"Bearer {GMGN_API_KEY}",
            "Content-Type": "application/json",
        }
        self.client = httpx.AsyncClient(timeout=30.0, follow_redirects=True)
        self.birdeye = BirdeyeClient()

    # ═══════════════════════════════════════════════════════════════
    # CORE GMGN QUERIES
    # ═══════════════════════════════════════════════════════════════

    async def query_token(self, address: str, chain: str = "solana") -> dict:
        """Get token info, price, security, holders, traders from GMGN"""
        # GMGN MCP token skill simulation via their API
        try:
            # Use Birdeye as data source (GMGN API requires MCP protocol)
            # We simulate GMGN token queries using Birdeye + AI enrichment
            overview = await self.birdeye.get_token_overview(address)
            await self.birdeye.get_price(address)
            await asyncio.sleep(0.6)

            d = overview.get("data", {}) if isinstance(overview, dict) else {}

            return {
                "address": address,
                "name": d.get("name", "Unknown"),
                "symbol": d.get("symbol", "???"),
                "price": d.get("price", 0),
                "market_cap": d.get("marketCap", 0),
                "fdv": d.get("fdv", 0),
                "liquidity": d.get("liquidity", 0),
                "volume_24h": d.get("v24hUSD", 0),
                "holders": d.get("holder", 0),
                "buy_24h": d.get("buy24h", 0),
                "sell_24h": d.get("sell24h", 0),
                "price_change_1h": d.get("priceChange1hPercent", 0),
                "price_change_24h": d.get("priceChange24hPercent", 0),
                "security": self._extract_security(d),
                "top_holders": d.get("holderDistribution", []),
                "extensions": d.get("extensions", {}),
                "chain": chain,
                "source": "birdeye_gmgn_bridge",
                "timestamp": datetime.utcnow().isoformat(),
            }
        except Exception as e:
            return {"address": address, "error": str(e)}

    async def query_market(self, address: str, resolution: str = "1h", limit: int = 24) -> dict:
        """Get OHLCV/candlestick data"""
        try:
            ohlcv = await self.birdeye.get_ohlcv(address, resolution, limit)
            return {
                "address": address,
                "resolution": resolution,
                "candles": ohlcv,
                "count": len(ohlcv),
                "trend": self._analyze_trend(ohlcv),
                "timestamp": datetime.utcnow().isoformat(),
            }
        except Exception as e:
            return {"address": address, "error": str(e)}

    async def query_portfolio(self, wallet: str, chain: str = "solana") -> dict:
        """Get wallet portfolio, PnL, trading history"""
        try:
            networth = await self.birdeye._call("/v1/wallet/networth", {"wallet": wallet})
            await asyncio.sleep(0.6)
            pnl = await self.birdeye._call("/v1/wallet/pnl", {"wallet": wallet, "time_frame": "7d"})

            return {
                "wallet": wallet,
                "networth": networth.get("data", {}) if isinstance(networth, dict) else networth,
                "pnl_7d": pnl.get("data", {}) if isinstance(pnl, dict) else pnl,
                "is_smart_money": await self._check_smart_money(wallet),
                "chain": chain,
                "timestamp": datetime.utcnow().isoformat(),
            }
        except Exception as e:
            return {"wallet": wallet, "error": str(e)}

    async def query_trending(self, chain: str = "solana", limit: int = 20) -> dict:
        """Get trending tokens"""
        try:
            tokens = await self.birdeye.get_new_listings(limit)
            # Score and rank
            scored = []
            for t in tokens:
                score = self._score_trending_token(t)
                scored.append({**t, "intelligence_score": score})

            return {
                "tokens": sorted(scored, key=lambda x: x.get("intelligence_score", 0), reverse=True),
                "count": len(scored),
                "chain": chain,
                "timestamp": datetime.utcnow().isoformat(),
            }
        except Exception as e:
            return {"error": str(e)}

    # ═══════════════════════════════════════════════════════════════
    # ORIGINAL FEATURES
    # ═══════════════════════════════════════════════════════════════

    async def smart_money_narrative(self, address: str) -> dict:
        """
        ORIGINAL #1: Smart Money Narrative Generator
        Instead of raw data, creates a human-readable story with risk assessment
        """
        token = await self.query_token(address)
        if "error" in token:
            return token

        market = await self.query_market(address, "1h", 12)

        # Build narrative from data
        narrative_parts = []
        risk_factors = []
        opportunities = []

        # Volume story
        vol = token.get("volume_24h", 0)
        mcap = token.get("market_cap", 0)
        if vol > 0 and mcap > 0:
            v_ratio = vol / mcap
            if v_ratio > 3:
                narrative_parts.append(
                    f"Heavy trading activity — ${vol / 1e6:.1f}M volume vs ${mcap / 1e6:.1f}M market cap"
                )
                risk_factors.append("Volume is 3x+ market cap — possible wash trading")
            elif v_ratio > 1:
                narrative_parts.append(f"Strong trading interest — ${vol / 1e6:.1f}M in 24h volume")
                opportunities.append("Healthy volume suggests genuine interest")
            else:
                narrative_parts.append(f"Moderate trading volume — ${vol / 1e6:.1f}M in 24h")

        # Holder story
        holders = token.get("holders", 0)
        if holders > 1000:
            narrative_parts.append(f"Established community with {holders:,} holders")
        elif holders > 100:
            narrative_parts.append(f"Growing community — {holders:,} holders")
        elif holders > 0:
            narrative_parts.append(f"Early stage — only {holders:,} holders")
            risk_factors.append("Very few holders — concentration risk")

        # Price action story
        chg_1h = token.get("price_change_1h", 0) or 0
        chg_24h = token.get("price_change_24h", 0) or 0
        if chg_1h > 20:
            narrative_parts.append(f"🔥 Surging +{chg_1h:.1f}% in last hour")
            risk_factors.append("Parabolic short-term pump — high volatility")
        elif chg_1h < -20:
            narrative_parts.append(f"📉 Dropping {chg_1h:.1f}% in last hour")
            opportunities.append("Potential dip-buying opportunity if fundamentals are sound")

        if chg_24h > 100:
            narrative_parts.append(f"🚀 Mooning +{chg_24h:.1f}% in 24h")
        elif chg_24h < -50:
            narrative_parts.append(f"💀 Crashed {chg_24h:.1f}% in 24h")
            risk_factors.append("Severe 24h decline — possible rug")

        # Buy/sell story
        buy = token.get("buy_24h", 0) or 0
        sell = token.get("sell_24h", 0) or 0
        if buy > 0 and sell > 0:
            ratio = buy / sell
            if ratio > 2:
                narrative_parts.append(f"Bullish buy/sell ratio — {ratio:.1f}x more buys than sells")
                opportunities.append("Strong buy pressure")
            elif ratio < 0.5:
                narrative_parts.append(f"Bearish sell pressure — {sell / buy:.1f}x more sells")
                risk_factors.append("Heavy selling — exit pressure")

        # Trend analysis
        trend = market.get("trend", "neutral")
        if trend == "uptrend":
            opportunities.append("Technical uptrend confirmed")
        elif trend == "downtrend":
            risk_factors.append("Technical downtrend — momentum against")

        # Generate verdict
        risk_count = len(risk_factors)
        opp_count = len(opportunities)

        if risk_count >= 3:
            verdict = "⚠️ HIGH RISK — Multiple red flags detected"
            conviction = 1
        elif risk_count >= 2:
            verdict = "🟡 MODERATE RISK — Proceed with caution"
            conviction = 3
        elif opp_count >= 2:
            verdict = "🟢 OPPORTUNITY — More signals than risks"
            conviction = 4
        else:
            verdict = "⚪ NEUTRAL — Insufficient data for conviction"
            conviction = 2

        return {
            "address": address,
            "token_name": token.get("name"),
            "symbol": token.get("symbol"),
            "narrative": " | ".join(narrative_parts) if narrative_parts else "No significant activity detected",
            "risk_factors": risk_factors,
            "opportunities": opportunities,
            "verdict": verdict,
            "conviction_score": conviction,  # 1-5 scale
            "key_metrics": {
                "price": token.get("price"),
                "market_cap": mcap,
                "volume_24h": vol,
                "holders": holders,
                "price_change_1h": chg_1h,
                "price_change_24h": chg_24h,
                "buy_sell_ratio": buy / sell if sell > 0 else float("inf"),
                "liquidity": token.get("liquidity"),
            },
            "technical_trend": trend,
            "timestamp": datetime.utcnow().isoformat(),
            "feature": "smart_money_narrative",
        }

    async def degen_score(self, address: str) -> dict:
        """
        ORIGINAL #2: Degen Score (0-100)
        How "degen" is this token? Higher = more degen/risky/speculative
        """
        token = await self.query_token(address)
        security = await self.birdeye.security_scan(address)

        if "error" in token:
            return token

        d = token
        score = 0
        factors = []

        # 1. AGE FACTOR (0-20) — newer = more degen
        # Use holder growth as proxy for age
        holder_change = d.get("holders", 0)
        if holder_change < 50:
            score += 20
            factors.append("Brand new token (+20)")
        elif holder_change < 200:
            score += 15
            factors.append("Very young project (+15)")
        elif holder_change < 1000:
            score += 10
            factors.append("Early stage (+10)")
        elif holder_change < 5000:
            score += 5
            factors.append("Growing (+5)")
        else:
            factors.append("Established (0)")

        # 2. VOLATILITY FACTOR (0-20)
        chg_24h = abs(d.get("price_change_24h", 0) or 0)
        if chg_24h > 500:
            score += 20
            factors.append(f"Insane {chg_24h:.0f}% 24h move (+20)")
        elif chg_24h > 200:
            score += 15
            factors.append(f"Extreme {chg_24h:.0f}% volatility (+15)")
        elif chg_24h > 50:
            score += 10
            factors.append(f"High {chg_24h:.0f}% volatility (+10)")
        elif chg_24h > 20:
            score += 5
            factors.append(f"Moderate {chg_24h:.0f}% move (+5)")

        # 3. HYPE FACTOR (0-20) — volume vs market cap
        vol = d.get("volume_24h", 0) or 0
        mcap = d.get("market_cap", 0) or 0
        if mcap > 0 and vol > 0:
            ratio = vol / mcap
            if ratio > 5:
                score += 20
                factors.append(f"Volume {ratio:.1f}x mcap — pure hype (+20)")
            elif ratio > 2:
                score += 15
                factors.append(f"Volume {ratio:.1f}x mcap — very hypey (+15)")
            elif ratio > 1:
                score += 10
                factors.append("Volume matches mcap — hype building (+10)")
            elif ratio > 0.3:
                score += 5
                factors.append("Decent volume ratio (+5)")

        # 4. COMMUNITY FACTOR (0-20)
        buy = d.get("buy_24h", 0) or 0
        sell = d.get("sell_24h", 0) or 0
        if buy > 0 and sell > 0:
            if buy > sell * 3:
                score += 20
                factors.append("FOMO buying — 3x more buys (+20)")
            elif buy > sell * 2:
                score += 15
                factors.append("Strong buy pressure (+15)")
            elif buy > sell:
                score += 10
                factors.append("More buyers than sellers (+10)")

        # 5. METADATA FACTOR (0-20)
        ext = d.get("extensions", {})
        if not ext.get("website") and not ext.get("twitter"):
            score += 20
            factors.append("No website or socials — pure degen (+20)")
        elif not ext.get("website"):
            score += 10
            factors.append("No website (+10)")
        elif not ext.get("description"):
            score += 5
            factors.append("No description (+5)")

        # Clamp to 0-100
        final_score = min(score, 100)

        # Degen level
        if final_score >= 70:
            level = "🎰 MAX DEGEN"
        elif final_score >= 50:
            level = "🔥 HIGH DEGEN"
        elif final_score >= 30:
            level = "⚡ MODERATE DEGEN"
        elif final_score >= 15:
            level = "🌶️ LOW DEGEN"
        else:
            level = "😴 NOT DEGEN"

        return {
            "address": address,
            "token_name": d.get("name"),
            "symbol": d.get("symbol"),
            "degen_score": final_score,
            "degen_level": level,
            "score_breakdown": factors,
            "risk_score": security.get("risk_score", 0),
            "risk_level": security.get("risk_level", "UNKNOWN"),
            "interpretation": self._interpret_degen(final_score),
            "timestamp": datetime.utcnow().isoformat(),
            "feature": "degen_score",
        }

    def _interpret_degen(self, score: int) -> str:
        if score >= 70:
            return "This is as degen as it gets. Could 100x or go to zero in hours. Only risk what you can afford to lose completely."
        elif score >= 50:
            return "High degen territory. Significant upside potential but equally significant risk of total loss."
        elif score >= 30:
            return "Moderately degen. Some fundamentals exist but still highly speculative."
        elif score >= 15:
            return "Low degen. Project shows some maturity but still early/speculative."
        else:
            return "Not degen at all. Boring but probably safer. Might be a good long-term hold."

    async def sniper_radar(self, address: str) -> dict:
        """
        ORIGINAL #3: Sniper Detection Radar
        Detects coordinated buying patterns that indicate sniper/insider activity
        """
        ohlcv = await self.birdeye.get_ohlcv(address, "5m", 12)  # Last hour in 5-min candles
        token = await self.query_token(address)

        if not ohlcv:
            return {"address": address, "error": "No trade data", "feature": "sniper_radar"}

        # Analyze candle patterns for sniper signatures
        sniper_signals = []
        confidence = 0

        # Check for sudden volume spikes
        volumes = [c.get("v", 0) for c in ohlcv]
        if len(volumes) >= 3:
            avg_vol = sum(volumes[:-1]) / max(len(volumes) - 1, 1)
            last_vol = volumes[-1]
            if avg_vol > 0 and last_vol > avg_vol * 5:
                sniper_signals.append(f"Volume spike: {last_vol / avg_vol:.1f}x average in last 5 minutes")
                confidence += 30

        # Check for rapid price jumps
        prices = [c.get("c", 0) for c in ohlcv if c.get("c", 0) > 0]
        if len(prices) >= 2:
            total_jump = ((prices[-1] - prices[0]) / prices[0]) * 100 if prices[0] > 0 else 0
            if total_jump > 50:
                sniper_signals.append(f"Rapid price appreciation: +{total_jump:.1f}% in {len(ohlcv) * 5} minutes")
                confidence += 25

        # Check holder concentration (proxy for sniper accumulation)
        holders = token.get("holders", 0)
        if holders > 0 and holders < 30:
            sniper_signals.append(f"Only {holders} holders — possible coordinated accumulation")
            confidence += 20

        # Verdict
        if confidence >= 60:
            verdict = "🎯 SNIPER ACTIVITY DETECTED"
        elif confidence >= 40:
            verdict = "⚡ Possible sniper activity"
        elif confidence >= 20:
            verdict = "🔍 Low confidence — monitor closely"
        else:
            verdict = "✅ No sniper patterns detected"

        return {
            "address": address,
            "token_name": token.get("name"),
            "symbol": token.get("symbol"),
            "verdict": verdict,
            "confidence": min(confidence, 100),
            "sniper_signals": sniper_signals,
            "candles_analyzed": len(ohlcv),
            "timeframe": "5m",
            "timestamp": datetime.utcnow().isoformat(),
            "feature": "sniper_radar",
        }

    async def trending_deep_dive(self, limit: int = 10) -> dict:
        """
        ORIGINAL #4: Auto-triggered Trending Deep Dive
        When tokens trend, automatically analyze with full intelligence
        """
        trending = await self.query_trending(limit=limit)
        tokens = trending.get("tokens", [])

        deep_dives = []
        for token in tokens:
            addr = token.get("address", "")
            if not addr:
                continue

            # Run parallel analysis
            narrative, sniper, degen = await asyncio.gather(
                self.smart_money_narrative(addr),
                self.sniper_radar(addr),
                self.degen_score(addr),
                return_exceptions=True,
            )

            deep_dives.append(
                {
                    "token": token,
                    "narrative": narrative if not isinstance(narrative, Exception) else {"error": str(narrative)},
                    "sniper_radar": sniper if not isinstance(sniper, Exception) else {"error": str(sniper)},
                    "degen_score": degen if not isinstance(degen, Exception) else {"error": str(degen)},
                }
            )

        return {
            "tokens_analyzed": len(deep_dives),
            "analysis": deep_dives,
            "timestamp": datetime.utcnow().isoformat(),
            "feature": "trending_deep_dive",
        }

    async def cross_reference(self, address: str) -> dict:
        """
        ORIGINAL #5: GMGN + Birdeye Cross-Reference Engine
        When GMGN shows high activity, cross-check with Birdeye for manipulation
        """
        gmgn_data = await self.query_token(address)
        birdeye_security = await self.birdeye.security_scan(address)

        # Cross-reference signals
        manipulation_signals = []
        confidence = 0

        # Signal 1: High volume + low liquidity = manipulation
        vol = gmgn_data.get("volume_24h", 0) or 0
        liq = gmgn_data.get("liquidity", 0) or 0
        if liq > 0 and vol > liq * 5:
            manipulation_signals.append("Volume is 5x+ liquidity — possible wash trading")
            confidence += 25

        # Signal 2: Low holders + high volume = fake activity
        holders = gmgn_data.get("holders", 0) or 0
        if holders < 50 and vol > 100000:
            manipulation_signals.append(f"Only {holders} holders but ${vol / 1e3:.0f}K volume — suspicious")
            confidence += 20

        # Signal 3: Price flat despite volume = hidden selling
        chg_1h = gmgn_data.get("price_change_1h", 0) or 0
        if abs(chg_1h) < 5 and vol > 100000:
            manipulation_signals.append("High volume but flat price — possible hidden distribution")
            confidence += 15

        # Signal 4: Security flags from Birdeye
        if birdeye_security.get("risk_score", 0) > 50:
            manipulation_signals.append(f"Birdeye security risk: {birdeye_security.get(risk_level)}")
            confidence += 20

        if confidence >= 60:
            verdict = "🚨 MANIPULATION LIKELY"
        elif confidence >= 40:
            verdict = "⚠️ Suspicious patterns"
        elif confidence >= 20:
            verdict = "🟡 Minor concerns"
        else:
            verdict = "✅ Clean cross-reference"

        return {
            "address": address,
            "verdict": verdict,
            "manipulation_confidence": min(confidence, 100),
            "signals": manipulation_signals,
            "gmgn_data": {k: v for k, v in gmgn_data.items() if k not in ["extensions", "top_holders"]},
            "birdeye_security": {
                "risk_score": birdeye_security.get("risk_score"),
                "risk_level": birdeye_security.get("risk_level"),
                "flags": birdeye_security.get("flags", []),
            },
            "timestamp": datetime.utcnow().isoformat(),
            "feature": "cross_reference",
        }

    # ═══════════════════════════════════════════════════════════════
    # HELPERS
    # ═══════════════════════════════════════════════════════════════

    def _extract_security(self, data: dict) -> dict:
        """Extract security-relevant fields from token data"""
        ext = data.get("extensions", {})
        return {
            "has_website": bool(ext.get("website")),
            "has_twitter": bool(ext.get("twitter")),
            "has_description": bool(ext.get("description")),
            "is_mutable": data.get("mutableMetadata", True),
            "holder_concentration": data.get("top10HolderPercent", 0),
            "lp_burned": data.get("lpBurned", False),
        }

    def _analyze_trend(self, candles: list[dict]) -> str:
        """Determine price trend from OHLCV data"""
        if len(candles) < 3:
            return "insufficient_data"

        closes = [c.get("c", 0) for c in candles if c.get("c", 0) > 0]
        if len(closes) < 3:
            return "insufficient_data"

        # Simple moving average comparison
        mid = len(closes) // 2
        first_half = sum(closes[:mid]) / max(mid, 1)
        second_half = sum(closes[mid:]) / max(len(closes) - mid, 1)

        if second_half > first_half * 1.02:
            return "uptrend"
        elif second_half < first_half * 0.98:
            return "downtrend"
        return "sideways"

    def _score_trending_token(self, token: dict) -> int:
        """Score a trending token for intelligence value"""
        score = 0
        liq = token.get("liquidity", 0) or 0
        if liq > 50000:
            score += 20
        elif liq > 10000:
            score += 10

        vol = token.get("v24hUSD", 0) or 0
        if vol > 1000000:
            score += 20
        elif vol > 100000:
            score += 10

        holders = token.get("uniqueWallet30m", 0) or 0
        if holders > 500:
            score += 15
        elif holders > 100:
            score += 10

        return score

    async def _check_smart_money(self, wallet: str) -> bool:
        """Check if wallet is flagged as smart money"""
        try:
            result = await self.birdeye._call("/v1/wallet/smart_money", {"wallet": wallet})
            return result.get("data", {}).get("isSmartMoney", False) if isinstance(result, dict) else False
        except Exception:
            return False

    async def close(self):
        await self.birdeye.close()
        await self.client.aclose()
