"""AfterShip Base."""
import asyncio
from socket import gaierror
from typing import TYPE_CHECKING, Optional

from aiohttp import ClientError, ClientResponse, ClientSession, ClientTimeout

from .const import BASE_URL, GOOD_HTTP_CODES
from .exceptions import AfterShipCommunicationException

if TYPE_CHECKING:
    from .trackings import AfterShipTrackings


class AfterShipBase:
    """Aftership Base object."""

    _api_key: str
    _session: ClientSession
    _timeout: int
    _trackings: Optional["AfterShipTrackings"]

    async def _call_api(
        self, endpoint: str, method: str = "GET", data: Optional[dict] = None
    ) -> Optional[ClientResponse]:
        """Private method to call the AfterShip API."""
        try:
            response = await self._session.request(
                method=method,
                url=f"{BASE_URL}/{endpoint}",
                headers={
                    "aftership-api-key": self._api_key,
                    "Content-Type": "application/json",
                },
                json=data,
                timeout=ClientTimeout(total=self._timeout),
            )
            return await self._handle_response(response)

        except asyncio.TimeoutError as exception:
            raise AfterShipCommunicationException("Timeout error") from exception

        except (ClientError, gaierror) as exception:
            raise AfterShipCommunicationException(
                f"Communication error {exception}"
            ) from exception

    async def _handle_response(self, response: ClientResponse) -> Optional[dict]:
        """Private method handle the result from AfterShip."""
        result = await response.json() if response else {}

        if response.status not in GOOD_HTTP_CODES:
            meta = result.get("meta", {})
            raise AfterShipCommunicationException(
                f"{response.status} is not valid - {meta.get('code')} - {meta.get('message')}"
            )

        return result.get("data", {})
