"""Unified deploy server wrappers."""

from __future__ import annotations

from typing import TYPE_CHECKING, Any


if TYPE_CHECKING:
    from collections.abc import Callable


def _default_matrice_deploy_factory(
    load_model: Callable[[Any], Any],
    predict: Callable[[Any, bytes], Any],
    action_id: str,
    port: int,
) -> Any:
    """Construct a ``matrice.deploy.MatriceDeploy`` server instance.

    Args:
        load_model: Callable that loads and returns model state.
        predict: Callable that performs inference from model and bytes input.
        action_id: Platform action identifier for deployment tracking.
        port: External server port.

    Returns:
        Initialized ``MatriceDeploy`` server object.
    """
    from matrice.deploy import MatriceDeploy  # type: ignore[reportMissingImports]

    return MatriceDeploy(load_model, predict, action_id, port)


def _default_matrice_inference_factory(
    load_model: Callable[[Any], Any],
    predict: Callable[[Any, bytes], Any],
    action_id: str,
    port: int,
) -> Any:
    """Construct a ``matrice_inference.MatriceDeployServer`` instance.

    Args:
        load_model: Callable that loads and returns model state.
        predict: Callable that performs inference from model and bytes input.
        action_id: Platform action identifier for deployment tracking.
        port: External server port.

    Returns:
        Initialized ``MatriceDeployServer`` object.
    """
    from matrice_inference import MatriceDeployServer  # type: ignore[reportMissingImports]

    return MatriceDeployServer(
        load_model=load_model,
        predict=predict,
        action_id=action_id,
        external_port=int(port),
    )


def create_deploy_server(
    *,
    load_model: Callable[[Any], Any],
    predict: Callable[[Any, bytes], Any],
    action_id: str,
    port: int,
    backend: str = "matrice_deploy",
    server_factory: Callable[[Callable[[Any], Any], Callable[[Any, bytes], Any], str, int], Any] | None = None,
) -> Any:
    """Create a deploy server instance from backend or custom factory.

    Args:
        load_model: Callable that loads and returns model state.
        predict: Callable that performs inference from model and bytes input.
        action_id: Platform action identifier for deployment tracking.
        port: External server port.
        backend: Backend selector for built-in server implementations.
        server_factory: Optional custom server factory override.

    Returns:
        Deploy server object supporting ``start_server`` or ``start``.
    """
    if server_factory is not None:
        return server_factory(load_model, predict, action_id, int(port))

    backend_key = backend.strip().lower()
    if backend_key == "matrice_deploy":
        return _default_matrice_deploy_factory(load_model, predict, action_id, int(port))
    if backend_key == "matrice_inference":
        return _default_matrice_inference_factory(load_model, predict, action_id, int(port))

    raise ValueError(
        f"Unsupported deploy backend '{backend}'. "
        "Use 'matrice_deploy', 'matrice_inference', or provide `server_factory`."
    )


def start_deploy_server(
    *,
    load_model: Callable[[Any], Any],
    predict: Callable[[Any, bytes], Any],
    action_id: str,
    port: int,
    backend: str = "matrice_deploy",
    server_factory: Callable[[Callable[[Any], Any], Callable[[Any, bytes], Any], str, int], Any] | None = None,
) -> Any:
    """Create and start a deploy server using known start hooks.

    Args:
        load_model: Callable that loads and returns model state.
        predict: Callable that performs inference from model and bytes input.
        action_id: Platform action identifier for deployment tracking.
        port: External server port.
        backend: Backend selector for built-in server implementations.
        server_factory: Optional custom server factory override.

    Returns:
        Started deploy server object.
    """
    server = create_deploy_server(
        load_model=load_model,
        predict=predict,
        action_id=action_id,
        port=int(port),
        backend=backend,
        server_factory=server_factory,
    )

    if hasattr(server, "start_server"):
        server.start_server()
        return server
    if hasattr(server, "start"):
        server.start()
        return server

    raise AttributeError(
        "Deploy server object has no supported start method. "
        "Expected `start_server()` or `start()`."
    )
