from typing import Any, Dict, Optional, TypeVar

from litellm.llms.base_llm.containers.transformation import BaseContainerConfig
from litellm.responses.utils import ResponsesAPIRequestUtils
from litellm.types.containers.main import (
    ContainerCreateOptionalRequestParams,
    ContainerListOptionalRequestParams,
)
from litellm.types.router import GenericLiteLLMParams


def decode_managed_container_id_for_request(
    container_id: str,
    custom_llm_provider: str,
    litellm_params: GenericLiteLLMParams,
) -> tuple[str, str, GenericLiteLLMParams]:
    """Decode a LiteLLM-managed container ID for upstream API calls.

    Returns:
        (original_container_id, resolved_provider, updated_litellm_params)
    """
    decoded = ResponsesAPIRequestUtils._decode_container_id(container_id)
    original_container_id = decoded.get("response_id", container_id)

    decoded_provider = decoded.get("custom_llm_provider")
    if decoded_provider and custom_llm_provider == "openai":
        custom_llm_provider = decoded_provider

    decoded_model_id = decoded.get("model_id")
    if decoded_model_id and not litellm_params.get("model_id"):
        litellm_params["model_id"] = decoded_model_id

    return original_container_id, custom_llm_provider, litellm_params


T = TypeVar("T")


class ContainerRequestUtils:
    @staticmethod
    def get_requested_container_create_optional_param(
        passed_params: dict,
    ) -> ContainerCreateOptionalRequestParams:
        """Extract only valid container creation parameters from the passed parameters."""
        container_create_optional_params = ContainerCreateOptionalRequestParams()

        valid_params = [
            "expires_after",
            "file_ids",
            "extra_headers",
            "extra_body",
        ]

        for param in valid_params:
            if param in passed_params and passed_params[param] is not None:
                container_create_optional_params[param] = passed_params[param]  # type: ignore

        return container_create_optional_params

    @staticmethod
    def get_optional_params_container_create(
        container_provider_config: BaseContainerConfig,
        container_create_optional_params: ContainerCreateOptionalRequestParams,
    ) -> Dict:
        """Get the optional parameters for container creation."""
        supported_params = container_provider_config.get_supported_openai_params()

        # Filter out unsupported parameters
        filtered_params = {
            k: v
            for k, v in container_create_optional_params.items()
            if k in supported_params
        }

        return container_provider_config.map_openai_params(
            container_create_optional_params=filtered_params,  # type: ignore
            drop_params=False,
        )

    @staticmethod
    def get_requested_container_list_optional_param(
        passed_params: dict,
    ) -> ContainerListOptionalRequestParams:
        """Extract only valid container list parameters from the passed parameters."""
        container_list_optional_params = ContainerListOptionalRequestParams()

        valid_params = [
            "after",
            "limit",
            "order",
            "extra_headers",
            "extra_query",
        ]

        for param in valid_params:
            if param in passed_params and passed_params[param] is not None:
                container_list_optional_params[param] = passed_params[param]  # type: ignore

        return container_list_optional_params

    @staticmethod
    def encode_container_id_in_response(
        response_obj: T,
        custom_llm_provider: Optional[str],
        litellm_metadata: Optional[Dict[str, Any]] = None,
        extra_body: Optional[Dict[str, Any]] = None,
    ) -> T:
        """
        Encode container_id in response object with provider/model metadata for routing.

        This mirrors the responses API pattern where response IDs are encoded with
        routing metadata so follow-up calls can route to the correct provider.

        Encodes when:
        1. litellm_metadata contains model_info.id (indicating router/proxy usage), OR
        2. extra_body contains target_model_names (indicating model-specific routing)

        Direct SDK calls with explicit custom_llm_provider and no routing hints return raw IDs.

        Args:
            response_obj: Response object with an `id` attribute (ContainerObject, DeleteContainerResult, etc.)
            custom_llm_provider: Provider name (e.g., "azure", "openai")
            litellm_metadata: Optional litellm_metadata dict that may contain model_info.id
            extra_body: Optional extra_body dict that may contain target_model_names

        Returns:
            The same response object with encoded container_id (if routing metadata present)
        """
        # Extract model_id from litellm_metadata
        litellm_metadata = litellm_metadata or {}
        model_info: Dict[str, Any] = litellm_metadata.get("model_info", {}) or {}
        model_id = model_info.get("id")

        # Check if we should encode based on routing metadata
        should_encode = False

        # Case 1: Router/proxy usage (model_id from router)
        if model_id is not None:
            should_encode = True

        # Case 2: target_model_names in extra_body (model-specific routing)
        if extra_body and "target_model_names" in extra_body:
            should_encode = True
            # Extract model_id from target_model_names if not already set
            if model_id is None:
                target_models = extra_body["target_model_names"]
                # Use first model as model_id for encoding
                if isinstance(target_models, str):
                    model_id = target_models.split(",")[0].strip()
                elif isinstance(target_models, list) and len(target_models) > 0:
                    model_id = str(target_models[0]).strip()

        # Only encode if we have routing metadata
        if should_encode and response_obj and hasattr(response_obj, "id"):
            encoded_id = ResponsesAPIRequestUtils._build_container_id(
                custom_llm_provider=custom_llm_provider,
                model_id=model_id,
                container_id=response_obj.id,
            )
            response_obj.id = encoded_id

        return response_obj
