from typing import Callable, Any, Dict, Optional, TypeVar, Generic
from metorial_util_endpoint import MetorialEndpointManager

ConfigT = TypeVar("ConfigT")
ApiVersionT = TypeVar("ApiVersionT")


class MetorialSDKBuilder(Generic[ApiVersionT, ConfigT]):
  def __init__(self, api_name: str, api_version: ApiVersionT):
    self.api_name = api_name
    self.api_version = api_version
    self._get_api_host: Optional[Callable[[ConfigT], str]] = None
    self._get_headers: Optional[Callable[[ConfigT], Dict[str, str]]] = None

  @classmethod
  def create(cls, api_name: str, api_version: ApiVersionT):
    return cls(api_name, api_version)

  def set_get_api_host(self, get_api_host: Callable[[ConfigT], str]):
    self._get_api_host = get_api_host
    return self

  def set_get_headers(self, get_headers: Callable[[ConfigT], Dict[str, str]]):
    self._get_headers = get_headers
    return self

  def build(self, get_config: Callable[[Dict[str, Any]], ConfigT]):
    if not self._get_headers:
      raise ValueError("get_headers must be set")
    if not self._get_api_host:
      raise ValueError("api_host must be set")

    def builder(get_endpoints: Callable[[MetorialEndpointManager], Dict[str, Any]]):
      def sdk(config: Dict[str, Any]):
        full_config = get_config(config)
        api_host = self._get_api_host(full_config)  # type: ignore[misc]
        manager = MetorialEndpointManager(
          full_config,
          api_host,
          self._get_headers,  # type: ignore[arg-type]
          enable_debug_logging=bool(config.get("enableDebugLogging", False)),
        )
        endpoints = get_endpoints(manager)
        return {"_config": {"apiHost": api_host, **full_config}, **endpoints}  # type: ignore[dict-item]

      return sdk

    return builder
