# -*- coding: utf-8 -*-
"""
Модуль, который умеет получать данные по HTTP.
Функция L{load_url_data} возвращает данные, расположенные по переданному ей URL.
"""

import http.cookiejar
import ssl
import urllib.error
import urllib.parse
import urllib.request
import requests


__author__ = "Bogdanov Evgeny"
__email__ = "evbogdanov@yandex-team.ru"

USERAGENT = 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_13_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/81.0.4036.0 Safari/537.36'


def load_url_data(url, username=None, password=None, additional_cookies=None, additional_headers=None, timeout=10,
                  can_be_empty=False, post_data=None):
    data = ''
    try:
        cj = http.cookiejar.CookieJar()
        password_mgr = urllib.request.HTTPPasswordMgrWithDefaultRealm()
        password_mgr.add_password(realm=None,
                                  uri=url,
                                  user=username,
                                  passwd=password)
        auth_handler = urllib.request.HTTPBasicAuthHandler(password_mgr)

        if hasattr(ssl, 'create_default_context'):
            # FIXME: вопрос конечно, стоит ли такое разрешать
            context = ssl.create_default_context()
            context.check_hostname = False
            context.verify_mode = ssl.CERT_NONE
            # opener = urllib.request.build_opener(urllib.request.HTTPSHandler(context=context, debuglevel=1),
            opener = urllib.request.build_opener(urllib.request.HTTPSHandler(context=context),
                                                 auth_handler, urllib.request.HTTPCookieProcessor(cj))
        else:
            opener = urllib.request.build_opener(auth_handler, urllib.request.HTTPCookieProcessor(cj))
        opener.addheaders = [('User-Agent', USERAGENT)]
        if additional_cookies:
            opener.addheaders.append(("Cookie", additional_cookies))

        if additional_headers is not None:
            for header_name, header_value in additional_headers:
                opener.addheaders.append((header_name, header_value))

        f = opener.open(url, timeout=timeout, data=post_data)
        code = f.code
        if 200 <= code <= 399:
            data = f.read()
        else:
            err_msg = "incorrect http response code: url = <%s>, code = %d" % (url, code)
            raise RuntimeError(err_msg)
    except Exception as e:
        err_msg = "exception while curl.perform: <%s>, url: <%s>" % (str(e), url)
        raise RuntimeError(err_msg)

    if not data and not can_be_empty:
        err_msg = "no data from url(empty response): <%s>" % url
        raise RuntimeError(err_msg)

    # Хак для cbr.ru
    if additional_cookies is None and data.find(b"<html><body><script>document.cookie='") >= 0:
        cookie = data.split(b"document.cookie='")[1].split(b"; path=/';window.location.href=window.")[0]
        return load_url_data(url, username, password, cookie)
    return data


def second_load_url_data(url, username=None, password=None, additional_cookies=None, additional_headers=None,
                         timeout=10, can_be_empty=False, post_data=None):
    data = ''
    try:
        method = 'post' if post_data else 'get'
        headers = {key: value for key, value in additional_headers} if additional_headers is not None else None
        result = requests.request(method, url, data=post_data, headers=headers)
        if result.status_code == 200:
            data = result.content
    except Exception as e:
        err_msg = "exception while second_load_url_data: <%s>, url: <%s>" % (str(e), url)
        raise RuntimeError(err_msg)
    return data


def load_url_data_retry(url, username=None, password=None, additional_cookies=None, additional_headers=None, timeout=1,
                        retries=2):
    while retries:
        retries -= 1
        try:
            return load_url_data(url, username=username, password=password, additional_cookies=additional_cookies,
                                 additional_headers=additional_headers, timeout=timeout)
        except RuntimeError as e:
            if retries == 0:
                raise e


def get_http_code(url, username=None, password=None, additional_cookies=None, additional_headers=None, timeout=10):
    try:
        if hasattr(ssl, 'create_default_context'):
            context = ssl.create_default_context()
            context.check_hostname = False
            context.verify_mode = ssl.CERT_NONE
            req = urllib.request.Request(url, headers={'User-Agent': USERAGENT})
            connection = urllib.request.urlopen(req, timeout=timeout, context=context)
        else:
            req = urllib.request.Request(url, headers={'User-Agent': USERAGENT})
            connection = urllib.request.urlopen(req, timeout=timeout)
        code = connection.getcode()
        message = 'ok'
        connection.close()
    except urllib.error.HTTPError as e:
        message = e
        code = e.getcode()
    except IOError as exc:
        message = exc
        code = None
    return code, message


def get_http_code_retry(url, username=None, password=None, additional_cookies=None, additional_headers=None, timeout=10,
                        retries=2):
    while retries:
        retries -= 1
        try:
            code, message = get_http_code(url, username=username, password=password,
                                          additional_cookies=additional_cookies, additional_headers=additional_headers,
                                          timeout=timeout)
            if message == 'ok' or retries == 0:
                return code, message
        except RuntimeError as e:
            if retries == 0:
                raise e
