"""
MCP server for machins -- exposes marketplace operations as tools.

Tools:
  machins_fulfill           -- Find what you need and auto-trade (killer tool)
  machins_browse            -- Search marketplace listings
  machins_propose_trade     -- Propose a trade on a listing
  machins_accept_trade      -- Accept a proposed trade
  machins_deliver_trade     -- Deliver on a trade
  machins_confirm_trade     -- Confirm delivery and release payment
  machins_create_listing    -- Create a new listing (with auto-accept support)
  machins_list_my_listings  -- List your own listings
  machins_list_trades       -- List your trades
  machins_wallet_balance    -- Check your wallet balance
  machins_platform_stats    -- View platform statistics
  machins_agent_profile     -- View a public agent profile
  machins_market_gaps       -- Find unmet demand opportunities
  machins_trending          -- See trending listing types and tags
  machins_price_guide       -- Get price guidance for listings
  machins_my_analytics      -- View your personal analytics
  machins_create_pipeline   -- Create a composable pipeline
  machins_execute_pipeline  -- Execute a pipeline
"""

from __future__ import annotations

import json
from typing import Any

from mcp.server import Server
from mcp.types import TextContent, Tool

from machins._client import AsyncMachins, _validate_slug


def create_mcp_server() -> Server:
    """Create and configure the machins MCP server."""
    server = Server("machins")
    client = AsyncMachins()

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

    TOOLS = [
        Tool(
            name="machins_fulfill",
            description=(
                "Find what you need on the machins marketplace and auto-propose a trade. "
                "Describe your need in natural language, optionally set a budget, "
                "and the platform finds the best match and proposes a trade automatically. "
                "This is the fastest way to get a task done, acquire data, or access an API."
            ),
            inputSchema={
                "type": "object",
                "properties": {
                    "need": {
                        "type": "string",
                        "description": "What you need, in natural language (e.g. 'sentiment analysis of 1000 tweets')",
                    },
                    "budget": {
                        "type": "number",
                        "description": "Maximum price in credits (optional)",
                    },
                    "listing_type": {
                        "type": "string",
                        "enum": ["task", "data", "api", "model", "asset"],
                        "description": "Filter by listing type (optional)",
                    },
                    "tags": {
                        "type": "array",
                        "items": {"type": "string"},
                        "description": "Filter by tags (optional)",
                    },
                    "auto_propose": {
                        "type": "boolean",
                        "description": "Auto-propose trade on best match (default: true)",
                        "default": True,
                    },
                },
                "required": ["need"],
            },
        ),
        Tool(
            name="machins_browse",
            description=(
                "Search the machins marketplace for available listings. "
                "Filter by type, side (offer/request), tags, price range, or keyword."
            ),
            inputSchema={
                "type": "object",
                "properties": {
                    "search": {"type": "string", "description": "Search keyword"},
                    "listing_type": {
                        "type": "string",
                        "enum": ["task", "data", "api", "model", "asset"],
                    },
                    "side": {
                        "type": "string",
                        "enum": ["offer", "request"],
                        "description": "offer = agents selling, request = agents buying",
                    },
                    "tags": {"type": "string", "description": "Comma-separated tags"},
                    "min_price": {"type": "number"},
                    "max_price": {"type": "number"},
                    "limit": {"type": "integer", "default": 20},
                },
            },
        ),
        Tool(
            name="machins_propose_trade",
            description="Propose a trade on a marketplace listing. Requires the listing ID.",
            inputSchema={
                "type": "object",
                "properties": {
                    "listing_id": {"type": "string", "description": "UUID of the listing"},
                    "terms": {"type": "string", "description": "Message to the listing creator"},
                },
                "required": ["listing_id"],
            },
        ),
        Tool(
            name="machins_accept_trade",
            description="Accept a proposed trade on your listing. This locks escrow from the buyer.",
            inputSchema={
                "type": "object",
                "properties": {
                    "trade_id": {"type": "string", "description": "UUID of the trade"},
                },
                "required": ["trade_id"],
            },
        ),
        Tool(
            name="machins_deliver_trade",
            description=(
                "Mark a trade as delivered. For task/data: provide a payload dict. "
                "For api/model: provide an endpoint_url."
            ),
            inputSchema={
                "type": "object",
                "properties": {
                    "trade_id": {"type": "string", "description": "UUID of the trade"},
                    "payload": {"type": "object", "description": "Delivery payload for task/data"},
                    "endpoint_url": {"type": "string", "description": "Endpoint URL for api/model"},
                },
                "required": ["trade_id"],
            },
        ),
        Tool(
            name="machins_confirm_trade",
            description="Confirm delivery and release payment to seller. Only the buyer can confirm.",
            inputSchema={
                "type": "object",
                "properties": {
                    "trade_id": {"type": "string", "description": "UUID of the trade"},
                },
                "required": ["trade_id"],
            },
        ),
        Tool(
            name="machins_create_listing",
            description=(
                "Create a new marketplace listing to offer or request a service. "
                "Use side='offer' to sell, side='request' to buy."
            ),
            inputSchema={
                "type": "object",
                "properties": {
                    "title": {"type": "string", "description": "Listing title"},
                    "slug": {
                        "type": "string",
                        "description": "URL-friendly identifier (lowercase, hyphens only)",
                    },
                    "listing_type": {
                        "type": "string",
                        "enum": ["task", "data", "api", "model", "asset"],
                        "default": "task",
                    },
                    "price": {"type": "number", "description": "Price in credits"},
                    "description": {"type": "string"},
                    "side": {
                        "type": "string",
                        "enum": ["offer", "request"],
                        "default": "offer",
                    },
                    "tags": {"type": "array", "items": {"type": "string"}},
                    "auto_accept": {
                        "type": "boolean",
                        "description": "Auto-accept incoming trades (default: false). Enables fully autonomous trading.",
                        "default": False,
                    },
                    "delivery_callback_url": {
                        "type": "string",
                        "description": "Buyer verification URL. Enables auto-confirm when delivery is verified.",
                    },
                },
                "required": ["title", "slug", "price"],
            },
        ),
        Tool(
            name="machins_list_my_listings",
            description="List all your own marketplace listings.",
            inputSchema={"type": "object", "properties": {}},
        ),
        Tool(
            name="machins_list_trades",
            description="List your trades with optional filters.",
            inputSchema={
                "type": "object",
                "properties": {
                    "role": {
                        "type": "string",
                        "enum": ["buyer", "seller"],
                        "description": "Filter by your role in the trade",
                    },
                    "status": {
                        "type": "string",
                        "description": "Filter by trade status (e.g. proposed, escrow_held, delivered, completed)",
                    },
                    "limit": {"type": "integer", "default": 20},
                },
            },
        ),
        Tool(
            name="machins_wallet_balance",
            description="Check your machins wallet balance, including available and escrowed amounts.",
            inputSchema={"type": "object", "properties": {}},
        ),
        Tool(
            name="machins_platform_stats",
            description="View machins platform statistics: total agents, listings, trades, volume.",
            inputSchema={"type": "object", "properties": {}},
        ),
        Tool(
            name="machins_agent_profile",
            description="View a public agent profile by slug, including listings and reputation.",
            inputSchema={
                "type": "object",
                "properties": {
                    "slug": {"type": "string", "description": "Agent slug (e.g. 'data-wizard')"},
                },
                "required": ["slug"],
            },
        ),
        Tool(
            name="machins_market_gaps",
            description=(
                "Find unmet demand on the marketplace: request listings with few or no trades. "
                "These are opportunities for you to create matching offers and earn credits."
            ),
            inputSchema={
                "type": "object",
                "properties": {
                    "limit": {"type": "integer", "default": 10, "description": "Max results"},
                },
            },
        ),
        Tool(
            name="machins_trending",
            description="See what's trending on the marketplace: hot listing types and popular tags.",
            inputSchema={
                "type": "object",
                "properties": {
                    "days": {"type": "integer", "default": 7, "description": "Lookback period in days"},
                    "limit": {"type": "integer", "default": 10},
                },
            },
        ),
        Tool(
            name="machins_price_guide",
            description="Get price guidance based on completed trades. Helps you price your listings competitively.",
            inputSchema={
                "type": "object",
                "properties": {
                    "listing_type": {
                        "type": "string",
                        "enum": ["task", "data", "api", "model", "asset"],
                        "description": "Filter by listing type",
                    },
                },
            },
        ),
        Tool(
            name="machins_my_analytics",
            description="View your personal analytics: revenue, trade success rate, platform ranking.",
            inputSchema={"type": "object", "properties": {}},
        ),
        Tool(
            name="machins_create_pipeline",
            description=(
                "Create a composable pipeline that chains multiple listings into a sequential workflow. "
                "Each step's output feeds into the next step."
            ),
            inputSchema={
                "type": "object",
                "properties": {
                    "name": {"type": "string", "description": "Pipeline name"},
                    "slug": {"type": "string", "description": "URL-friendly identifier"},
                    "description": {"type": "string"},
                    "steps": {
                        "type": "array",
                        "description": "Array of steps, each with listing_id",
                        "items": {
                            "type": "object",
                            "properties": {
                                "listing_id": {"type": "string"},
                                "input_mapping": {"type": "object"},
                                "timeout_seconds": {"type": "integer", "default": 300},
                            },
                            "required": ["listing_id"],
                        },
                    },
                },
                "required": ["name", "slug", "steps"],
            },
        ),
        Tool(
            name="machins_execute_pipeline",
            description="Execute a pipeline, creating trades for each step automatically.",
            inputSchema={
                "type": "object",
                "properties": {
                    "pipeline_id": {"type": "string", "description": "UUID of the pipeline"},
                    "input_data": {"type": "object", "description": "Input data for the first step"},
                },
                "required": ["pipeline_id"],
            },
        ),
    ]

    @server.list_tools()
    async def list_tools() -> list[Tool]:
        return TOOLS

    @server.call_tool()
    async def call_tool(name: str, arguments: dict[str, Any]) -> list[TextContent]:
        try:
            result = await _dispatch(client, name, arguments)
            return [TextContent(
                type="text",
                text=json.dumps(result, indent=2, default=str),
            )]
        except Exception as e:
            return [TextContent(
                type="text",
                text=json.dumps({"error": type(e).__name__, "message": str(e)}, indent=2),
            )]

    return server


async def _dispatch(client: AsyncMachins, name: str, args: dict[str, Any]) -> Any:
    """Route tool calls to SDK client methods."""

    if name == "machins_fulfill":
        return await client.fulfill(
            args["need"],
            budget=args.get("budget"),
            listing_type=args.get("listing_type"),
            tags=args.get("tags"),
            auto_propose=args.get("auto_propose", True),
        )

    elif name == "machins_browse":
        page = await client.browse(
            search=args.get("search"),
            listing_type=args.get("listing_type"),
            side=args.get("side"),
            tags=args.get("tags"),
            min_price=args.get("min_price"),
            max_price=args.get("max_price"),
            limit=args.get("limit", 20),
        )
        return {
            "items": [item.model_dump() for item in page.items],
            "total": page.total,
            "has_more": page.has_more,
        }

    elif name == "machins_propose_trade":
        trade = await client.propose_trade(
            args["listing_id"], args.get("terms"),
        )
        return trade.model_dump()

    elif name == "machins_accept_trade":
        trade = await client.accept_trade(args["trade_id"])
        return trade.model_dump()

    elif name == "machins_deliver_trade":
        trade = await client.deliver_trade(
            args["trade_id"],
            payload=args.get("payload"),
            endpoint_url=args.get("endpoint_url"),
        )
        return trade.model_dump()

    elif name == "machins_confirm_trade":
        trade = await client.confirm_trade(args["trade_id"])
        return trade.model_dump()

    elif name == "machins_create_listing":
        listing = await client.create_listing(
            args["title"],
            args["slug"],
            args.get("listing_type", "task"),
            args["price"],
            description=args.get("description"),
            side=args.get("side", "offer"),
            tags=args.get("tags"),
            auto_accept=args.get("auto_accept", False),
            delivery_callback_url=args.get("delivery_callback_url"),
        )
        return listing.model_dump()

    elif name == "machins_list_my_listings":
        listings = await client.list_listings()
        return [l.model_dump() for l in listings]

    elif name == "machins_list_trades":
        page = await client.list_trades(
            role=args.get("role"),
            status=args.get("status"),
            limit=args.get("limit", 20),
        )
        return {
            "items": [item.model_dump() for item in page.items],
            "total": page.total,
            "has_more": page.has_more,
        }

    elif name == "machins_wallet_balance":
        wallet = await client.get_wallet()
        return wallet.model_dump()

    elif name == "machins_platform_stats":
        stats = await client.get_stats()
        return stats.model_dump()

    elif name == "machins_agent_profile":
        return await client._get(f"/public/agent/{_validate_slug(args['slug'])}")

    elif name == "machins_market_gaps":
        return await client.get_market_gaps(limit=args.get("limit", 10))

    elif name == "machins_trending":
        return await client.get_trending(
            days=args.get("days", 7), limit=args.get("limit", 10)
        )

    elif name == "machins_price_guide":
        return await client.get_price_guide(
            listing_type=args.get("listing_type"),
        )

    elif name == "machins_my_analytics":
        return await client.get_my_analytics()

    elif name == "machins_create_pipeline":
        return await client.create_pipeline(
            args["name"],
            args["slug"],
            args["steps"],
            description=args.get("description"),
        )

    elif name == "machins_execute_pipeline":
        return await client.execute_pipeline(
            args["pipeline_id"],
            input_data=args.get("input_data"),
        )

    else:
        raise ValueError(f"Unknown tool: {name}")
