from typing import Dict, List, Any, Optional
from .core import UnifiedChatClient
from .exceptions import SDKError, APIRequestError, ConnectionError, TimeoutError


class OpenAIClient:
    """Client specifically for interacting with OpenAI models."""

    # This class variable defines the provider identifier used when
    # communicating with the UnifiedChatClient. It tells the unified
    # service to route requests to its OpenAI integration.
    _PROVIDER_NAME = "openai"

    # --- FIX: Add 'model' parameter to __init__ ---
    # (This comment was in the original code)
    def __init__(self, base_url: str, model: str, timeout: int = 60):
        """
        Initializes the OpenAI client for a specific model.

        Args:
            base_url: Base URL of the unified FastAPI service.
            model: The specific OpenAI model name this client instance will use.
            api_key: Optional API key to authenticate with the FastAPI service.
                     (Note: api_key is in docstring but not a parameter of __init__.
                     Authentication is likely handled by
                     UnifiedChatClient or via other means).
            timeout: Request timeout in seconds.
        """
        # --- Initialization Flow ---

        # Step 1: Instantiate the Unified Client
        # A UnifiedChatClient instance is created. This unified client is responsible
        # for the actual HTTP communication with the backend FastAPI service.
        # It's configured with the base_url of that service and a request timeout.
        self.unified_client = UnifiedChatClient(base_url, timeout)

        # Step 2: Validate the Model Name
        # It's crucial that an OpenAI model (e.g., "gpt-4-turbo", "gpt-3.5-turbo")
        # is specified for this client instance. If no model name is provided,
        # it raises a ValueError because the client wouldn't know which OpenAI
        # model to target.
        if not model:
            raise ValueError("An OpenAI model name must be provided.")

        # Step 3: Store the Model Name
        # The provided model name is stored as an instance attribute. This means
        # this specific OpenAIClient instance will always use this model
        # for its chat operations.
        self.model = model  # Store the model name

    def chat(
        self,
        messages: List[Dict[str, str]],
        use_refinement: bool,
        critic_provider: str,
        critic_model: str,
        max_refinement_iterations: int,
        generator_extra_params: Dict[str, str],
        max_tokens: Optional[int] = None,
        temperature: Optional[float] = None,
        **kwargs: Any,
    ) -> Dict[str, Any]:
        """
        Sends a chat request using the pre-configured OpenAI model.

        Args:
            messages: The list of message dictionaries.
            max_tokens: Optional maximum tokens for the response.
            temperature: Optional sampling temperature.
            **kwargs: Additional parameters. Should NOT include provider,
            model, or messages.

        Returns:
            The API response dictionary.
        """
        # --- Chat Request Flow ---

        # Step 1: Filter Additional Keyword Arguments
        # This line creates a new dictionary `filtered_kwargs`. It takes all
        # keyword arguments passed via `**kwargs` and excludes 'provider', 'model',
        # and 'messages'. This is to prevent accidental overriding of these
        # core parameters, which are explicitly set by this OpenAIClient.
        # Other valid OpenAI parameters (e.g., top_p, frequency_penalty, tool_choice)
        # passed in `**kwargs` will be preserved.
        filtered_kwargs = {
            k: v
            for k, v in kwargs.items()
            if k not in ["provider", "model", "messages"]
        }

        # Step 2: Delegate to the Unified Client's Chat Method
        # The actual API call is made by invoking the `chat` method of the
        # `self.unified_client` instance. This unified client handles the
        # communication with the backend FastAPI service.
        return self.unified_client.chat(
            # Step 2a: Specify the Provider
            # The `provider` argument is set to `self._PROVIDER_NAME`
            # (which is "openai").
            # This tells the unified FastAPI service to route this request to its
            # OpenAI backend integration.
            provider=self._PROVIDER_NAME,
            # Step 2b: Specify the Model
            # The `model` argument is set to `self.model` (the model name stored
            # during initialization, e.g., "gpt-4-turbo"). This tells the
            # unified service (and subsequently OpenAI) which specific model to use.
            model=self.model,
            # Step 2c: Pass Through Messages
            # The `messages` list (conversation history) is passed directly to the
            # unified client.
            messages=messages,
            # Step 2d: Pass Through Standard Optional Parameters
            # Optional parameters like `max_tokens` and `temperature` are also
            # passed through. If they are None, the unified client or the
            # backend service might use default values.
            # Max tokens for the generated response.
            max_tokens=max_tokens,
            # Sampling temperature for generation (controls randomness).
            temperature=temperature,
            # Flag to enable/disable the refinement process.
            use_refinement=use_refinement,
            # Provider for the critic LLM used in refinement.
            critic_provider=critic_provider,
            # Specific model name for the critic LLM.
            critic_model=critic_model,
            # Maximum number of refinement loops.
            max_refinement_iterations=max_refinement_iterations,
            # Extra parameters for the generator model.
            generator_extra_params=generator_extra_params,
            # Step 2e: Pass Through Filtered Additional Parameters
            # Any other keyword arguments (now in `filtered_kwargs`) are unpacked
            # and passed to the unified client. These could be other OpenAI-specific
            # parameters not explicitly listed in this method's signature.
            **filtered_kwargs,
        )
        # Step 3: Return the Response
        # The `self.unified_client.chat()` method is expected to make the HTTP request,
        # handle potential network errors or API errors from the unified service,
        # and return the JSON response from the OpenAI API (as proxied by the
        # unified service). This response is then returned directly by this method.


# This list defines the public interface of this module.
# When someone does `from your_module import *`, only these names will be imported.
__all__ = [
    "OpenAIClient",
    "SDKError",
    "APIRequestError",
    "ConnectionError",
    "TimeoutError",
]
