"""
SwarmPay MCP Server – Model Context Protocol Integration.

Damit können Claude, ClawdBots, MoltBots und alle MCP-kompatiblen
AI-Agents direkt auf SwarmPay zugreifen und Zahlungen auslösen.

Starte mit:
    python3 -m swarmpay.mcp_server

Oder füge in deine Claude MCP-Config ein:
    {
        "mcpServers": {
            "swarmpay": {
                "command": "python3",
                "args": ["-m", "swarmpay.mcp_server"]
            }
        }
    }
"""
from __future__ import annotations

import json
import sys
import os

# Projekt-Root zum Path hinzufügen
sys.path.append(os.path.join(os.path.dirname(__file__), ".."))

from swarmpay.client import SwarmPay
from swarmpay.fee_engine import FeeConfig

# SwarmPay-Instanz (wird beim Start konfiguriert)
_swarmpay: SwarmPay | None = None


def get_swarmpay() -> SwarmPay:
    global _swarmpay
    if _swarmpay is None:
        _swarmpay = SwarmPay(
            admin_wallet=os.getenv("SWARMPAY_ADMIN_WALLET", "") or os.getenv("PAYFI_ADMIN_WALLET", ""),
            fee_percent=float(os.getenv("SWARMPAY_FEE_PERCENT", "0.01")),
            network=os.getenv("SWARMPAY_NETWORK", "base-sepolia"),
        )
    return _swarmpay


# ── MCP Tool Definitions ─────────────────────────────────────

TOOLS = [
    {
        "name": "swarmpay_create_wallet",
        "description": "Erstellt eine neue Crypto-Wallet für einen KI-Agenten. "
                       "Die Wallet kann USDC empfangen und senden.",
        "inputSchema": {
            "type": "object",
            "properties": {
                "agent_id": {
                    "type": "string",
                    "description": "Eindeutige ID für den Agenten (z.B. 'my-bot-1')",
                }
            },
            "required": ["agent_id"],
        },
    },
    {
        "name": "swarmpay_pay",
        "description": "Sendet eine Zahlung von einem Agenten an einen anderen. "
                       "1% Fee wird automatisch abgezogen und an den Plattform-Admin gesendet. "
                       "Zahlung erfolgt in USDC über die Blockchain.",
        "inputSchema": {
            "type": "object",
            "properties": {
                "agent_id": {
                    "type": "string",
                    "description": "ID des zahlenden Agenten",
                },
                "recipient": {
                    "type": "string",
                    "description": "Wallet-Adresse des Empfängers",
                },
                "amount": {
                    "type": "number",
                    "description": "Betrag in USD (z.B. 0.50 für 50 Cent)",
                },
            },
            "required": ["agent_id", "recipient", "amount"],
        },
    },
    {
        "name": "swarmpay_find_service",
        "description": "Sucht in der Service-Registry nach verfügbaren KI-Services. "
                       "Gibt Anbieter mit Wallet, Preis und Beschreibung zurück.",
        "inputSchema": {
            "type": "object",
            "properties": {
                "service_type": {
                    "type": "string",
                    "description": "Art des gesuchten Services (z.B. 'text-analysis', 'translation', 'image-generation')",
                }
            },
            "required": ["service_type"],
        },
    },
    {
        "name": "swarmpay_buy_service",
        "description": "Findet den günstigsten Anbieter für einen Service-Typ und bezahlt automatisch. "
                       "Kombiniert Suche + Zahlung in einem Schritt.",
        "inputSchema": {
            "type": "object",
            "properties": {
                "agent_id": {
                    "type": "string",
                    "description": "ID des kaufenden Agenten",
                },
                "service_type": {
                    "type": "string",
                    "description": "Gewünschter Service-Typ",
                },
            },
            "required": ["agent_id", "service_type"],
        },
    },
    {
        "name": "swarmpay_register_service",
        "description": "Registriert einen neuen Service in der SwarmPay Registry. "
                       "Andere Agenten können diesen Service dann finden und buchen.",
        "inputSchema": {
            "type": "object",
            "properties": {
                "agent_id": {
                    "type": "string",
                    "description": "ID des anbietenden Agenten",
                },
                "service_type": {
                    "type": "string",
                    "description": "Art des Services (z.B. 'text-analysis')",
                },
                "price_usd": {
                    "type": "number",
                    "description": "Preis pro Aufruf in USD",
                },
                "description": {
                    "type": "string",
                    "description": "Beschreibung des Services",
                },
            },
            "required": ["agent_id", "service_type", "price_usd"],
        },
    },
    {
        "name": "swarmpay_balance",
        "description": "Zeigt den aktuellen Kontostand einer Agenten-Wallet.",
        "inputSchema": {
            "type": "object",
            "properties": {
                "agent_id": {
                    "type": "string",
                    "description": "ID des Agenten",
                }
            },
            "required": ["agent_id"],
        },
    },
    {
        "name": "swarmpay_list_services",
        "description": "Listet alle verfügbaren Services in der Registry auf.",
        "inputSchema": {
            "type": "object",
            "properties": {},
        },
    },
    {
        "name": "swarmpay_fee_schedule",
        "description": "Zeigt die aktuelle Gebührenstruktur (Staffelpreise nach Volumen).",
        "inputSchema": {
            "type": "object",
            "properties": {},
        },
    },
    {
        "name": "swarmpay_escrow_fund",
        "description": "Create and fund an on-chain escrow. Holds USDC in a smart contract "
                       "until the service is delivered and the buyer releases funds.",
        "inputSchema": {
            "type": "object",
            "properties": {
                "agent_id": {
                    "type": "string",
                    "description": "ID of the buyer agent",
                },
                "provider_wallet": {
                    "type": "string",
                    "description": "Wallet address of the service provider",
                },
                "amount_usd": {
                    "type": "number",
                    "description": "Amount in USD to escrow (e.g. 1.00)",
                },
                "service_type": {
                    "type": "string",
                    "description": "Type of service (e.g. 'translation', 'analysis')",
                },
                "timeout_seconds": {
                    "type": "number",
                    "description": "Escrow deadline in seconds (default: 3600)",
                },
            },
            "required": ["agent_id", "provider_wallet", "amount_usd", "service_type"],
        },
    },
    {
        "name": "swarmpay_escrow_confirm",
        "description": "Provider confirms that the service has been delivered. "
                       "This is an on-chain transaction that updates the escrow status.",
        "inputSchema": {
            "type": "object",
            "properties": {
                "agent_id": {
                    "type": "string",
                    "description": "ID of the provider agent confirming delivery",
                },
                "escrow_nonce": {
                    "type": "number",
                    "description": "The on-chain escrow nonce/ID",
                },
            },
            "required": ["agent_id", "escrow_nonce"],
        },
    },
    {
        "name": "swarmpay_escrow_release",
        "description": "Buyer releases escrowed funds to the provider after service delivery. "
                       "Provider receives payment, platform receives fee.",
        "inputSchema": {
            "type": "object",
            "properties": {
                "agent_id": {
                    "type": "string",
                    "description": "ID of the buyer agent releasing funds",
                },
                "escrow_nonce": {
                    "type": "number",
                    "description": "The on-chain escrow nonce/ID",
                },
            },
            "required": ["agent_id", "escrow_nonce"],
        },
    },
    {
        "name": "swarmpay_escrow_dispute",
        "description": "Open a dispute on an escrow. Either buyer or provider can dispute. "
                       "A dispute resolver will decide the outcome.",
        "inputSchema": {
            "type": "object",
            "properties": {
                "agent_id": {
                    "type": "string",
                    "description": "ID of the agent opening the dispute",
                },
                "escrow_nonce": {
                    "type": "number",
                    "description": "The on-chain escrow nonce/ID",
                },
                "reason": {
                    "type": "string",
                    "description": "Reason for the dispute",
                },
            },
            "required": ["agent_id", "escrow_nonce"],
        },
    },
    {
        "name": "swarmpay_escrow_refund",
        "description": "Refund escrowed funds back to the buyer. "
                       "Only possible after deadline expires or during a dispute.",
        "inputSchema": {
            "type": "object",
            "properties": {
                "agent_id": {
                    "type": "string",
                    "description": "ID of the agent requesting refund",
                },
                "escrow_nonce": {
                    "type": "number",
                    "description": "The on-chain escrow nonce/ID",
                },
            },
            "required": ["agent_id", "escrow_nonce"],
        },
    },
]


# ── Tool Handler ──────────────────────────────────────────────

_wallets: dict = {}  # agent_id -> AgentWallet


def handle_tool(name: str, arguments: dict) -> str:
    """Verarbeitet einen MCP Tool-Call."""
    sp = get_swarmpay()

    if name == "swarmpay_create_wallet":
        agent_id = arguments["agent_id"]
        wallet = sp.create_wallet(agent_id)
        _wallets[agent_id] = wallet
        return json.dumps({
            "agent_id": agent_id,
            "wallet_address": wallet.address,
            "network": wallet.network,
            "status": "created",
        })

    elif name == "swarmpay_pay":
        agent_id = arguments["agent_id"]
        if agent_id not in _wallets:
            return json.dumps({"error": f"Agent '{agent_id}' hat keine Wallet. Erstelle zuerst eine mit swarmpay_create_wallet."})
        wallet = _wallets[agent_id]
        result = wallet.pay(arguments["recipient"], arguments["amount"])
        return json.dumps({
            "success": result.success,
            "transaction_id": result.transaction_id,
            "amount_usd": result.amount_usd,
            "fee_usd": result.fee_usd,
            "service_amount_usd": result.service_amount_usd,
            "explorer_url": result.explorer_url,
            "error": result.error,
        })

    elif name == "swarmpay_find_service":
        services = sp.find_service(arguments["service_type"])
        return json.dumps({"services": services, "count": len(services)})

    elif name == "swarmpay_buy_service":
        agent_id = arguments["agent_id"]
        if agent_id not in _wallets:
            return json.dumps({"error": f"Agent '{agent_id}' hat keine Wallet."})
        wallet = _wallets[agent_id]
        result = sp.buy_service(wallet, arguments["service_type"])
        if "error" in result:
            return json.dumps(result)
        payment = result["payment"]
        return json.dumps({
            "success": payment.success,
            "provider": result["provider"],
            "amount_usd": payment.amount_usd,
            "fee_usd": payment.fee_usd,
            "transaction_id": payment.transaction_id,
            "error": payment.error,
        })

    elif name == "swarmpay_register_service":
        agent_id = arguments["agent_id"]
        if agent_id not in _wallets:
            return json.dumps({"error": f"Agent '{agent_id}' hat keine Wallet."})
        wallet = _wallets[agent_id]
        service_id = sp.register_service(
            wallet=wallet,
            service_type=arguments["service_type"],
            price_usd=arguments["price_usd"],
            description=arguments.get("description", ""),
        )
        return json.dumps({"service_id": service_id, "status": "registered"})

    elif name == "swarmpay_balance":
        agent_id = arguments["agent_id"]
        if agent_id not in _wallets:
            return json.dumps({"error": f"Agent '{agent_id}' hat keine Wallet."})
        wallet = _wallets[agent_id]
        return json.dumps({
            "agent_id": agent_id,
            "balance_usdc": wallet.balance("USDC"),
            "wallet_address": wallet.address,
        })

    elif name == "swarmpay_list_services":
        services = sp.registry.list_all()
        return json.dumps({"services": services, "count": len(services)})

    elif name == "swarmpay_fee_schedule":
        schedule = sp.fee_schedule
        return json.dumps({"fee_tiers": schedule})

    elif name == "swarmpay_escrow_fund":
        agent_id = arguments["agent_id"]
        if agent_id not in _wallets:
            return json.dumps({"error": f"Agent '{agent_id}' has no wallet. Create one first."})
        wallet = _wallets[agent_id]
        try:
            result = sp.create_onchain_escrow(
                buyer_wallet=wallet,
                provider_wallet=arguments["provider_wallet"],
                amount_usd=arguments["amount_usd"],
                service_type=arguments["service_type"],
                escrow_nonce=sp.onchain_escrow.config.chain_id if sp.onchain_escrow else 1,
                timeout_seconds=int(arguments.get("timeout_seconds", 3600)),
            )
            return json.dumps({
                "escrow_id": result.escrow.escrow_id,
                "status": result.escrow.status.value,
                "funding_tx_hash": result.funding_tx_hash,
                "approval_tx_hash": result.approval_tx_hash,
            })
        except Exception as e:
            return json.dumps({"error": str(e)})

    elif name == "swarmpay_escrow_confirm":
        agent_id = arguments["agent_id"]
        if agent_id not in _wallets:
            return json.dumps({"error": f"Agent '{agent_id}' has no wallet."})
        wallet = _wallets[agent_id]
        try:
            result = sp.confirm_onchain_delivery(wallet, int(arguments["escrow_nonce"]))
            return json.dumps({
                "escrow_id": result.escrow_id,
                "status": result.status.value,
                "tx_hash": result.tx_hash,
            })
        except Exception as e:
            return json.dumps({"error": str(e)})

    elif name == "swarmpay_escrow_release":
        agent_id = arguments["agent_id"]
        if agent_id not in _wallets:
            return json.dumps({"error": f"Agent '{agent_id}' has no wallet."})
        wallet = _wallets[agent_id]
        try:
            result = sp.release_onchain_escrow(wallet, int(arguments["escrow_nonce"]))
            return json.dumps({
                "escrow_id": result.escrow_id,
                "status": result.status.value,
                "tx_hash": result.tx_hash,
            })
        except Exception as e:
            return json.dumps({"error": str(e)})

    elif name == "swarmpay_escrow_dispute":
        agent_id = arguments["agent_id"]
        if agent_id not in _wallets:
            return json.dumps({"error": f"Agent '{agent_id}' has no wallet."})
        wallet = _wallets[agent_id]
        try:
            result = sp.dispute_onchain_escrow(
                wallet, int(arguments["escrow_nonce"]),
                reason=arguments.get("reason", ""),
            )
            return json.dumps({
                "escrow_id": result.escrow_id,
                "status": result.status.value,
                "tx_hash": result.tx_hash,
                "reason_hash": result.reason_hash,
            })
        except Exception as e:
            return json.dumps({"error": str(e)})

    elif name == "swarmpay_escrow_refund":
        agent_id = arguments["agent_id"]
        if agent_id not in _wallets:
            return json.dumps({"error": f"Agent '{agent_id}' has no wallet."})
        wallet = _wallets[agent_id]
        try:
            result = sp.refund_onchain_escrow(wallet, int(arguments["escrow_nonce"]))
            return json.dumps({
                "escrow_id": result.escrow_id,
                "status": result.status.value,
                "tx_hash": result.tx_hash,
            })
        except Exception as e:
            return json.dumps({"error": str(e)})

    return json.dumps({"error": f"Unknown tool: {name}"})


# ── MCP Protocol (JSON-RPC over stdio) ───────────────────────

def send_response(response_id, result):
    """Sendet eine JSON-RPC Response über stdout."""
    response = {"jsonrpc": "2.0", "id": response_id, "result": result}
    msg = json.dumps(response)
    sys.stdout.write(f"Content-Length: {len(msg)}\r\n\r\n{msg}")
    sys.stdout.flush()


def send_error(response_id, code, message):
    """Sendet einen JSON-RPC Error."""
    response = {
        "jsonrpc": "2.0",
        "id": response_id,
        "error": {"code": code, "message": message},
    }
    msg = json.dumps(response)
    sys.stdout.write(f"Content-Length: {len(msg)}\r\n\r\n{msg}")
    sys.stdout.flush()


def handle_request(request: dict):
    """Verarbeitet einen eingehenden MCP Request."""
    method = request.get("method", "")
    req_id = request.get("id")
    params = request.get("params", {})

    if method == "initialize":
        send_response(req_id, {
            "protocolVersion": "2024-11-05",
            "capabilities": {"tools": {"listChanged": False}},
            "serverInfo": {
                "name": "swarmpay",
                "version": "0.1.0",
                "description": "SwarmPay – The Payment Layer for AI Agents",
            },
        })

    elif method == "notifications/initialized":
        pass  # Keine Antwort nötig

    elif method == "tools/list":
        send_response(req_id, {"tools": TOOLS})

    elif method == "tools/call":
        tool_name = params.get("name", "")
        arguments = params.get("arguments", {})
        try:
            result_text = handle_tool(tool_name, arguments)
            send_response(req_id, {
                "content": [{"type": "text", "text": result_text}],
            })
        except Exception as e:
            sys.stderr.write(f"[SwarmPay MCP] Tool error: {e}\n")
            send_response(req_id, {
                "content": [{"type": "text", "text": json.dumps({"error": "Internal error. Check server logs."})}],
                "isError": True,
            })

    elif method == "ping":
        send_response(req_id, {})

    else:
        if req_id is not None:
            send_error(req_id, -32601, f"Method not found: {method}")


def main():
    """MCP Server Hauptschleife – liest JSON-RPC über stdin."""
    while True:
        try:
            # Content-Length Header lesen
            header = ""
            while True:
                line = sys.stdin.readline()
                if not line or line.strip() == "":
                    break
                header += line

            if not header:
                break

            # Content-Length extrahieren
            content_length = 0
            for h in header.split("\n"):
                if h.lower().startswith("content-length:"):
                    content_length = int(h.split(":")[1].strip())

            if content_length == 0:
                continue

            # Body lesen
            body = sys.stdin.read(content_length)
            request = json.loads(body)
            handle_request(request)

        except json.JSONDecodeError:
            continue
        except KeyboardInterrupt:
            break
        except Exception as e:
            sys.stderr.write(f"[SwarmPay MCP] Error: {e}\n")
            continue


if __name__ == "__main__":
    main()
