import requests, requests.utils
from typing import Any, Text, Dict, SupportsInt, SupportsFloat, SupportsBytes


def msg_digest(res, **kwargs):
    import urllib.parse
    toshort = lambda t: t[0:256] + '  ... [MORE ' + str(
        int(((len(t) - 256) / len(t)) * 100)) + '% OMITTED HERE]' if len(t) > 256 else t
    reqline = '%s %s HTTP/%.1f\n' % (res.request.method, res.request.path_url, res.raw.version * 0.1)
    reqhead = 'Host: %s\n' % urllib.parse.urlparse(res.request.url).netloc
    for k, v in dict(res.request.headers).items():
        reqhead += '%s: %s\n' % (k, v)
    else:
        reqhead += '\n'
    reqbody = ''
    if isinstance(res.request.body, bytes):
        reqbody += str(res.request.body)[2:-1]
    elif res.request.body:
        reqbody += str(res.request.body)
    resline = 'HTTP/%.1f %d %s\n' % (res.raw.version * 0.1, res.raw.status, res.raw.reason)
    reshead = ''
    for k, v in dict(res.headers).items():
        reshead += '%s: %s\n' % (k, v)
    else:
        reshead += '\n'
    resbody = ''
    if res.text:
        resbody += res.text
    return {
        "req": reqline + reqhead + toshort(reqbody),
        "res": resline + reshead + toshort(resbody)
    }


def hook_response_debug(res, **kwargs):
    info = msg_digest(res, **kwargs)
    logs = '[->]' + '\n' + info["req"] + '\n' + '[<-]' + '\n' + info["res"]
    print(logs)
    try:
        import logging
        logging.log(logging.DEBUG, logs)
    except:
        pass


class Request:
    __http__ = requests
    __method_list__ = ('GET', 'POST', 'PUT', 'DELETE', 'HEAD', 'OPTIONS', 'TRACE', 'PATCH')
    __response_object__ = None

    def http(self,
             method: Text = 'GET',
             url: Text = None,
             query: Dict | Text = None,
             data: Dict | Text | SupportsBytes = None,
             data_json: Any = None,
             data_file: Dict = None,
             header: Dict = None,
             cookie: Dict = None,
             auth: Any = None,
             timeout: SupportsInt | SupportsFloat = None,
             proxy: Text = None,
             auto_redirect=False,
             ignore_cert_error=False,
             debug=False):
        method = method.upper()
        if method not in self.__method_list__:
            raise Exception('不支持的请求方法 | Unsupported request method.')
        if method == 'HEAD':
            auto_redirect = False
        if isinstance(proxy, str) and len(proxy) >= 5:
            proxy = {"http": proxy, "https": proxy}
        else:
            proxy = None
        self.__response_object__ = self.__http__.request(
            method=method,
            url=url,
            params=query,
            data=data,
            headers=header,
            cookies=cookie,
            files=data_file,
            auth=auth,
            timeout=timeout,
            allow_redirects=auto_redirect,
            proxies=proxy,
            verify=not ignore_cert_error,
            json=data_json,
            hooks=[None, {"response": hook_response_debug}][debug]
        )
        try:
            json_content = self.__response_object__.json()
        except:
            json_content = None
        return {
            "url": self.__response_object__.url, "encoding": self.__response_object__.encoding,
            "status": self.__response_object__.status_code,
            "reason": self.__response_object__.reason,
            "header": self.__response_object__.headers,
            "duration": round(self.__response_object__.elapsed.microseconds / 1000, 1),
            "cookie": requests.utils.dict_from_cookiejar(self.__response_object__.cookies),
            "text": self.__response_object__.text,
            "json": json_content,
            "content": self.__response_object__.content
        }


class Session(Request):
    __http__ = requests.session()


if __name__ == '__main__':
    req = Session()
    print(req.http('GET', 'https://www.baidu.com/s', query={"wd": '社会主义核心价值观'},
                   header={"User-Agent": 'Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) '
                                         'Chrome/86.0.4240.198 Safari/537.36'},
                   auto_redirect=True, debug=False))
