"""Microstructure Invariance pipeline functions.

Pipeline functions:
    invariance_monitor - Real-time invariance analysis per-market
"""

from __future__ import annotations

from typing import Any, Callable

from horizon._horizon import (
    invariance_analysis,
    kyle_obizhaeva_impact,
    trading_activity,
)
from horizon.context import Context


def invariance_monitor(
    feed: str,
    window: int = 100,
) -> Callable[[Context], dict[str, Any]]:
    """Create a microstructure invariance monitoring pipeline function.

    Tracks dollar volume and volatility to compute invariance metrics
    in real-time, detecting informed trading activity.

    Args:
        feed: Feed name to read trade data from.
        window: Rolling window for volatility estimation.

    Returns:
        Pipeline function: (Context) -> dict with keys:
            trading_activity, invariant_bet_size, impact,
            efficiency_score, is_informed
    """
    from horizon._horizon import auth_require_pro
    auth_require_pro()

    price_histories: dict[str, list[float]] = {}
    volume_accum: dict[str, float] = {}
    trade_counts: dict[str, int] = {}

    def _invariance_monitor(ctx: Context) -> dict[str, Any]:
        market_id = ctx.market.id if ctx.market else "__default__"
        fd = ctx.feeds.get(feed)

        if market_id not in price_histories:
            price_histories[market_id] = []
            volume_accum[market_id] = 0.0
            trade_counts[market_id] = 0

        prices = price_histories[market_id]

        result = {
            "trading_activity": 0.0,
            "invariant_bet_size": 0.0,
            "impact": 0.0,
            "efficiency_score": 0.0,
            "is_informed": False,
        }

        if fd is None or fd.price <= 0:
            return result

        prices.append(fd.price)
        if len(prices) > window:
            prices[:] = prices[-window:]

        vol_24h = fd.volume_24h if fd.volume_24h > 0 else 0.0
        volume_accum[market_id] += fd.last_trade_size if fd.last_trade_size > 0 else 0.0
        trade_counts[market_id] += 1

        if len(prices) >= 3 and vol_24h > 0:
            # Estimate volatility from returns
            returns = [
                (prices[i] - prices[i - 1]) / prices[i - 1]
                for i in range(1, len(prices))
                if prices[i - 1] > 0
            ]
            if returns:
                import math
                vol = math.sqrt(sum(r * r for r in returns) / len(returns))
                vol = max(vol, 1e-8)

                w = trading_activity(vol_24h, vol)
                avg_trade = volume_accum[market_id] / max(trade_counts[market_id], 1)

                try:
                    analysis = invariance_analysis(
                        vol_24h, vol, max(trade_counts[market_id], 1), max(avg_trade, 1e-8)
                    )
                    result["trading_activity"] = analysis.trading_activity
                    result["invariant_bet_size"] = analysis.bet_size
                    result["impact"] = analysis.impact_per_bet
                    result["efficiency_score"] = analysis.market_efficiency_score
                except (ValueError, RuntimeError):
                    pass

                if avg_trade > 0:
                    result["impact"] = kyle_obizhaeva_impact(avg_trade, vol_24h, vol)

        return result

    _invariance_monitor.__name__ = "invariance_monitor"
    return _invariance_monitor
