"""Shared configuration accessors for provider modules.

Each provider needs to read its section of ``~/.ember/config.yaml`` via
``EmberContext``.  Rather than duplicating the pattern in every provider,
this module provides parameterized helpers.

Usage::

    from ember.models.providers._config import make_config_helpers

    _config_value, _config_str = make_config_helpers("bedrock")
"""

from __future__ import annotations

from typing import Any, Optional


def make_config_helpers(
    provider_name: str,
) -> tuple[
    "type[object]",  # _config_value
    "type[object]",  # _config_str
]:
    """Return ``(_config_value, _config_str)`` closures for *provider_name*.

    Args:
        provider_name: Config section name (e.g., ``"bedrock"``, ``"vertex"``).

    Returns:
        A 2-tuple of callables: ``(_config_value, _config_str)``.
    """

    def _config_value(field: str) -> Any:
        from ember._internal.context.runtime import EmberContext

        return EmberContext.current().get_config(
            f"providers.{provider_name}.{field}"
        )

    def _config_str(field: str) -> Optional[str]:
        raw = _config_value(field)
        if raw is None:
            return None
        if isinstance(raw, str):
            trimmed = raw.strip()
            return trimmed or None
        raise TypeError(
            f"providers.{provider_name}.{field} must be a string"
        )

    return _config_value, _config_str


def estimate_tokens(
    text: str,
    config_value: Any,
    provider_name: str,
) -> int:
    """Estimate token count from text using a configurable char/token ratio.

    Providers that lack native token counting (ollama, rnd1) use this
    shared estimation logic.

    Args:
        text: Input text to estimate tokens for.
        config_value: Result of ``_config_value("token_char_ratio")``.
        provider_name: Provider name for error messages.

    Returns:
        Estimated token count (minimum 1).
    """
    if config_value is None:
        ratio = 4.0
    elif isinstance(config_value, bool):
        raise TypeError(
            f"providers.{provider_name}.token_char_ratio must be numeric"
        )
    elif isinstance(config_value, (int, float)):
        ratio = float(config_value)
    elif isinstance(config_value, str):
        try:
            ratio = float(config_value)
        except ValueError as exc:
            raise TypeError(
                f"providers.{provider_name}.token_char_ratio must be numeric"
            ) from exc
    else:
        raise TypeError(
            f"providers.{provider_name}.token_char_ratio must be numeric, "
            f"got {type(config_value).__name__}"
        )

    ratio = max(1.0, ratio)
    return max(1, int((len(text) / ratio) + 0.5))
