"""Graph/Network Analysis pipeline functions.

Pipeline functions:
    market_network - Build and analyze market correlation networks
"""

from __future__ import annotations

from collections import deque
from typing import Any, Callable

from horizon.context import Context


def market_network(
    feeds: list[str],
    window: int = 100,
    threshold: float = 0.5,
) -> Callable[[Context], dict[str, Any]]:
    """Create a market network analysis pipeline function.

    Builds a correlation graph from multiple feeds and analyzes
    network structure including communities and centrality.

    Args:
        feeds: List of feed names to include.
        window: Rolling window for correlation estimation.
        threshold: Correlation threshold for edge creation.

    Returns:
        Pipeline function: (Context) -> dict with keys:
            density, n_communities, central_market, contagion_risk
    """
    from horizon._horizon import auth_require_pro
    auth_require_pro()

    price_histories: dict[str, deque] = {}
    tick_count = [0]

    def _market_network(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

        result = {
            "density": 0.0,
            "n_communities": 0,
            "central_market": "",
            "contagion_risk": 0.0,
        }

        # Only recompute every window ticks
        if tick_count[0] % window != 0:
            return result

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

        if min_len < 10 or len(feeds) < 2:
            return result

        try:
            from horizon._horizon import build_correlation_graph

            # Build returns and correlation matrix
            n = len(feeds)
            returns_data = []
            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_data.append(rets)

            # Compute correlation matrix
            m = min(len(r) for r in returns_data)
            if m < 5:
                return result

            corr = [[0.0] * n for _ in range(n)]
            for i in range(n):
                corr[i][i] = 1.0
                for j in range(i + 1, n):
                    ri = returns_data[i][:m]
                    rj = returns_data[j][:m]
                    mean_i = sum(ri) / m
                    mean_j = sum(rj) / m
                    cov = sum((ri[k] - mean_i) * (rj[k] - mean_j) for k in range(m)) / m
                    var_i = sum((ri[k] - mean_i) ** 2 for k in range(m)) / m
                    var_j = sum((rj[k] - mean_j) ** 2 for k in range(m)) / m
                    import math
                    denom = math.sqrt(max(var_i, 1e-15) * max(var_j, 1e-15))
                    c = cov / denom if denom > 1e-15 else 0.0
                    corr[i][j] = c
                    corr[j][i] = c

            graph = build_correlation_graph(corr, feeds, threshold)
            result["density"] = graph.density
            result["n_communities"] = len(graph.communities)

            # Find most central node
            if graph.nodes:
                best_node = max(graph.nodes, key=lambda n: n.degree)
                result["central_market"] = best_node.name

        except (ValueError, RuntimeError, ImportError):
            pass

        return result

    _market_network.__name__ = "market_network"
    return _market_network
