"""Market-making arbitrage: quote on one exchange, hedge on another.

Earn spread on the quoting exchange while maintaining delta neutrality
by hedging on a second exchange. Combines Avellaneda-Stoikov market
making with cross-venue hedging.
"""

from __future__ import annotations

import logging
from dataclasses import dataclass
from typing import Callable

from horizon._horizon import Quote, reservation_price, optimal_spread
from horizon.context import Context

logger = logging.getLogger(__name__)


@dataclass
class MMArbConfig:
    """Configuration for market-making arbitrage."""

    quote_exchange: str
    hedge_exchange: str
    quote_feed: str
    hedge_feed: str
    base_spread: float = 0.04
    gamma: float = 0.5
    max_position: float = 100.0
    hedge_threshold: float = 10.0
    hedge_aggression: float = 0.01
    size: float = 5.0


def mm_arb(
    config: MMArbConfig,
) -> Callable[[Context], list[Quote]]:
    """Create a pipeline function for market-making arbitrage.

    Generates Avellaneda-Stoikov quotes on the quoting exchange.
    When delta (net position) exceeds the hedge threshold, submits
    aggressive FOK orders on the hedge exchange to neutralize.

    Args:
        config: MMArbConfig with exchange/feed/parameter configuration.

    Returns:
        Pipeline function: (Context) -> list[Quote]
    """
    from horizon._horizon import auth_require_pro
    auth_require_pro()

    cumulative_delta = 0.0

    def _quoter(ctx: Context) -> list[Quote]:
        nonlocal cumulative_delta

        engine = ctx.params.get("engine")
        if engine is None:
            return []

        # Read quote exchange feed
        quote_snap = engine.feed_snapshot(config.quote_feed) if hasattr(engine, "feed_snapshot") else None
        if quote_snap is None:
            return []

        mid = quote_snap.price if quote_snap.price > 0 else (quote_snap.bid + quote_snap.ask) / 2
        if mid <= 0:
            return []

        # Get current position for inventory skew
        inventory = ctx.inventory
        position = inventory.net if inventory else 0.0

        # Track delta from fills
        fills = ctx.params.get("_mm_arb_last_fills", 0)
        current_fills = len(engine.fills()) if hasattr(engine, "fills") else 0
        if current_fills > fills:
            ctx.params["_mm_arb_last_fills"] = current_fills

        # Avellaneda-Stoikov reservation price and optimal spread
        sigma = 0.05  # Default volatility estimate
        t_remaining = 1.0  # Normalized remaining time
        r_price = reservation_price(mid, position, config.gamma, sigma, t_remaining)
        o_spread = optimal_spread(config.gamma, sigma, t_remaining, config.base_spread)

        half = o_spread / 2
        bid = max(0.01, r_price - half)
        ask = min(0.99, r_price + half)

        if bid >= ask:
            return []

        # Hedge when delta exceeds threshold
        if abs(position) > config.hedge_threshold:
            hedge_snap = engine.feed_snapshot(config.hedge_feed) if hasattr(engine, "feed_snapshot") else None
            if hedge_snap is not None:
                try:
                    from horizon._horizon import OrderSide, Side, TimeInForce

                    if position > config.hedge_threshold:
                        # Too long, sell on hedge exchange
                        hedge_price = (hedge_snap.bid - config.hedge_aggression) if hedge_snap.bid > 0 else mid
                        hedge_size = min(abs(position) - config.hedge_threshold / 2, config.max_position)
                        engine.submit_order(
                            ctx.market.id if hasattr(ctx, "market") and ctx.market else "default",
                            Side.Yes, OrderSide.Sell, hedge_size,
                            max(0.01, hedge_price),
                            exchange=config.hedge_exchange,
                        )
                        logger.debug("MM arb hedge: sold %.1f on %s", hedge_size, config.hedge_exchange)
                    elif position < -config.hedge_threshold:
                        hedge_price = (hedge_snap.ask + config.hedge_aggression) if hedge_snap.ask > 0 else mid
                        hedge_size = min(abs(position) - config.hedge_threshold / 2, config.max_position)
                        engine.submit_order(
                            ctx.market.id if hasattr(ctx, "market") and ctx.market else "default",
                            Side.Yes, OrderSide.Buy, hedge_size,
                            min(0.99, hedge_price),
                            exchange=config.hedge_exchange,
                        )
                        logger.debug("MM arb hedge: bought %.1f on %s", hedge_size, config.hedge_exchange)
                except Exception as e:
                    logger.warning("MM arb hedge failed: %s", e)

        return [Quote(bid=bid, ask=ask, size=config.size)]

    _quoter.__name__ = "mm_arb"
    return _quoter
