"""Horizon SDK MCP Server.

Exposes the Horizon trading engine as MCP tools for Claude Code,
Cursor, Claude Desktop, and other MCP-compatible clients.

Run: python -m horizon.mcp
"""

from __future__ import annotations

from mcp.server.fastmcp import FastMCP

from horizon import tools

mcp = FastMCP(
    "horizon-sdk",
    instructions=(
        "Horizon SDK - prediction market trading engine. "
        "Use these tools to check positions, submit orders, manage risk, "
        "discover markets, analyze wallets, check feed health, run Monte Carlo "
        "simulations, execute arbitrage, and compute Kelly-optimal sizing on "
        "Polymarket and Kalshi."
    ),
)


# ---------------------------------------------------------------------------
# Tools
# ---------------------------------------------------------------------------

@mcp.tool()
def engine_status() -> dict:
    """Get trading engine status: PnL, open orders, positions, kill switch state, uptime."""
    return tools.engine_status()


@mcp.tool()
def list_positions() -> list[dict]:
    """List all open positions with size, entry price, PnL, and exchange."""
    return tools.list_positions()


@mcp.tool()
def list_open_orders(market_id: str | None = None) -> list[dict]:
    """List open orders. Optionally filter by market_id."""
    return tools.list_open_orders(market_id)


@mcp.tool()
def list_recent_fills(limit: int = 20) -> list[dict]:
    """List recent trade fills. Default last 20."""
    return tools.list_recent_fills(limit)


@mcp.tool()
def submit_order(market_id: str, side: str, price: float, size: float) -> dict:
    """Submit a limit order. side: 'buy' or 'sell'. price: 0-1 (probability). Returns order ID."""
    return tools.submit_order(market_id, side, price, size)


@mcp.tool()
def cancel_order(order_id: str) -> dict:
    """Cancel a single order by its ID."""
    return tools.cancel_order(order_id)


@mcp.tool()
def cancel_all_orders() -> dict:
    """Cancel ALL open orders across all exchanges. Use with caution."""
    return tools.cancel_all_orders()


@mcp.tool()
def cancel_market_orders(market_id: str) -> dict:
    """Cancel all orders for a specific market."""
    return tools.cancel_market_orders(market_id)


@mcp.tool()
def activate_kill_switch(reason: str) -> dict:
    """EMERGENCY STOP. Activates the kill switch and cancels all orders. Use only in emergencies."""
    return tools.activate_kill_switch(reason)


@mcp.tool()
def deactivate_kill_switch() -> dict:
    """Deactivate the kill switch to resume normal trading."""
    return tools.deactivate_kill_switch()


@mcp.tool()
def get_feed_snapshot(name: str) -> dict:
    """Get the latest price/bid/ask snapshot for a named feed."""
    return tools.get_feed_snapshot(name)


@mcp.tool()
def list_all_feeds() -> list[dict]:
    """List all active feed snapshots with current prices."""
    return tools.list_all_feeds()


@mcp.tool()
def discover_markets(exchange: str = "polymarket", query: str = "", limit: int = 10) -> list[dict]:
    """Search for prediction markets on Polymarket or Kalshi. Returns market name, ID, and metadata."""
    return tools.discover(exchange, query, limit)


@mcp.tool()
def kelly_sizing(
    prob: float,
    price: float,
    bankroll: float = 1000.0,
    fraction: float = 0.25,
    max_size: float = 100.0,
) -> dict:
    """Compute Kelly-optimal position size. prob: estimated probability (0-1). price: market price (0-1)."""
    return tools.kelly_sizing(prob, price, bankroll, fraction, max_size)


@mcp.tool()
def check_parity(market_id: str) -> dict:
    """Check YES/NO price parity for a market. Detects if prices deviate from summing to 1.0."""
    return tools.check_parity(market_id)


@mcp.tool()
def add_stop_loss(
    market_id: str, side: str, order_side: str, size: float, trigger: float
) -> dict:
    """Add a stop-loss order. side: 'yes'/'no'. order_side: 'buy'/'sell'. Triggers at price."""
    return tools.add_stop_loss(market_id, side, order_side, size, trigger)


@mcp.tool()
def add_take_profit(
    market_id: str, side: str, order_side: str, size: float, trigger: float
) -> dict:
    """Add a take-profit order. side: 'yes'/'no'. order_side: 'buy'/'sell'. Triggers at price."""
    return tools.add_take_profit(market_id, side, order_side, size, trigger)


@mcp.tool()
def list_contingent_orders() -> list[dict]:
    """List all pending stop-loss and take-profit orders."""
    return tools.list_contingent_orders()


# ---------------------------------------------------------------------------
# Feed Health
# ---------------------------------------------------------------------------

@mcp.tool()
def check_feed_health(stale_threshold: float = 30.0) -> dict:
    """Check staleness and health of all feeds. Reports which feeds are stale, age in seconds, and whether all feeds are down."""
    return tools.check_feed_health(stale_threshold)


# ---------------------------------------------------------------------------
# Discovery
# ---------------------------------------------------------------------------

@mcp.tool()
def discover_events(query: str = "", limit: int = 10, min_volume: float = 0.0) -> list[dict]:
    """Discover multi-outcome events on Polymarket. Returns events with all outcomes and prices."""
    return tools.discover_event(query, limit, min_volume)


@mcp.tool()
def top_markets(exchange: str = "polymarket", limit: int = 10, category: str = "") -> list[dict]:
    """Get the highest-volume active markets. Exchange: 'polymarket' or 'kalshi'."""
    return tools.get_top_markets(exchange, limit, category)


# ---------------------------------------------------------------------------
# Wallet Analytics (Polymarket public - no auth needed)
# ---------------------------------------------------------------------------

@mcp.tool()
def get_wallet_trades(address: str, limit: int = 50, condition_id: str | None = None) -> list[dict]:
    """Fetch trade history for a Polymarket wallet address (0x...). No auth required."""
    return tools.wallet_trades(address, limit, condition_id)


@mcp.tool()
def get_market_trades(condition_id: str, limit: int = 50, side: str | None = None, min_size: float = 0.0) -> list[dict]:
    """Fetch recent trades for a Polymarket market by condition ID. Filter by side ('BUY'/'SELL') and min USDC size."""
    return tools.market_trades(condition_id, limit, side, min_size)


@mcp.tool()
def get_wallet_positions(address: str, limit: int = 50, sort_by: str = "CURRENT") -> list[dict]:
    """Fetch open positions for a Polymarket wallet. Sort: TOKENS, CURRENT, INITIAL, CASHPNL, PERCENTPNL, PRICE, AVGPRICE."""
    return tools.wallet_positions(address, limit, sort_by)


@mcp.tool()
def get_wallet_value(address: str) -> dict:
    """Get total USD value of all open positions in a Polymarket wallet."""
    return tools.wallet_value(address)


@mcp.tool()
def get_wallet_profile(address: str) -> dict:
    """Get public profile for a Polymarket wallet: pseudonym, name, bio, X handle."""
    return tools.wallet_profile(address)


@mcp.tool()
def get_top_holders(condition_id: str, limit: int = 20) -> list[dict]:
    """Get top token holders for a Polymarket market. Returns wallet, amount, and optional pseudonym."""
    return tools.market_top_holders(condition_id, limit)


@mcp.tool()
def analyze_market_flow(condition_id: str, trade_limit: int = 500, top_n: int = 10) -> dict:
    """Analyze trade flow for a market: buy/sell volume, net flow, unique wallets, top buyers/sellers."""
    return tools.market_flow(condition_id, trade_limit, top_n)


# ---------------------------------------------------------------------------
# Simulation
# ---------------------------------------------------------------------------

@mcp.tool()
def simulate_portfolio(scenarios: int = 10000, seed: int | None = None) -> dict:
    """Run Monte Carlo simulation on current engine positions. Returns VaR, CVaR, win probability, mean/median PnL."""
    return tools.simulate_portfolio(scenarios, seed)


# ---------------------------------------------------------------------------
# Arbitrage
# ---------------------------------------------------------------------------

@mcp.tool()
def execute_arbitrage(
    market_id: str,
    buy_exchange: str,
    sell_exchange: str,
    buy_price: float,
    sell_price: float,
    size: float,
) -> dict:
    """Execute atomic cross-exchange arbitrage. Buys on one exchange, sells on another. Auto-cancels buy if sell fails."""
    return tools.execute_arb(market_id, buy_exchange, sell_exchange, buy_price, sell_price, size)


# ---------------------------------------------------------------------------
# Resources
# ---------------------------------------------------------------------------

@mcp.resource("horizon://status")
def resource_status() -> str:
    """Current engine status as JSON context."""
    import json
    return json.dumps(tools.engine_status(), indent=2)


@mcp.resource("horizon://positions")
def resource_positions() -> str:
    """Current positions as JSON context."""
    import json
    return json.dumps(tools.list_positions(), indent=2)


# ---------------------------------------------------------------------------
# Entry point
# ---------------------------------------------------------------------------

def main() -> None:
    """Run the MCP server on stdio transport."""
    mcp.run(transport="stdio")
