"""Async HTTP client implementation"""

import httpx
from typing import Optional, Dict, Any
from .retry import AsyncRetryHandler
from .exceptions import (
    OctenAPIError,
    OctenTimeoutError,
    OctenConnectionError,
    OctenRateLimitError,
    OctenAuthenticationError,
)
from ..utils.constants import (
    DEFAULT_TIMEOUT,
    DEFAULT_MAX_RETRIES,
    DEFAULT_MAX_CONNECTIONS,
    DEFAULT_MAX_KEEPALIVE_CONNECTIONS,
    DEFAULT_KEEPALIVE_EXPIRY,
    HEADER_API_KEY,
    HEADER_CONTENT_TYPE,
    HEADER_USER_AGENT,
    USER_AGENT_TEMPLATE,
)


class AsyncHTTPClient:
    """Asynchronous HTTP client

    Supports connection pooling, keep-alive, HTTP/2, and automatic retry

    Attributes:
        base_url: API base URL
        api_key: API key
        timeout: Default timeout (seconds)
        max_retries: Maximum number of retries
        http2: Whether to enable HTTP/2
    """

    def __init__(
        self,
        base_url: str,
        api_key: str,
        timeout: float = DEFAULT_TIMEOUT,
        max_retries: int = DEFAULT_MAX_RETRIES,
        http2: bool = True,
        max_connections: int = DEFAULT_MAX_CONNECTIONS,
        max_keepalive_connections: int = DEFAULT_MAX_KEEPALIVE_CONNECTIONS,
        keepalive_expiry: float = DEFAULT_KEEPALIVE_EXPIRY,
    ):
        self.base_url = base_url
        self.api_key = api_key
        self.timeout = timeout
        self.max_retries = max_retries

        # ConfigurationConnection pool
        limits = httpx.Limits(
            max_connections=max_connections,
            max_keepalive_connections=max_keepalive_connections,
            keepalive_expiry=keepalive_expiry,
        )

        try:
            from ..version import __version__
        except ImportError:
            __version__ = "unknown"

        headers = {
            HEADER_API_KEY: api_key,
            HEADER_CONTENT_TYPE: "application/json",
            HEADER_USER_AGENT: USER_AGENT_TEMPLATE.format(version=__version__),
        }

        self._client = httpx.AsyncClient(
            base_url=base_url,
            timeout=httpx.Timeout(timeout),
            http2=http2,
            limits=limits,
            headers=headers,
            follow_redirects=True,
        )

        self._retry_handler = AsyncRetryHandler(max_retries=max_retries)

    async def request(
        self,
        method: str,
        endpoint: str,
        timeout: Optional[float] = None,
        json: Optional[Dict[str, Any]] = None,
        params: Optional[Dict[str, Any]] = None,
        **kwargs,
    ) -> Dict[str, Any]:
        """Send async HTTP request

        Args:
            method: HTTP method (GET, POST, etc.)
            endpoint: API endpoint path
            timeout: Request timeout (seconds), overrides default
            json: JSON Request body
            params: URL QueryParameters
            **kwargs: Other parameters passed to httpx

        Returns:
            JSON data from response

        Raises:
            OctenAPIError: API returned error
            OctenTimeoutError: Request timeout
            OctenConnectionError: Connection error
        """

        async def _make_request() -> Dict[str, Any]:
            try:
                request_timeout = timeout if timeout is not None else self.timeout

                response = await self._client.request(
                    method=method,
                    url=endpoint,
                    json=json,
                    params=params,
                    timeout=request_timeout,
                    **kwargs,
                )

                return self._handle_response(response)

            except httpx.TimeoutException as e:
                raise OctenTimeoutError(
                    message=f"Request timed out: {str(e)}",
                    timeout=timeout or self.timeout,
                )
            except httpx.ConnectError as e:
                raise OctenConnectionError(
                    message=f"Connection failed: {str(e)}",
                )
            except httpx.HTTPError as e:
                raise OctenConnectionError(
                    message=f"HTTP error occurred: {str(e)}",
                )

        return await self._retry_handler.execute_async(_make_request)

    def _handle_response(self, response: httpx.Response) -> Dict[str, Any]:
        """Handle HTTP response

        Args:
            response: httpx response object

        Returns:
            JSON data from response

        Raises:
            OctenAPIError: API returned error
            OctenRateLimitError: Rate limit error
            OctenAuthenticationError: Authentication error
        """
        request_id = response.headers.get("x-request-id")

        response_data = self._safe_json(response)

        if response.is_success:
            if response_data is not None:
                return response_data
            else:
                raise OctenAPIError(
                    message="Failed to parse response JSON",
                    status_code=response.status_code,
                    request_id=request_id,
                )

        error_message = self._extract_error_message_from_data(response_data, response)

        # Authentication error（401）
        if response.status_code == 401:
            raise OctenAuthenticationError(
                message=error_message,
                response_data=response_data,
                request_id=request_id,
            )

        # Rate limit error（429）
        if response.status_code == 429:
            retry_after = response.headers.get("retry-after")
            retry_after_seconds = int(retry_after) if retry_after else None
            raise OctenRateLimitError(
                message=error_message,
                retry_after=retry_after_seconds,
                response_data=response_data,
                request_id=request_id,
            )

        raise OctenAPIError(
            message=error_message,
            status_code=response.status_code,
            response_data=response_data,
            request_id=request_id,
        )

    def _extract_error_message_from_data(
        self, data: Optional[Dict[str, Any]], response: httpx.Response
    ) -> str:
        """Extract error message from parsed JSON data

        Args:
            data: Parsed JSON data
            response: httpx response object

        Returns:
            Error messageString
        """
        if isinstance(data, dict):
            if "msg" in data:
                return data["msg"]
            if "message" in data:
                return data["message"]
            if "error" in data:
                return str(data["error"])

        return f"HTTP {response.status_code}: {response.reason_phrase}"

    def _safe_json(self, response: httpx.Response) -> Optional[Dict[str, Any]]:
        """Safely parse JSON response

        Args:
            response: httpx response object

        Returns:
            JSON data or None
        """
        try:
            return response.json()
        except Exception:
            return None

    async def close(self):
        """Close HTTP client and release connection pool resources"""
        await self._client.aclose()

    async def __aenter__(self):
        """Support async context manager"""
        return self

    async def __aexit__(self, exc_type, exc_val, exc_tb):
        """Auto close when exiting async context manager"""
        await self.close()
