"""HTTP client configuration."""

from __future__ import annotations

from msgspec import Struct

from pinecone._internal.constants import DEFAULT_TIMEOUT


class HTTPConfig(Struct, kw_only=True, omit_defaults=True):
    """HTTP client configuration.

    This immutable configuration class controls all aspects of HTTP client behavior
    including timeouts, retries, rate limiting, and logging. Uses msgspec.Struct
    for performance and type safety.

    Examples:
        Basic usage with defaults:
            >>> config = HTTPConfig()
            >>> config.timeout
            30

        Custom timeout and retries:
            >>> config = HTTPConfig(timeout=60, max_retries=5)

        Granular timeout control:
            >>> config = HTTPConfig(timeout={"connect": 5, "read": 60, "write": 30})

        Enable rate limiting:
            >>> config = HTTPConfig(
            ...     rate_limit_enabled=True, rate_limit_tokens=100, rate_limit_period=60.0
            ... )

        Enable request/response logging for debugging:
            >>> config = HTTPConfig(log_requests=True, log_responses=True)

    Attributes:
        timeout: Request timeout in seconds. Can be a single int/float for all
            timeout types, or a dict with keys 'connect', 'read', 'write', 'pool'
            for granular control.
        max_retries: Maximum number of retry attempts for failed requests.
        max_connections: Maximum number of concurrent connections to maintain.
        max_keepalive_connections: Maximum number of persistent connections to maintain.
        retry_statuses: HTTP status codes that trigger automatic retries.
        retry_backoff_factor: Multiplier for exponential backoff between retries.
        retry_max_wait: Maximum wait time in seconds between retry attempts.
        rate_limit_enabled: Enable client-side rate limiting to prevent API throttling.
        rate_limit_tokens: Number of tokens available in the rate limit bucket.
        rate_limit_period: Time period in seconds for rate limit token refresh.
        log_requests: Log outgoing HTTP requests for debugging.
        log_responses: Log incoming HTTP responses for debugging.
        http2: Enable HTTP/2 support for multiplexing and better performance.
    """

    # Connection settings
    timeout: int | float | dict[str, float] = DEFAULT_TIMEOUT
    max_retries: int = 3
    max_connections: int = 100
    max_keepalive_connections: int = 20

    # Retry settings
    retry_statuses: tuple[int, ...] = (429, 500, 502, 503, 504)
    retry_backoff_factor: float = 2.0
    retry_max_wait: int = 60

    # Rate limiting
    rate_limit_enabled: bool = False
    rate_limit_tokens: int = 100
    rate_limit_period: float = 60.0

    # Logging
    log_requests: bool = False
    log_responses: bool = False

    # HTTP/2 settings
    http2: bool = True

    def _validate_timeout(self) -> None:
        """Validate timeout configuration.

        Raises:
            ValueError: If timeout values are invalid.
            TypeError: If timeout type is invalid.
        """
        if isinstance(self.timeout, dict):
            valid_keys = {"connect", "read", "write", "pool"}
            invalid_keys = set(self.timeout.keys()) - valid_keys
            if invalid_keys:
                raise ValueError(
                    f"Invalid timeout keys: {invalid_keys}. Valid keys are: {valid_keys}"
                )
            for key, value in self.timeout.items():
                if value <= 0:
                    raise ValueError(f"timeout.{key} must be positive, got {value}")
        elif isinstance(self.timeout, (int, float)):
            if self.timeout <= 0:
                raise ValueError(f"timeout must be positive, got {self.timeout}")
        else:
            raise TypeError(
                f"timeout must be int, float, or dict, got {type(self.timeout).__name__}"
            )

    def __post_init__(self) -> None:
        """Validate configuration values.

        Raises:
            ValueError: If configuration values are invalid.
            TypeError: If configuration types are invalid.
        """
        # Validate timeout
        self._validate_timeout()

        if self.max_retries < 0:
            raise ValueError(f"max_retries must be non-negative, got {self.max_retries}")

        if self.max_connections <= 0:
            raise ValueError(f"max_connections must be positive, got {self.max_connections}")

        if self.max_keepalive_connections < 0:
            raise ValueError(
                f"max_keepalive_connections must be non-negative, "
                f"got {self.max_keepalive_connections}"
            )

        if self.max_keepalive_connections > self.max_connections:
            raise ValueError(
                f"max_keepalive_connections ({self.max_keepalive_connections}) "
                f"cannot exceed max_connections ({self.max_connections})"
            )

        if self.retry_backoff_factor <= 0:
            raise ValueError(
                f"retry_backoff_factor must be positive, got {self.retry_backoff_factor}"
            )

        if self.retry_max_wait <= 0:
            raise ValueError(f"retry_max_wait must be positive, got {self.retry_max_wait}")

        if self.rate_limit_enabled:
            if self.rate_limit_tokens <= 0:
                raise ValueError(
                    f"rate_limit_tokens must be positive when rate limiting enabled, "
                    f"got {self.rate_limit_tokens}"
                )
            if self.rate_limit_period <= 0:
                raise ValueError(
                    f"rate_limit_period must be positive when rate limiting enabled, "
                    f"got {self.rate_limit_period}"
                )

        if not self.retry_statuses:
            raise ValueError("retry_statuses cannot be empty")
