#!/usr/bin/env python3
"""#19 - Smart Contract Function Analyzer. Extends SENTINEL to decompile and analyze
bytecode. Returns human-readable "what this contract actually does." """

import os
import re
from typing import Any

import httpx
from fastapi import APIRouter, Query

router = APIRouter(prefix="/api/v1/contract-analyzer", tags=["contract-analyzer"])

BACKEND = os.environ.get("BACKEND_URL", "http://localhost:8000")

# Known suspicious function signatures (4-byte selectors)
SUSPICIOUS_SELECTORS = {
    "0x18160ddd": "totalSupply()",
    "0x06fdde03": "name()",
    "0x95d89b41": "symbol()",
    "0x313ce567": "decimals()",
    "0x70a08231": "balanceOf(address)",
    "0xa9059cbb": "transfer(address,uint256)",
    "0x23b872dd": "transferFrom(address,address,uint256)",
    "0x095ea7b3": "approve(address,uint256)",
    "0x42966c68": "burn(uint256)",
    "0x79cc6790": "burnFrom(address,uint256)",
    "0xf2fde38b": "transferOwnership(address)",
    "0x8da5cb5b": "owner()",
    "0x8456cb59": "pause()",
    "0x3f4ba83a": "unpause()",
    "0x40c10f19": "mint(address,uint256)",
    "0x9dc29fac": "burn(uint256)",
    "0x79ba5097": "renounceOwnership()",
    "0x715018a6": "renounceOwnership()",
    "0x83197ef0": "includeInReward(address)",
    "0xea8a1af0": "excludeFromReward(address)",
    "0x7f41468d": "setSwapAndLiquifyEnabled(bool)",
    "0x55505aac": "setMaxTxPercent(uint256)",
    "0x3141de2d": "setMaxWalletPercent(uint256)",
}

# Patterns that indicate malicious intent
MALICIOUS_PATTERNS = [
    ("unlimited mint", [r"mint\(", r"_mint\(", r"mint_without_limit"]),
    ("hidden owner functions", [r"onlyOwner", r"require\(.*owner"]),
    ("transfer fee manipulation", [r"setTax", r"setFee", r"updateFee"]),
    ("blacklist capability", [r"blacklist", r"isBlacklisted", r"_blacklist"]),
    ("pause/trading halt", [r"pause\(", r"unpause\(", r"setTrading"]),
    ("reentrancy risk", [r"\.call\{", r"\.transfer\("]),
    ("selfdestruct", [r"selfdestruct\(", r"suicide\("]),
    ("proxy upgrade risk", [r"upgradeTo\(", r"upgradeToAndCall\(", r"_upgradeTo"]),
]


async def _get_contract_bytecode(address: str, chain: str) -> dict[str, Any]:
    """Fetch contract bytecode and source from Etherscan/Blockscout."""
    explorers = {
        "ethereum": "https://api.etherscan.io/api",
        "bsc": "https://api.bscscan.com/api",
        "polygon": "https://api.polygonscan.com/api",
        "arbitrum": "https://api.arbiscan.io/api",
        "base": "https://api.basescan.org/api",
        "optimism": "https://api-optimistic.etherscan.io/api",
    }

    result = {"bytecode": "", "source": "", "abi": [], "verified": False}

    api_base = explorers.get(chain)
    if not api_base:
        return result

    try:
        async with httpx.AsyncClient(timeout=10) as client:
            # Get bytecode
            resp = await client.get(
                f"{api_base}",
                params={"module": "proxy", "action": "eth_getCode", "address": address, "apikey": "YourApiKeyToken"},
            )
            if resp.status_code == 200:
                result["bytecode"] = resp.json().get("result", "")

            # Check if verified
            resp2 = await client.get(
                f"{api_base}",
                params={
                    "module": "contract",
                    "action": "getsourcecode",
                    "address": address,
                    "apikey": "YourApiKeyToken",
                },
            )
            if resp2.status_code == 200:
                data = resp2.json().get("result", [{}])[0]
                result["source"] = data.get("SourceCode", "")
                result["abi"] = data.get("ABI", "[]")
                result["verified"] = True
    except Exception:
        pass

    return result


def _analyze_bytecode(bytecode: str, source: str) -> dict:
    """Analyze contract bytecode/source for suspicious patterns."""
    findings: list[dict] = []
    risk_score = 0

    # Check for suspicious function selectors in bytecode
    for selector, name in SUSPICIOUS_SELECTORS.items():
        if selector[2:] in bytecode.lower():
            risk_map = {
                "mint": 15,
                "burn": 5,
                "pause": 10,
                "transferOwnership": 10,
                "renounceOwnership": 5,
                "includeInReward": 10,
                "setSwapAndLiquifyEnabled": 10,
                "setMaxTxPercent": 10,
                "setMaxWalletPercent": 10,
            }
            for key, score in risk_map.items():
                if key in name:
                    risk_score += score
                    findings.append(
                        {
                            "function": name,
                            "selector": selector,
                            "risk": "HIGH" if score >= 10 else "MEDIUM",
                            "explanation": f"Contract has {name} function - {'can create unlimited tokens' if 'mint' in name.lower() else 'may be used to manipulate trading'}",
                        }
                    )
                    break

    # Check source code for malicious patterns
    if source:
        for pattern_name, regexes in MALICIOUS_PATTERNS:
            for regex in regexes:
                if re.search(regex, source, re.IGNORECASE):
                    risk_score += 10
                    findings.append(
                        {
                            "pattern": pattern_name,
                            "matched": regex,
                            "risk": "HIGH",
                            "explanation": f"Source code contains {pattern_name} pattern",
                        }
                    )
                    break

    risk_level = (
        "CRITICAL" if risk_score >= 50 else "HIGH" if risk_score >= 25 else "MEDIUM" if risk_score >= 10 else "LOW"
    )
    return {"risk_score": min(100, risk_score), "risk_level": risk_level, "findings": findings}


@router.get("/analyze/{address}")
async def analyze_contract(address: str, chain: str = Query("ethereum")):
    """Analyze a smart contract's functions and risk profile."""
    info = await _get_contract_bytecode(address, chain)
    analysis = _analyze_bytecode(info.get("bytecode", ""), info.get("source", ""))

    # Also run SENTINEL scan
    try:
        async with httpx.AsyncClient(timeout=10) as client:
            resp = await client.post(
                f"{BACKEND}/api/v1/token/scan",
                json={"token_address": address, "chain": chain},
                headers={"X-RMI-Key": "rmi-internal-2026"},
            )
            if resp.status_code == 200:
                sentinel = resp.json()
                analysis["sentinel_score"] = sentinel.get("safety_score", 50)
                analysis["sentinel_flags"] = sentinel.get("risk_flags", [])
    except Exception:
        pass

    return {
        "contract": address,
        "chain": chain,
        "verified": info.get("verified", False),
        "bytecode_length": len(info.get("bytecode", "")),
        "analysis": analysis,
        "summary": (
            f"Risk: {analysis['risk_level']} ({analysis['risk_score']}/100). "
            f"{len(analysis['findings'])} suspicious patterns found. "
            f"Verified: {'Yes' if info.get('verified') else 'No'}."
        ),
    }


@router.get("/detect-mint/{address}")
async def detect_mint_function(address: str, chain: str = Query("ethereum")):
    """Quick check: does this contract have a mint function?"""
    info = await _get_contract_bytecode(address, chain)
    bytecode = info.get("bytecode", "")

    mint_selectors = ["40c10f19", "079cc6790", "a0712d68"]
    found = []
    for sel in mint_selectors:
        if sel in bytecode.lower():
            name = SUSPICIOUS_SELECTORS.get(f"0x{sel}", "unknown mint function")
            found.append({"selector": f"0x{sel}", "function": name})
    return {
        "contract": address,
        "has_mint_function": len(found) > 0,
        "mint_functions": found,
        "risk": "HIGH" if len(found) > 0 else "LOW",
        "note": "Mint functions allow creating new tokens - typical of scams" if found else "No mint function detected",
    }
