"""Client middleware composition.

The SDK uses a shared runtime middleware pipeline for both SQL and HTTP execution.
This module translates high-level `ExecutionConfig` knobs into concrete middleware
instances (logging, metrics, retries).

Returned values:
- `middlewares`: ordered list to apply around the base executor
- `metrics`: an in-memory metrics sink (or a no-op sink)
"""

from __future__ import annotations

import logging
from typing import Any, Callable

from relationalai.config.config_fields import ExecutionConfig
from relationalai.runtime.middleware import (
    InMemoryMetricsSink,
    LoggingMiddleware,
    MetricsMiddleware,
    NoOpMetricsSink,
    RetryMiddleware,
    RetryPolicy,
)


def compose_middlewares(
    cfg: ExecutionConfig,
    *,
    is_retryable: Callable[[Exception, Any], bool],
    logger_name: str,
) -> tuple[list[Any], Any]:
    """Compose the middleware chain from generic execution config knobs."""
    enable_logging = cfg.logging
    enable_metrics = cfg.metrics
    enable_retries = cfg.retries.enabled

    retry_policy = RetryPolicy(
        max_attempts=cfg.retries.max_attempts,
        base_delay_s=cfg.retries.base_delay_s,
        max_delay_s=cfg.retries.max_delay_s,
        jitter=cfg.retries.jitter,
    )

    metrics = InMemoryMetricsSink() if enable_metrics else NoOpMetricsSink()
    logger = logging.getLogger(logger_name)

    middlewares: list[Any] = []
    if enable_logging:
        middlewares.append(LoggingMiddleware(logger=logger, enabled=True))
    if enable_metrics:
        middlewares.append(MetricsMiddleware(metrics=metrics))

    if enable_retries:
        middlewares.append(
            RetryMiddleware(
                policy=retry_policy,
                is_retryable=is_retryable,
                logger=logger,
                metrics=metrics,
                enabled=True,
            )
        )

    return middlewares, metrics

