"""Factory functions for constructing Keiro runtime components.

Provides a single entry point for wiring the protocol-based components
(``Eb1Ensemble``, ``UpstreamPool``) together and into the gateway
serving infrastructure.

Example::

    from keiro.gateway.boot.factory import create_engine

    engine = create_engine()
    result = engine.run(EB1Request(prompt="Hello"))
"""

from __future__ import annotations

import logging
from typing import TYPE_CHECKING

from keiro.ensemble.engine import Eb1Ensemble
from keiro.protocol import EB1Engine, ModelInvoker
from keiro.upstream.pool import UpstreamPool

if TYPE_CHECKING:
    from ember.models.runtime.registry import ModelRegistry

LOG = logging.getLogger(__name__)


def create_engine(
    *,
    registry: ModelRegistry | None = None,
    invoker: ModelInvoker | None = None,
) -> EB1Engine:
    """Construct a fully-wired EB1 ensemble engine.

    If ``invoker`` is not provided, creates an ``UpstreamPool`` backed by
    the given or global ``ModelRegistry``. The ``Eb1Ensemble`` is wired
    with the invoker for future protocol-based execution.

    During migration, the ensemble internally still delegates to
    ``run_plan()`` which calls providers directly. The ``invoker``
    parameter is stored for the transition to protocol-based dispatch.

    Args:
        registry: Explicit ModelRegistry. If None, the global registry
            is resolved lazily on first upstream call.
        invoker: Explicit ModelInvoker implementation. If None, an
            UpstreamPool is created.

    Returns:
        A fully wired EB1Engine implementation.
    """
    if invoker is None:
        invoker = UpstreamPool(registry=registry)

    engine = Eb1Ensemble(invoker=invoker)
    LOG.info("EB1 engine created with %s invoker", type(invoker).__name__)
    return engine


__all__ = ["create_engine"]
