"""Vine Copula pipeline functions.

Pipeline functions:
    vine_risk_monitor - Monitor tail risk via vine copulas
"""

from __future__ import annotations

from collections import deque
from typing import Any, Callable

from horizon.context import Context


def vine_risk_monitor(
    feeds: list[str],
    vine_type: str = "dvine",
    window: int = 200,
    refit_interval: int = 100,
) -> Callable[[Context], dict[str, Any]]:
    """Create a vine copula risk monitoring pipeline function.

    Fits vine copulas to multivariate feed data and estimates
    joint tail risk.

    Args:
        feeds: List of feed names to model jointly.
        vine_type: "cvine" or "dvine".
        window: Rolling window for fitting.
        refit_interval: Refit every N ticks.

    Returns:
        Pipeline function: (Context) -> dict with keys:
            tail_risk, n_variables, log_likelihood
    """
    from horizon._horizon import auth_require_ultra
    auth_require_ultra()

    price_histories: dict[str, deque] = {}
    tick_count = [0]
    cached_result: dict[str, Any] = {
        "tail_risk": 0.0,
        "n_variables": 0,
        "log_likelihood": 0.0,
    }

    def _vine_risk_monitor(ctx: Context) -> dict[str, Any]:
        for feed in feeds:
            if feed not in price_histories:
                price_histories[feed] = deque(maxlen=window)
            fd = ctx.feeds.get(feed)
            if fd is not None and fd.price > 0:
                price_histories[feed].append(fd.price)

        tick_count[0] += 1

        if tick_count[0] % refit_interval != 0:
            return cached_result.copy()

        min_len = min(
            (len(price_histories[f]) for f in feeds if f in price_histories),
            default=0,
        )

        if min_len < 30 or len(feeds) < 2:
            return cached_result.copy()

        try:
            from horizon._horizon import fit_vine, vine_tail_risk, VineType, rank_transform

            # Build returns matrix
            returns_matrix = []
            for feed in feeds:
                prices = list(price_histories[feed])[-min_len:]
                rets = [
                    (prices[i] - prices[i - 1]) / prices[i - 1]
                    for i in range(1, len(prices))
                    if prices[i - 1] > 0
                ]
                returns_matrix.append(rank_transform(rets))

            vt = VineType.DVine if vine_type.lower() == "dvine" else VineType.CVine
            vine = fit_vine(returns_matrix, vt)

            tail = vine_tail_risk(vine, 0.05, 1000, 42)

            cached_result["tail_risk"] = round(tail, 6)
            cached_result["n_variables"] = vine.n_variables
            cached_result["log_likelihood"] = round(vine.log_likelihood, 2)

        except (ValueError, RuntimeError, ImportError):
            pass

        return cached_result.copy()

    _vine_risk_monitor.__name__ = "vine_risk_monitor"
    return _vine_risk_monitor
