import base64
import logging
import platform
import requests

from sunpal import APIError, InvalidRequestError, OperationFailedError, compat
from sunpal.main import SunPal
from sunpal.main import Environment
from sunpal import compat
from sunpal.version import VERSION

_logger = logging.getLogger(__name__)


def _basic_auth_str(username):
    return "Basic " + base64.b64encode(
        ("%s:" % username).encode("latin1")
    ).strip().decode("latin1")


def request(method, url, env, params=None, headers=None, file=None):
    if not env:
        raise Exception("No environment configured.")
    if headers is None:
        headers = {}

    url = env.api_url(url)
    if method.lower() in ("get", "head", "delete"):
        if params:
            url = "%s?%s" % (url, compat.urlencode(params))

        payload = None
    else:
        payload = compat.urlencode(params)
        headers["Content-type"] = "application/x-www-form-urlencoded"

    headers.update(
        {
            "User-Agent": "Sunpal-Python-Client v%s" % VERSION,
            "Accept": "application/json",
            "api-key": env.api_key,
            "Lang-Version": str(compat.py_major_v) + "." + str(compat.py_minor_v),
            "OS-Version": platform.platform(),
        }
    )

    meta = compat.urlparse(url)
    request_args = {
        "method": method.upper(),
        "timeout": (env.connect_timeout, env.read_timeout),
        "data": payload,
        "headers": headers,
    }

    if file:
        request_args.update({"files": file})
        headers.pop("Content-type")
        headers.pop("Accept")
        request_args["data"] = params

    uri = meta.netloc + meta.path + "?" + meta.query

    if SunPal.verify_ca_certs:
        request_args.update(
            {
                "verify": SunPal.ca_cert_path,
                "url": "https://" + uri,
            }
        )
    else:
        if Environment.protocol == "https":
            request_args.update(
                {
                    "url": "https://" + uri,
                }
            )
        else:
            request_args.update(
                {
                    "url": "http://" + uri,
                }
            )

    _logger.debug("{method} Request: {url}".format(**request_args))
    _logger.debug(
        "HEADERS: {0}".format(
            {k: v for k, v in headers.items() if k.lower() != "authorization"}
        )
    )
    if payload:
        _logger.debug("PAYLOAD: {data}".format(**request_args))

    response = requests.request(**request_args)

    if compat.py_major_v >= 3:
        _logger.debug(
            "{method} Response: {status_code} - {text}".format(
                method=request_args["method"],
                status_code=response.status_code,
                text=response.text,
            )
        )
    elif compat.py_major_v < 3:
        _logger.debug(
            "{method} Response: {status_code} - {text}".format(
                method=request_args["method"],
                status_code=response.status_code,
                text=response.text.encode("utf 8"),
            )
        )

    return process_response(url, response.text, response.status_code)


def process_response(url, response, http_code):
    try:
        if response:
            resp_json = compat.json.loads(response)
        else:
            resp_json = {}

    except Exception:
        if "503" in response:
            raise Exception(
                "Sorry, the server is currently unable to handle the request due to a temporary overload or scheduled maintenance. Please retry after sometime. \n type: internal_temporary_error, \n http_status_code: 503, \n error_code: internal_temporary_error,\n content:"
                + response
            )
        elif "504" in response:
            raise Exception(
                "The server did not receive a timely response from an upstream server, request aborted. If this problem persists, contact us at support@sunpal.com. \n type: gateway_timeout, \n http_status_code: 504, \n error_code: gateway_timeout,\n content:"
                + response
            )
        else:
            raise Exception(
                "Sorry, something went wrong when trying to process the request. If this problem persists, contact us at support@sunpal.com. \n type: internal_error, \n http_status_code: 500, \n error_code: internal_error,\n content:"
                + response
            )

    if http_code == 404:
        return {}

    if http_code < 200 or http_code > 299:
        handle_api_resp_error(url, http_code, resp_json)

    return resp_json


def handle_api_resp_error(url, http_code, resp_json):

    # print("resp_json", resp_json)
    if "errors" not in resp_json:
        raise Exception(
            "The api_error_code is not present. Probably an error. \n URL is "
            + url
            + "\nContent is \n "
            + str(resp_json)
        )

    if "operation_failed" == resp_json.get("type"):
        raise OperationFailedError(http_code, resp_json)
    elif "invalid_request" == resp_json.get("type"):
        raise InvalidRequestError(http_code, resp_json)
    else:
        raise APIError(http_code, resp_json)
