"""Copula Dependence pipeline functions.

Pipeline functions:
    copula_dependence - Track copula-based dependence between two feeds
"""

from __future__ import annotations

from collections import deque
from typing import Any, Callable

from horizon.context import Context


def copula_dependence(
    feed_a: str,
    feed_b: str,
    window: int = 100,
) -> Callable[[Context], dict[str, Any]]:
    """Create a copula dependence monitoring pipeline function.

    Fits copula models to track tail dependence and non-linear
    correlation between two feeds.

    Args:
        feed_a: First feed name.
        feed_b: Second feed name.
        window: Rolling window for fitting.

    Returns:
        Pipeline function: (Context) -> dict with keys:
            family, parameter, kendall_tau, aic
    """
    from horizon._horizon import auth_require_pro
    auth_require_pro()

    returns_a: dict[str, deque] = {}
    returns_b: dict[str, deque] = {}
    prev_a: dict[str, float] = {}
    prev_b: dict[str, float] = {}
    tick_counts: dict[str, int] = {}

    def _copula_dependence(ctx: Context) -> dict[str, Any]:
        market_id = ctx.market.id if ctx.market else "__default__"
        fd_a = ctx.feeds.get(feed_a)
        fd_b = ctx.feeds.get(feed_b)

        if market_id not in returns_a:
            returns_a[market_id] = deque(maxlen=window)
            returns_b[market_id] = deque(maxlen=window)
            prev_a[market_id] = 0.0
            prev_b[market_id] = 0.0
            tick_counts[market_id] = 0

        result = {
            "family": "unknown",
            "parameter": 0.0,
            "kendall_tau": 0.0,
            "aic": 0.0,
        }

        if fd_a is not None and fd_b is not None and fd_a.price > 0 and fd_b.price > 0:
            if prev_a[market_id] > 0 and prev_b[market_id] > 0:
                ra = (fd_a.price - prev_a[market_id]) / prev_a[market_id]
                rb = (fd_b.price - prev_b[market_id]) / prev_b[market_id]
                returns_a[market_id].append(ra)
                returns_b[market_id].append(rb)

            prev_a[market_id] = fd_a.price
            prev_b[market_id] = fd_b.price
            tick_counts[market_id] += 1

        # Fit copula periodically
        if (
            len(returns_a.get(market_id, [])) >= 20
            and tick_counts.get(market_id, 0) % 50 == 0
        ):
            try:
                from horizon._horizon import best_copula, rank_transform

                ra = list(returns_a[market_id])
                rb = list(returns_b[market_id])
                u = rank_transform(ra)
                v = rank_transform(rb)

                fit = best_copula(u, v)
                result["family"] = repr(fit.family)
                result["parameter"] = round(fit.parameter, 4)
                result["kendall_tau"] = round(fit.kendall_tau, 4)
                result["aic"] = round(fit.aic, 2)
            except (ValueError, RuntimeError):
                pass

        return result

    _copula_dependence.__name__ = "copula_dependence"
    return _copula_dependence
