from urllib.parse import urljoin

import requests
from requests import Response, HTTPError

from biolib.typing_utils import Dict, Optional, Union
from biolib.biolib_api_client import BiolibApiClient as DeprecatedApiClient


class ApiClient:

    def get(
            self,
            url: str,
            params: Optional[Dict[str, Union[str, int]]] = None,
            headers: Optional[Dict[str, str]] = None,
    ) -> Response:
        response = requests.get(
            headers=self._get_headers(headers),
            params=params,
            timeout=10,
            url=self._get_absolute_url(url),
        )
        ApiClient.raise_for_status(response)
        return response

    def post(self, path: str, data: Dict) -> Response:
        response = requests.post(
            headers=self._get_headers(),
            json=data,
            timeout=10,
            url=self._get_absolute_url(path),
        )
        ApiClient.raise_for_status(response)
        return response

    @staticmethod
    def raise_for_status(response):
        # Logic taken from `requests.Response.raise_for_status()`
        http_error_msg = ''
        reason = response.text
        if 400 <= response.status_code < 500:
            http_error_msg = u'%s Client Error: %s for url: %s' % (response.status_code, reason, response.url)

        elif 500 <= response.status_code < 600:
            http_error_msg = u'%s Server Error: %s for url: %s' % (response.status_code, reason, response.url)

        if http_error_msg:
            raise HTTPError(http_error_msg, response=response)

    @staticmethod
    def _get_headers(opt_headers: Optional[Dict[str, str]] = None) -> Dict[str, str]:
        headers: Dict[str, str] = opt_headers or {}

        deprecated_api_client = DeprecatedApiClient.get()

        if deprecated_api_client.is_signed_in:
            deprecated_api_client.refresh_access_token()

        # Adding access_token outside is_signed_in check as job_worker.py currently sets access_token
        # without setting refresh_token
        access_token = deprecated_api_client.access_token
        if access_token:
            headers['Authorization'] = f'Bearer {access_token}'

        return headers

    @staticmethod
    def _get_absolute_url(path: str) -> str:
        deprecated_api_client = DeprecatedApiClient.get()
        base_api_url = urljoin(deprecated_api_client.base_url, '/api/')
        return urljoin(base_api_url, path.strip('/') + '/')
