"""EVA Algebra — composition operators for monomers."""

from typing import Any, Callable

F = Callable[..., Any]


def seq(f: F, g: F) -> F:
    """Sequential composition: g(f(x))."""
    def _seq(*args: Any, **kwargs: Any) -> Any:
        return g(f(*args, **kwargs))
    return _seq


def par(f: F, g: F) -> Callable[[Any, Any], tuple[Any, Any]]:
    """Parallel composition: (f(a), g(b))."""
    def _par(a: Any, b: Any) -> tuple[Any, Any]:
        return (f(a), g(b))
    return _par


def cond(predicate: Callable[[Any], bool], then_fn: F, else_fn: F) -> F:
    """Conditional composition: then_fn(x) if predicate(x) else else_fn(x)."""
    def _cond(*args: Any, **kwargs: Any) -> Any:
        if predicate(*args, **kwargs):
            return then_fn(*args, **kwargs)
        return else_fn(*args, **kwargs)
    return _cond


def pipeline(*fns: F) -> F:
    """Chain N functions sequentially: fN(...f2(f1(x)))."""
    def _pipeline(*args: Any, **kwargs: Any) -> Any:
        result = fns[0](*args, **kwargs)
        for fn in fns[1:]:
            result = fn(result)
        return result
    return _pipeline


def compose(*fns: F) -> F:
    """Reverse pipeline: f1(f2(...fN(x)))."""
    return pipeline(*reversed(fns))
