"""
Entity Labeler - Advanced Wallet Labeling Module
================================================

Exposes:
  • Exchange/Protocol detection (Uniswap, Aave, Binance, etc.)
  • Whale detection (high-value wallets)
  • Contract type detection (fungible, non-fungible, proxy, library)
  • Risk scoring (low/medium/high/critical)
  • Smart contract verification status
  • Token metadata (name, symbol, decimals)
"""

import logging
from datetime import datetime
from typing import Any

from pydantic import BaseModel

from app.entity_clustering import EntityClusteringEngine

logger = logging.getLogger(__name__)


# ─── KNOWN ENTITIES DATABASE ──────────────────────────────────────────────

# Exchange contracts (major CEX/DEX)
EXCHANGES = {
    "binance": ["0x" + "0" * 39 + "2a", "0x" + "0" * 39 + "3b"],  # Placeholder - actual addresses
    "coinbase": ["0x" + "0" * 39 + "4c"],
    "uniswap": ["0x7a250d5630b4cf139281983dce37532e7d5c9196"],
    "sushiswap": ["0xc0a47dfe034b400b26bc65c9f1b2c5ac5b5d7373"],
    "curve": ["0x90e80ecf27b8b9f3a6c5b6694c44515f5b6f5d45"],
    "chainlink": ["0x514910771af9ca656af840dff83e8264ecf986ca"],
}

# Protocol contracts (DeFi protocols)
PROTOCOLS = {
    "aave": {
        "address": "0x7d2768de32b0b8013e039f31fbacf67128c9c3d8",
        "token": "0x37d819f03d3261550b4e75c5e5c5c5c5c5c5c5c5",  # placeholder
        "type": "lending",
    },
    "compound": {
        "address": "0x3fdf4e696732ad248fbfc9d846c252d66b4d945c",
        "type": "lending",
    },
    "uniswap_v3": {
        "address": "0x1f98431c8ad98523631ae4a59f267346ea31f988",
        "type": "amm",
    },
}

# Token categories
TOKEN_TYPES = {
    "stablecoin": ["usdc", "usdt", "dai", "busd", "ampt"],
    "memecoin": ["pepe", "shib", "doge", "floki"],
    "governance": ["snapshot", "governance", "vote"],
    "yield": ["aave", "comp", "yearn"],
}


# ─── DETECTION FUNCTIONS ──────────────────────────────────────────────────


def detect_exchange(address: str, name: str = "", symbol: str = "") -> str | None:
    """Detect if address belongs to a known exchange/protocol."""
    address_lower = address.lower()

    # Check exchange contracts
    for exchange, contracts in EXCHANGES.items():
        if any(contract.lower() in address_lower for contract in contracts):
            return exchange

    # Check name/symbol matching
    name_lower = (name + " " + symbol).lower()
    for exchange in EXCHANGES:
        if exchange.lower() in name_lower:
            return exchange

    return None


def detect_protocol(address: str, name: str = "", symbol: str = "") -> str | None:
    """Detect if address is a DeFi protocol."""
    # Check protocol contracts
    for protocol, info in PROTOCOLS.items():
        if info["address"].lower() in address.lower():
            return protocol

    # Check name/symbol
    name_lower = (name + " " + symbol).lower()
    for protocol in PROTOCOLS:
        if protocol.lower() in name_lower:
            return protocol

    return None


def detect_token_type(symbol: str, name: str = "") -> list[str]:
    """Detect token type(s) based on name/symbol."""
    symbol_lower = symbol.lower()
    name_lower = name.lower()

    types = []
    for token_type, keywords in TOKEN_TYPES.items():
        if any(kw in symbol_lower or kw in name_lower for kw in keywords):
            types.append(token_type)

    return types


def detect_whale(address: str, balance_eth: float = 0, balance_usd: float = 0) -> dict[str, Any] | None:
    """Detect if address is a whale (high-value wallet)."""
    whale_thresholds = {
        "super_whale": 10000,  # $10M+ USD
        "high_whale": 1000,  # $1M+ USD
        "medium_whale": 100,  # $100k+ USD
    }

    for level, threshold_usd in whale_thresholds.items():
        if balance_usd >= threshold_usd:
            return {
                "is_whale": True,
                "level": level,
                "balance_usd": balance_usd,
                "balance_eth": balance_eth,
                "rank": "whale",
            }

    return None


def detect_high_risk(address: str, tx_count: int = 0, age_days: int = 0) -> dict[str, Any]:
    """Detect high-risk wallet characteristics."""
    risk_factors = []
    risk_score = 0

    # Low age with high activity = suspicious
    if age_days < 30 and tx_count > 100:
        risk_factors.append("new_wallet_high_activity")
        risk_score += 2

    # High transaction count (potential bot/spam)
    if tx_count > 1000:
        risk_factors.append("high_frequency")
        risk_score += 1

    # Zero balance but active (potential scam)
    if tx_count > 50:
        risk_factors.append("活跃但余额为零")
        risk_score += 1

    return {
        "is_high_risk": risk_score >= 2,
        "risk_score": risk_score,
        "risk_factors": risk_factors,
        "risk_level": "low" if risk_score == 0 else ("medium" if risk_score <= 2 else "high"),
    }


def analyze_contract_type(bytecode: str, source_code: str | None = None) -> dict[str, Any]:
    """Analyze contract type from bytecode."""
    result = {
        "is_contract": True,
        "contract_type": "unknown",
        "is_verified": source_code is not None,
        "is_proxy": False,
        "proxy_type": None,
        "has_own_code": False,
    }

    # Check for proxy patterns
    if "0x360894a1" in bytecode:  # delegate call to
        result["is_proxy"] = True
        result["proxy_type"] = "delegate"
    elif "0xc5318c17" in bytecode:  # implementation storage
        result["is_proxy"] = True
        result["proxy_type"] = "transparent"
    elif "0x70ca07de" in bytecode:  # upgradeTo
        result["is_proxy"] = True
        result["proxy_type"] = "upgradeable"

    # Check for specific contract types
    if "transferFrom" in (source_code or ""):
        result["contract_type"] = "erc20"
    elif "tokenURI" in (source_code or "") or "safeMint" in (source_code or ""):
        result["contract_type"] = "erc721"
    elif "vote" in (source_code or ""):
        result["contract_type"] = "governance"

    return result


# ─── ENTITY LABELER ENGINE ────────────────────────────────────────────────


class EntityLabeler:
    """Main entity labeler engine."""

    def __init__(self, clustering_engine: EntityClusteringEngine | None = None):
        self.clustering = clustering_engine or EntityClusteringEngine()
        self.labels: dict[str, dict[str, Any]] = {}
        self.risk_scores: dict[str, float] = {}

    def label_address(
        self,
        address: str,
        chain: str = "ethereum",
        name: str = "",
        symbol: str = "",
        balance_eth: float = 0,
        balance_usd: float = 0,
        tx_count: int = 0,
        age_days: int = 0,
        bytecode: str = "",
        source_code: str | None = None,
    ) -> dict[str, Any]:
        """Comprehensive labeling of an address."""
        label = {
            "address": address,
            "chain": chain,
            "labels": [],
            "labels_detail": [],
            "risk": {"score": 0, "level": "low", "factors": []},
            "whale": None,
            "exchange": None,
            "protocol": None,
            "token_type": [],
            "contract": {},
            "verified_at": datetime.utcnow().isoformat(),
        }

        # Detect exchange
        exchange = detect_exchange(address, name, symbol)
        if exchange:
            label["exchange"] = exchange
            label["labels"].append(f"exchange:{exchange}")
            label["labels_detail"].append({"type": "exchange", "name": exchange})
            label["risk"]["score"] += 1

        # Detect protocol
        protocol = detect_protocol(address, name, symbol)
        if protocol:
            label["protocol"] = protocol
            label["labels"].append(f"protocol:{protocol}")
            label["labels_detail"].append({"type": "protocol", "name": protocol})

        # Detect whale
        whale = detect_whale(address, balance_eth, balance_usd)
        if whale:
            label["whale"] = whale
            label["labels"].append(f"whale:{whale['level']}")
            label["labels_detail"].append({"type": "whale", "level": whale["level"]})
            label["risk"]["score"] += 1  # Whales need monitoring

        # Detect token type
        token_types = detect_token_type(symbol, name)
        if token_types:
            label["token_type"] = token_types
            label["labels"].extend([f"token_type:{tt}" for tt in token_types])

        # Detect risk factors
        risk = detect_high_risk(address, tx_count, age_days)
        label["risk"]["score"] += risk["risk_score"]
        label["risk"]["factors"] = risk["risk_factors"]

        # Adjust risk level
        label["risk"]["level"] = risk["risk_level"]

        # Analyze contract
        if bytecode:
            contract_info = analyze_contract_type(bytecode, source_code)
            label["contract"] = contract_info
            if contract_info["contract_type"] != "unknown":
                label["labels"].append(f"contract:{contract_info['contract_type']}")

        # Store label
        self.labels[address] = label

        # Update risk score
        self.risk_scores[address] = min(label["risk"]["score"], 10)

        return label

    def batch_label_addresses(
        self,
        addresses: list[dict[str, Any]],
    ) -> dict[str, dict[str, Any]]:
        """Label multiple addresses at once."""
        results = {}
        for addr_info in addresses:
            address = addr_info.get("address", "")
            result = self.label_address(
                address=address,
                chain=addr_info.get("chain", "ethereum"),
                name=addr_info.get("name", ""),
                symbol=addr_info.get("symbol", ""),
                balance_eth=addr_info.get("balance_eth", 0),
                balance_usd=addr_info.get("balance_usd", 0),
                tx_count=addr_info.get("tx_count", 0),
                age_days=addr_info.get("age_days", 0),
                bytecode=addr_info.get("bytecode", ""),
                source_code=addr_info.get("source_code"),
            )
            results[address] = result
        return results

    def get_label(self, address: str) -> dict[str, Any] | None:
        """Get label for an address."""
        return self.labels.get(address.lower())

    def get_risk_score(self, address: str) -> float:
        """Get risk score for an address."""
        return self.risk_scores.get(address.lower(), 0)

    def get_risk_level(self, address: str) -> str:
        """Get risk level for an address."""
        score = self.get_risk_score(address)
        if score >= 8:
            return "critical"
        elif score >= 5:
            return "high"
        elif score >= 2:
            return "medium"
        return "low"


# ─── MODULE FUNCTIONS ─────────────────────────────────────────────────────

_labeler: EntityLabeler | None = None


def get_entity_labeler() -> EntityLabeler:
    """Get the global entity labeler instance."""
    global _labeler
    if _labeler is None:
        _labeler = EntityLabeler()
    return _labeler


def label_address(
    address: str,
    chain: str = "ethereum",
    name: str = "",
    symbol: str = "",
    balance_eth: float = 0,
    balance_usd: float = 0,
    tx_count: int = 0,
    age_days: int = 0,
    bytecode: str = "",
    source_code: str | None = None,
) -> dict[str, Any]:
    """Label an address with comprehensive metadata."""
    labeler = get_entity_labeler()
    return labeler.label_address(
        address=address,
        chain=chain,
        name=name,
        symbol=symbol,
        balance_eth=balance_eth,
        balance_usd=balance_usd,
        tx_count=tx_count,
        age_days=age_days,
        bytecode=bytecode,
        source_code=source_code,
    )


def batch_label_addresses(addresses: list[dict[str, Any]]) -> dict[str, dict[str, Any]]:
    """Label multiple addresses."""
    labeler = get_entity_labeler()
    return labeler.batch_label_addresses(addresses)


def get_risk_score(address: str) -> float:
    """Get risk score for an address."""
    labeler = get_entity_labeler()
    return labeler.get_risk_score(address)


def get_risk_level(address: str) -> str:
    """Get risk level for an address."""
    labeler = get_entity_labeler()
    return labeler.get_risk_level(address)


# ─── API RESPONSE MODELS ──────────────────────────────────────────────────


class LabelResponse(BaseModel):
    address: str
    chain: str = "ethereum"
    labels: list[str]
    risk: dict[str, Any]
    whale: dict[str, Any] | None = None
    exchange: str | None = None
    protocol: str | None = None
    token_type: list[str] = []
    contract: dict[str, Any] = {}
    verified_at: str


class RiskResponse(BaseModel):
    address: str
    risk_score: float
    risk_level: str
    risk_factors: list[str]
