from __future__ import annotations

from dataclasses import dataclass
from typing import Any


@dataclass(frozen=True)
class RayServeClient:
    """
    Minimal Ray Serve client wrapper.

    This is intentionally tiny and uses runtime imports so that:
    - unit tests can stub `ray` modules without needing real Ray installed
    - production can run with the real Ray Serve stack (v3.8+)
    """

    http_port: int = 8000
    proxy_location: str = "HeadOnly"
    ray_init_address: str = "auto"

    def ensure_started(self) -> None:
        import ray  # runtime import

        # Scheduler already calls ray.init(); make this idempotent.
        ray.init(address=self.ray_init_address, ignore_reinit_error=True, log_to_driver=False)  # type: ignore[call-arg]

        # Import serve lazily to allow tests to stub it.
        from ray import serve  # type: ignore

        serve.start(proxy_location=self.proxy_location, http_options={"host": "0.0.0.0", "port": int(self.http_port)})

    def apply_app(self, *, app: Any, app_name: str, route_prefix: str = "/") -> Any:
        from ray import serve  # type: ignore

        # If Ray Serve LLM isn't available, callers may pass a plain dict placeholder.
        # Running that through serve.run() results in a confusing TypeError; fail fast.
        if isinstance(app, dict):
            raise ValueError("invalid serve app object (Ray Serve LLM not available or build_openai_app failed)")

        return serve.run(app, name=app_name, route_prefix=route_prefix)

    def get_status(self) -> Any:
        from ray import serve  # type: ignore

        return serve.status()

    def delete_app(self, *, app_name: str) -> Any:
        from ray import serve  # type: ignore

        return serve.delete(app_name)
