import requests
from requests.exceptions import ConnectTimeout, RetryError

from common.third_party_api.amap.error_code import CODE
from common.third_party_api.exceptions import CallApiError
from common.utils.exceptions import ServiceHandleException
from common.utils.service_code import THIRD_PARTY_API_ERROR


class Configuration(object):
    def __init__(self, host, key, data=None, verify_ssl=False, proxy=None):
        self.host = host
        self.key = key
        self.data = data
        self.verify_ssl = verify_ssl
        self.proxy = proxy


class APIClient(object):
    def __init__(self, configuration, timeout=5, retries=3):
        session = requests.Session()
        adapter = requests.adapters.HTTPAdapter(pool_connections=10,
                                                pool_maxsize=100,
                                                max_retries=retries)
        session.mount("http://", adapter)
        session.mount("https://", adapter)
        self.default_json_headers = {
            "User-Agent":
            "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_14_4) AppleWebKit/537.36 \
                (KHTML, like Gecko) Chrome/84.0.4147.135 Safari/537.36",
            "Content-Type": "application/json;charset=UTF-8",
            "Connection": "close"
        }
        self.session = session
        self.login_url = "http://" + configuration.host + "/login"
        self.timeout = timeout
        self.configuration = configuration


class BaseClient(object):
    def __init__(self, apiclient):
        self.apiclient = apiclient
        self.client = apiclient.session

    def request(self, url, method, headers=None, *args, **kwargs):
        timer = kwargs.get("timer", 0)
        if not headers:
            headers = self.apiclient.default_json_headers
        final_url = "https://" + self.apiclient.configuration.host + url
        try:
            response = self.client.request(url=final_url,
                                           method=method,
                                           headers=headers,
                                           *args,
                                           **kwargs)
        except ConnectTimeout as e:
            raise CallApiError("time out", e.response.status_code, url, method,
                               e.response)
        except RetryError as e:
            raise CallApiError("max retries", e.response.status_code, url,
                               method, e.response)
        if response.status_code == 401 and timer < 2:
            timer += 1
            self.client = self.apiclient.session
            kwargs.update({"timer": timer})
            self.request(url, method, headers=headers, *args, **kwargs)
        rst = response.json()
        info_code = rst.get("infocode")
        if info_code == "10000":
            return rst
        elif info_code in CODE.keys():
            raise ServiceHandleException(msg="amap api error",
                                         msg_show=CODE[info_code],
                                         code=THIRD_PARTY_API_ERROR)
        elif info_code.startswith("300"):
            raise ServiceHandleException(msg="amap api error",
                                         msg_show="服务响应失败。",
                                         code=THIRD_PARTY_API_ERROR)
        else:
            raise ServiceHandleException(msg="amap api error",
                                         msg_show="未知错误",
                                         code=THIRD_PARTY_API_ERROR)

    def get(self, url, headers=None, data=None, params=None, *args, **kwargs):
        params.update({
            "key": self.apiclient.configuration.key,
            "output": "json"
        })
        return self.request(url,
                            method="GET",
                            headers=headers,
                            data=data,
                            params=params,
                            *args,
                            **kwargs)

    def post(self, url, headers=None, data=None, *args, **kwargs):
        return self.request(url,
                            method="POST",
                            headers=headers,
                            data=data,
                            *args,
                            **kwargs)
