"""Cross-Impact Matrix pipeline functions.

Pipeline functions:
    cross_impact_monitor - Monitor cross-market price impact
"""

from __future__ import annotations

from typing import Any, Callable

from horizon.context import Context


def cross_impact_monitor(
    feeds: list[str],
    lookback: int = 100,
) -> Callable[[Context], None]:
    """Create a cross-impact monitoring pipeline function.

    Estimates cross-market impact matrix and injects results into ctx.params.

    Args:
        feeds: List of feed names to track.
        lookback: Rolling window for estimation.

    Returns:
        Pipeline function: (Context) -> None (injects into ctx.params)
    """
    from horizon._horizon import auth_require_ultra
    auth_require_ultra()

    from horizon._horizon import CrossImpactEstimator

    estimators: dict[str, CrossImpactEstimator] = {}
    prev_prices: dict[str, dict[str, float]] = {}

    def _cross_impact_monitor(ctx: Context) -> None:
        market_id = ctx.market.id if ctx.market else "__default__"

        if market_id not in estimators:
            estimators[market_id] = CrossImpactEstimator(len(feeds), lookback)
            prev_prices[market_id] = {}

        estimator = estimators[market_id]
        prev = prev_prices[market_id]

        returns = []
        volumes = []
        has_all = True

        for feed in feeds:
            fd = ctx.feeds.get(feed)
            if fd is None or fd.price <= 0:
                has_all = False
                break

            p = prev.get(feed, fd.price)
            r = (fd.price - p) / p if p > 0 else 0.0
            returns.append(r)

            vol = fd.volume_24h if fd.volume_24h > 0 else 1.0
            sign = 1.0 if r >= 0 else -1.0
            volumes.append(sign * vol)

            prev[feed] = fd.price

        if has_all and len(returns) == len(feeds):
            estimator.add_observation(returns, volumes)

            try:
                matrix = estimator.estimate()
                ctx.params["cross_impact_matrix"] = matrix.matrix
                ctx.params["cross_impact_psd"] = matrix.is_psd
            except (ValueError, RuntimeError):
                pass

    _cross_impact_monitor.__name__ = "cross_impact_monitor"
    return _cross_impact_monitor
