"""
VELOCRIUM Client - Main HTTP client implementation
Author: Juste Elysée MALANDILA
LinkedIn: https://linkedin.com/in/juste-elysee-malandila
"""

from typing import Optional, Dict, Any, Union
import httpx
import asyncio
from .exceptions import VelocriumError, HTTPError


class Client:
    """
    Modern async/sync HTTP client with advanced features.
    
    Features:
    - Async/sync transparent API
    - Automatic retry with backoff
    - HTTP caching
    - Rate limiting
    - Connection pooling
    
    Example:
        >>> client = Client()
        >>> response = client.get("https://api.github.com/users/octocat")
        >>> print(response.json())
    """
    
    def __init__(
        self,
        base_url: Optional[str] = None,
        headers: Optional[Dict[str, str]] = None,
        timeout: Optional["Timeout"] = None,
        retry: Optional["Retry"] = None,
        cache: Optional["Cache"] = None,
        rate_limit: Optional["RateLimit"] = None,
        auth: Optional[Any] = None,
        hooks: Optional[Dict[str, list]] = None,
        proxies: Optional[Dict[str, str]] = None,
        verify: bool = True,
    ):
        """
        Initialize the Velocrium HTTP client.
        
        Args:
            base_url: Base URL for all requests
            headers: Default headers to include in all requests
            timeout: Timeout configuration
            retry: Retry configuration
            cache: Cache configuration
            rate_limit: Rate limiting configuration
            auth: Authentication handler
            hooks: Request/response hooks for middleware
            proxies: Proxy configuration
            verify: SSL certificate verification
        """
        self.base_url = base_url
        self.headers = headers or {}
        self.timeout = timeout
        self.retry = retry
        self.cache = cache
        self.rate_limit = rate_limit
        self.auth = auth
        self.hooks = hooks or {}
        self.proxies = proxies
        self.verify = verify
        
        # Initialize httpx client
        client_kwargs = {
            "headers": headers,
            "timeout": timeout.to_httpx() if timeout else None,
            "verify": verify,
        }
        if base_url:
            client_kwargs["base_url"] = base_url
            
        self._client = httpx.Client(**client_kwargs)
        self._async_client = httpx.AsyncClient(**client_kwargs)
    
    def get(self, url: str, **kwargs) -> httpx.Response:
        """Make a GET request."""
        return self._request("GET", url, **kwargs)
    
    async def aget(self, url: str, **kwargs) -> httpx.Response:
        """Make an async GET request."""
        return await self._arequest("GET", url, **kwargs)
    
    def post(self, url: str, **kwargs) -> httpx.Response:
        """Make a POST request."""
        return self._request("POST", url, **kwargs)
    
    async def apost(self, url: str, **kwargs) -> httpx.Response:
        """Make an async POST request."""
        return await self._arequest("POST", url, **kwargs)
    
    def put(self, url: str, **kwargs) -> httpx.Response:
        """Make a PUT request."""
        return self._request("PUT", url, **kwargs)
    
    async def aput(self, url: str, **kwargs) -> httpx.Response:
        """Make an async PUT request."""
        return await self._arequest("PUT", url, **kwargs)
    
    def delete(self, url: str, **kwargs) -> httpx.Response:
        """Make a DELETE request."""
        return self._request("DELETE", url, **kwargs)
    
    async def adelete(self, url: str, **kwargs) -> httpx.Response:
        """Make an async DELETE request."""
        return await self._arequest("DELETE", url, **kwargs)
    
    def _request(self, method: str, url: str, **kwargs) -> httpx.Response:
        """Internal sync request handler."""
        try:
            response = self._client.request(method, url, **kwargs)
            response.raise_for_status()
            return response
        except httpx.HTTPStatusError as e:
            raise HTTPError(f"HTTP {e.response.status_code}: {e.response.text}") from e
        except Exception as e:
            raise VelocriumError(f"Request failed: {str(e)}") from e
    
    async def _arequest(self, method: str, url: str, **kwargs) -> httpx.Response:
        """Internal async request handler."""
        try:
            response = await self._async_client.request(method, url, **kwargs)
            response.raise_for_status()
            return response
        except httpx.HTTPStatusError as e:
            raise HTTPError(f"HTTP {e.response.status_code}: {e.response.text}") from e
        except Exception as e:
            raise VelocriumError(f"Request failed: {str(e)}") from e
    
    def close(self):
        """Close the HTTP client."""
        self._client.close()
    
    async def aclose(self):
        """Close the async HTTP client."""
        await self._async_client.aclose()
    
    def __enter__(self):
        """Context manager entry."""
        return self
    
    def __exit__(self, exc_type, exc_val, exc_tb):
        """Context manager exit."""
        self.close()
    
    async def __aenter__(self):
        """Async context manager entry."""
        return self
    
    async def __aexit__(self, exc_type, exc_val, exc_tb):
        """Async context manager exit."""
        await self.aclose()
