"""
RMI LangChain Integration
==========================
Provides RMI tools as LangChain tools for use in LangChain agents, chains, and workflows.

Usage:
    from rmi_langchain import RMIToolkit, create_rmi_agent

    # Get all RMI tools as LangChain tools
    toolkit = RMIToolkit(api_key="rmi_dev_...")
    tools = toolkit.get_tools()

    # Create an agent with RMI tools
    agent = create_rmi_agent(api_key="rmi_dev_...")
    result = agent.invoke({"input": "Scan this wallet for risks: 0xd8dA..."})

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

import json
import os
from typing import Any

from pydantic import BaseModel, Field

try:
    from langchain_core.callbacks import CallbackManagerForToolRun
    from langchain_core.tools import BaseTool

    LANGCHAIN_AVAILABLE = True
except ImportError:
    LANGCHAIN_AVAILABLE = False

try:
    from rmi_sdk import RMI, ToolResult

    SDK_AVAILABLE = True
except ImportError:
    SDK_AVAILABLE = False


# ── RMI Tool Wrappers ─────────────────────────────────────────────


class RMIToolInput(BaseModel):
    """Base input schema for RMI tools."""

    address: str = Field(description="Wallet or token address to analyze")
    chain: str = Field(default="solana", description="Blockchain: solana, base, ethereum, bsc, etc.")


class ScanInput(RMIToolInput):
    """Input for wallet scan."""

    pass


class AuditInput(RMIToolInput):
    """Input for contract audit."""

    source_code: str | None = Field(default=None, description="Optional contract source code")


class WhaleInput(RMIToolInput):
    """Input for whale analysis."""

    pass


class ReputationInput(BaseModel):
    """Input for reputation score."""

    address: str = Field(description="Wallet or token address")


class HoneypotInput(RMIToolInput):
    """Input for honeypot check."""

    pass


class SentimentInput(BaseModel):
    """Input for sentiment analysis."""

    query: str = Field(description="Search query for sentiment analysis")


class RugProbabilityInput(RMIToolInput):
    """Input for rug probability."""

    pass


class CompositeScoreInput(RMIToolInput):
    """Input for composite score."""

    pass


class SmartMoneyInput(BaseModel):
    """Input for smart money analysis."""

    address: str = Field(description="Wallet address to find similar smart money wallets")


class MarketOverviewInput(BaseModel):
    """Input for market overview."""

    pass


class NarrativeInput(BaseModel):
    """Input for market narrative."""

    pass


class ForensicsInput(RMIToolInput):
    """Input for wallet forensics."""

    pass


if LANGCHAIN_AVAILABLE and SDK_AVAILABLE:

    class RMITool(BaseTool):
        """Base class for RMI LangChain tools."""

        rmi_client: RMI

        def _run(
            self,
            run_manager: CallbackManagerForToolRun | None = None,
            **kwargs: Any,
        ) -> str:
            try:
                result = self.rmi_client.call(self.name, kwargs)
                return json.dumps(result.raw, indent=2, default=str)
            except Exception as e:
                return json.dumps({"error": str(e), "tool": self.name})

        async def _arun(
            self,
            run_manager: CallbackManagerForToolRun | None = None,
            **kwargs: Any,
        ) -> str:
            # Use sync version for now — async SDK available separately
            return self._run(run_manager=run_manager, **kwargs)

    class RMIScanTool(RMITool):
        name: str = "rmi_scan"
        description: str = "Scan a wallet address for security risks, scam patterns, and suspicious activity. Returns risk assessment, labels, and recommendations."
        args_schema: type[BaseModel] = ScanInput

    class RMIAuditTool(RMITool):
        name: str = "rmi_audit"
        description: str = "Audit a smart contract for vulnerabilities, rug pull indicators, and malicious code patterns. Returns security assessment."
        args_schema: type[BaseModel] = AuditInput

    class RMIWhaleTool(RMITool):
        name: str = "rmi_whale"
        description: str = "Analyze whale wallet activity, holdings, and trading patterns. Returns portfolio analysis and behavioral insights."
        args_schema: type[BaseModel] = WhaleInput

    class RMIReputationTool(RMITool):
        name: str = "rmi_reputation"
        description: str = "Get a 0-100 reputation/trust score for a wallet or token address. Combines labels, scam databases, and on-chain behavior."
        args_schema: type[BaseModel] = ReputationInput

    class RMIHoneypotTool(RMITool):
        name: str = "rmi_honeypot"
        description: str = "Check if a token is a honeypot — tokens you can buy but cannot sell. Returns honeypot status and risk factors."
        args_schema: type[BaseModel] = HoneypotInput

    class RMISentimentTool(RMITool):
        name: str = "rmi_sentiment"
        description: str = "Get market sentiment analysis for a token, project, or keyword. Returns sentiment score and community mood."
        args_schema: type[BaseModel] = SentimentInput

    class RMIRugProbabilityTool(RMITool):
        name: str = "rmi_rug_probability"
        description: str = (
            "Get rug pull probability score (0-100) for a token. Predicts likelihood of rug pull in next 24 hours."
        )
        args_schema: type[BaseModel] = RugProbabilityInput

    class RMICompositeScoreTool(RMITool):
        name: str = "rmi_composite_score"
        description: str = "Get a composite buy/sell/avoid score for a token. Combines reputation, rug probability, market health, narrative sentiment, and MEV exposure."
        args_schema: type[BaseModel] = CompositeScoreInput

    class RMISmartMoneyTool(RMITool):
        name: str = "rmi_smart_money"
        description: str = "Find profitable traders similar to this wallet. Returns ranked list of smart money wallets with PnL and follow-worthiness scores."
        args_schema: type[BaseModel] = SmartMoneyInput

    class RMIMarketOverviewTool(RMITool):
        name: str = "rmi_market_overview"
        description: str = "Get current market overview — prices, volumes, trends across major chains and tokens."
        args_schema: type[BaseModel] = MarketOverviewInput

    class RMINarrativeTool(RMITool):
        name: str = "rmi_narrative"
        description: str = "Get current market narrative — what is the market saying RIGHT NOW? Returns trending narratives, sentiment, and community focus."
        args_schema: type[BaseModel] = NarrativeInput

    class RMIForensicsTool(RMITool):
        name: str = "rmi_forensics"
        description: str = (
            "Run deep wallet forensics — transaction history, fund flows, connected addresses, and risk analysis."
        )
        args_schema: type[BaseModel] = ForensicsInput

    # ── Toolkit ────────────────────────────────────────────────────

    class RMIToolkit:
        """RMI tools as a LangChain toolkit."""

        def __init__(self, api_key: str | None = None, **kwargs):
            self.api_key = api_key or os.environ.get("RMI_API_KEY")
            self.rmi = RMI(api_key=self.api_key, **kwargs)

        def get_tools(self) -> list[BaseTool]:
            """Get all RMI tools as LangChain tools."""
            return [
                RMIScanTool(rmi_client=self.rmi),
                RMIAuditTool(rmi_client=self.rmi),
                RMIWhaleTool(rmi_client=self.rmi),
                RMIReputationTool(rmi_client=self.rmi),
                RMIHoneypotTool(rmi_client=self.rmi),
                RMISentimentTool(rmi_client=self.rmi),
                RMIRugProbabilityTool(rmi_client=self.rmi),
                RMICompositeScoreTool(rmi_client=self.rmi),
                RMISmartMoneyTool(rmi_client=self.rmi),
                RMIMarketOverviewTool(rmi_client=self.rmi),
                RMINarrativeTool(rmi_client=self.rmi),
                RMIForensicsTool(rmi_client=self.rmi),
            ]

    def create_rmi_agent(
        api_key: str | None = None,
        model: str = "gpt-4",
        **kwargs,
    ):
        """Create a LangChain agent with RMI tools.

        Args:
            api_key: RMI API key.
            model: LLM model to use.
            **kwargs: Additional arguments for RMI client.

        Returns:
            Configured LangChain agent executor.
        """
        try:
            from langchain.agents import AgentExecutor, create_tool_calling_agent
            from langchain_core.prompts import ChatPromptTemplate, MessagesPlaceholder
            from langchain_openai import ChatOpenAI

            toolkit = RMIToolkit(api_key=api_key, **kwargs)
            tools = toolkit.get_tools()

            llm = ChatOpenAI(model=model, temperature=0)

            prompt = ChatPromptTemplate.from_messages(
                [
                    (
                        "system",
                        """You are a crypto security analyst powered by Rug Munch Intelligence (RMI).
You have access to 230+ crypto intelligence tools for:
- Wallet scanning and forensics
- Smart contract auditing
- Whale tracking and analysis
- Rug pull prediction
- Market sentiment and narratives
- Reputation scoring

Always use the appropriate tool for the user's query. If a tool returns no data, try a different approach.
Provide clear, actionable recommendations based on the tool results.""",
                    ),
                    MessagesPlaceholder("chat_history", optional=True),
                    ("human", "{input}"),
                    MessagesPlaceholder("agent_scratchpad"),
                ]
            )

            agent = create_tool_calling_agent(llm, tools, prompt)
            return AgentExecutor(agent=agent, tools=tools, verbose=True)

        except ImportError as e:
            raise ImportError(
                "langchain and langchain_openai are required: pip install langchain langchain-openai"
            ) from e

    def create_crewai_rmi_tools(api_key: str | None = None, **kwargs):
        """Create CrewAI-compatible tools.

        Usage:
            from rmi_langchain import create_crewai_rmi_tools
            from crewai import Agent, Task, Crew

            tools = create_crewai_rmi_tools(api_key="rmi_dev_...")

            analyst = Agent(
                role="Crypto Security Analyst",
                goal="Analyze crypto wallets and tokens for security risks",
                backstory="Expert in detecting rugs, honeypots, and scams",
                tools=tools,
                verbose=True,
            )
        """
        toolkit = RMIToolkit(api_key=api_key, **kwargs)
        return toolkit.get_tools()
