"""Almgren-Chriss Liquidation pipeline functions.

Pipeline functions:
    ac_liquidator - Optimal liquidation schedule
"""

from __future__ import annotations

from typing import Any, Callable

from horizon._horizon import ac_optimal_schedule
from horizon.context import Context


def ac_liquidator(
    feed: str,
    total_shares: float = 1000.0,
    n_steps: int = 20,
    permanent_impact: float = 0.001,
    temporary_impact: float = 0.01,
    risk_aversion: float = 1e-6,
) -> Callable[[Context], dict[str, Any]]:
    """Create an Almgren-Chriss liquidation pipeline function.

    Computes optimal liquidation schedule minimizing execution cost
    with risk aversion.

    Args:
        feed: Feed name for price/volatility data.
        total_shares: Total shares to liquidate.
        n_steps: Number of time steps.
        permanent_impact: Permanent impact coefficient.
        temporary_impact: Temporary impact coefficient.
        risk_aversion: Risk aversion parameter.

    Returns:
        Pipeline function: (Context) -> dict with keys:
            next_trade, expected_cost, variance, remaining
    """
    from horizon._horizon import auth_require_ultra
    auth_require_ultra()

    step_counts: dict[str, int] = {}
    schedules: dict[str, list] = {}

    def _ac_liquidator(ctx: Context) -> dict[str, Any]:
        market_id = ctx.market.id if ctx.market else "__default__"
        fd = ctx.feeds.get(feed)

        if market_id not in step_counts:
            step_counts[market_id] = 0
            schedules[market_id] = []

        result = {
            "next_trade": 0.0,
            "expected_cost": 0.0,
            "variance": 0.0,
            "remaining": total_shares,
        }

        if fd is not None and fd.price > 0:
            vol = max(ctx.params.get("volatility", 0.02), 0.001)

            # Recompute schedule if not yet done
            if not schedules[market_id]:
                try:
                    traj = ac_optimal_schedule(
                        total_shares, n_steps, vol,
                        permanent_impact, temporary_impact, risk_aversion,
                    )
                    schedules[market_id] = list(traj.schedule)
                    result["expected_cost"] = traj.expected_cost
                    result["variance"] = traj.variance
                except (ValueError, RuntimeError):
                    pass

            schedule = schedules[market_id]
            step = step_counts[market_id]

            if schedule and step < len(schedule) - 1:
                result["next_trade"] = schedule[step] - schedule[step + 1]
                result["remaining"] = schedule[step]
                step_counts[market_id] += 1

        return result

    _ac_liquidator.__name__ = "ac_liquidator"
    return _ac_liquidator
