"""Global singleton helpers for Omni clients."""

from __future__ import annotations

from contextlib import contextmanager
from contextvars import ContextVar
from pathlib import Path

from omni.client.async_client import AsyncOmniClient
from omni.client.sync_client import OmniClient
from omni.config import ConfigInput


class _GlobalConfig:
    def __init__(self) -> None:
        self.config: ConfigInput | None = None
        self.config_path: str | Path | None = None
        self.state_path: str | Path | None = None


_global_config = _GlobalConfig()
_async_clients: dict[tuple[str | None, str | None], AsyncOmniClient] = {}
_unified_clients: dict[tuple[str | None, str | None], OmniClient] = {}

_ctx_instance: ContextVar[str | None] = ContextVar("omni_instance", default=None)
_ctx_cluster: ContextVar[str | None] = ContextVar("omni_cluster", default=None)


def configure(
    config: ConfigInput | None = None,
    *,
    config_path: str | Path | None = None,
    state_path: str | Path | None = None,
) -> None:
    _global_config.config = config
    _global_config.config_path = config_path
    _global_config.state_path = state_path


def _effective(instance: str | None, cluster: str | None) -> tuple[str | None, str | None]:
    return instance or _ctx_instance.get(), cluster or _ctx_cluster.get()


def get_client(*, instance: str | None = None, cluster: str | None = None) -> AsyncOmniClient:
    """Return async-only client (legacy helper)."""
    resolved = _effective(instance, cluster)
    if resolved not in _async_clients:
        _async_clients[resolved] = AsyncOmniClient(
            _global_config.config,
            config_path=_global_config.config_path,
            state_path=_global_config.state_path,
            instance=resolved[0],
            cluster=resolved[1],
        )
    return _async_clients[resolved]


def get_sync_client(*, instance: str | None = None, cluster: str | None = None) -> OmniClient:
    """Return unified sync/async client."""
    resolved = _effective(instance, cluster)
    if resolved not in _unified_clients:
        _unified_clients[resolved] = OmniClient(
            _global_config.config,
            config_path=_global_config.config_path,
            state_path=_global_config.state_path,
            instance=resolved[0],
            cluster=resolved[1],
        )
    return _unified_clients[resolved]


def get_unified_client(*, instance: str | None = None, cluster: str | None = None) -> OmniClient:
    return get_sync_client(instance=instance, cluster=cluster)


def set_default_instance(name: str) -> None:
    client = get_sync_client()
    client._async.state.set_preference("default_instance", name)


def set_default_cluster(name: str) -> None:
    client = get_sync_client()
    client._async.state.set_preference("default_cluster", name)


@contextmanager
def use_instance(name: str):
    token = _ctx_instance.set(name)
    try:
        yield
    finally:
        _ctx_instance.reset(token)


@contextmanager
def use_cluster(name: str):
    token = _ctx_cluster.set(name)
    try:
        yield
    finally:
        _ctx_cluster.reset(token)
