"""Base service class for asynchronous operations."""

from typing import Any, Dict, Optional
import aiohttp
from sed_sh.exceptions import (
    SedSHError,
    AuthenticationError,
    RateLimitError,
    ResourceNotFoundError,
    InvalidRequestError,
    PaymentRequiredError,
    ServerError,
    NetworkError,
)


class AsyncBaseService:
    """Base class for all asynchronous service clients.

    This class handles common HTTP operations and error handling for async operations.
    All exceptions are caught and converted to appropriate SedSHError subclasses.
    """

    def __init__(
        self, base_url: str, api_key: str, timeout: int, session: aiohttp.ClientSession
    ) -> None:
        """Initialize the service.

        Args:
            base_url: API base URL
            api_key: API key for authentication
            timeout: Request timeout in seconds
            session: Shared aiohttp ClientSession
        """
        self.base_url = base_url.rstrip("/")
        self.api_key = api_key
        self.timeout = aiohttp.ClientTimeout(total=timeout)
        self.session = session

    async def _request(
        self,
        method: str,
        path: str,
        json: Optional[Dict[str, Any]] = None,
        data: Optional[Any] = None,
        headers: Optional[Dict[str, str]] = None,
        params: Optional[Dict[str, Any]] = None,
    ) -> Any:
        """Make an asynchronous HTTP request.

        Args:
            method: HTTP method (GET, POST, DELETE, etc.)
            path: API endpoint path
            json: JSON request body
            data: Raw request body
            headers: Additional headers
            params: Query parameters

        Returns:
            Response data (usually dict)

        Raises:
            SedSHError: On any error
        """
        url = f"{self.base_url}{path}"

        request_headers = {
            "Authorization": f"Bearer {self.api_key}",
            "User-Agent": "sed-sh-python/0.1.0",
        }
        if headers:
            request_headers.update(headers)

        try:
            async with self.session.request(
                method=method,
                url=url,
                json=json,
                data=data,
                headers=request_headers,
                params=params,
                timeout=self.timeout,
            ) as response:
                # Handle different status codes
                if response.status == 401:
                    raise AuthenticationError(
                        "Authentication failed. Check your API key.",
                        status_code=401,
                        response=await self._safe_json(response),
                    )
                elif response.status == 402:
                    raise PaymentRequiredError(
                        "Payment required. Insufficient account balance.",
                        status_code=402,
                        response=await self._safe_json(response),
                    )
                elif response.status == 404:
                    raise ResourceNotFoundError(
                        "Resource not found.",
                        status_code=404,
                        response=await self._safe_json(response),
                    )
                elif response.status == 429:
                    raise RateLimitError(
                        "Rate limit exceeded. Please slow down your requests.",
                        status_code=429,
                        response=await self._safe_json(response),
                    )
                elif response.status == 400:
                    error_data = await self._safe_json(response)
                    error_msg = error_data.get("error", "Invalid request parameters")
                    raise InvalidRequestError(
                        error_msg, status_code=400, response=error_data
                    )
                elif 500 <= response.status < 600:
                    raise ServerError(
                        f"Server error: {response.status}",
                        status_code=response.status,
                        response=await self._safe_json(response),
                    )

                # Raise for other error status codes
                response.raise_for_status()

                # Return JSON response if available
                if response.content_length and response.content_length > 0:
                    try:
                        return await response.json()
                    except (ValueError, aiohttp.ContentTypeError):
                        return await response.text()

                return None

        except aiohttp.ServerTimeoutError as e:
            raise NetworkError(
                f"Request timeout after {self.timeout.total} seconds"
            ) from e
        except aiohttp.ClientConnectionError as e:
            raise NetworkError("Network connection error") from e
        except aiohttp.ClientError as e:
            if not isinstance(e, SedSHError):
                raise SedSHError(f"Request failed: {str(e)}") from e
            raise

    async def _safe_json(self, response: aiohttp.ClientResponse) -> Dict[str, Any]:
        """Safely extract JSON from response.

        Args:
            response: Response object

        Returns:
            JSON data or empty dict
        """
        try:
            return await response.json()
        except (ValueError, aiohttp.ContentTypeError):
            return {}
