"""Entropy Pooling (Meucci) pipeline functions.

Pipeline functions:
    entropy_pooling - Apply views to scenario probabilities
"""

from __future__ import annotations

from typing import Any, Callable

from horizon.context import Context


def entropy_pooling(
    scenarios: list[list[float]],
    views: list[dict],
) -> Callable[[Context], dict[str, Any]]:
    """Create an entropy pooling pipeline function.

    Applies investor views to scenario probabilities using
    Meucci's entropy pooling (minimum relative entropy).

    Args:
        scenarios: Matrix of scenarios (rows=scenarios, cols=assets).
        views: List of view dicts with keys: coefficients, bound, is_equality.

    Returns:
        Pipeline function: (Context) -> dict with keys:
            posterior_mean, relative_entropy, effective_scenarios
    """
    from horizon._horizon import auth_require_ultra
    auth_require_ultra()

    from horizon._horizon import entropy_pool, ViewConstraint, posterior_mean

    computed = [False]
    cached: dict[str, Any] = {
        "posterior_mean": [],
        "relative_entropy": 0.0,
        "effective_scenarios": 0.0,
    }

    def _entropy_pooling(ctx: Context) -> dict[str, Any]:
        if computed[0]:
            return cached.copy()

        try:
            n = len(scenarios)
            prior = [1.0 / n] * n

            constraints = []
            for v in views:
                constraints.append(ViewConstraint(
                    coefficients=v.get("coefficients", []),
                    bound=v.get("bound", 0.0),
                    is_equality=v.get("is_equality", True),
                ))

            result = entropy_pool(prior, scenarios, constraints)

            cached["posterior_mean"] = posterior_mean(result.posterior_probs, scenarios)
            cached["relative_entropy"] = result.relative_entropy
            cached["effective_scenarios"] = result.effective_scenarios

            computed[0] = True
        except (ValueError, RuntimeError):
            pass

        return cached.copy()

    _entropy_pooling.__name__ = "entropy_pooling"
    return _entropy_pooling
