import demisto_client.demisto_api as demisto_api
import six

from demisto_client.demisto_api import ApiClient
from demisto_client.demisto_api.configuration import Configuration


def configure(base_url, api_key=None, username=None, password=None, verify_ssl=True, proxy=None,
              debug=False):
    """
    This wrapper provides an easier to use method of configuring the API client. The base
    Configuration method is still exposed if you wish to further configure the API Client.

    :param base_url: str - Base url of your Demisto instance.
    :param api_key: str - API key generated by your instance.
    :param username: str - If using credentials to authenticate, provide username of account.
    :param password: str - If using credentials to authenticate, provide password for the account.
                     Please note: headers are not encrypted.
    :param verify_ssl: bool - Indicates if valid SSLs are required for connection.
    :param proxy: dict - Dict object of your proxy settings.
    :param debug: bool - Include verbose logging.
    :return: Returns an API client configuration identical to the Configuration() method.
    """
    configuration = Configuration()
    configuration.api_key['Authorization'] = api_key
    configuration.host = base_url
    configuration.username = username
    configuration.password = password
    configuration.verify_ssl = verify_ssl
    configuration.proxy = proxy
    configuration.debug = debug
    api_instance = demisto_api.DefaultApi(ApiClient(configuration))
    return api_instance


def to_extended_dict(o):
    """
    In some cases, the models do not use the attribute map which causes the server to not return
    valid results. This function checks to see if an attribute map is part of the object and if so,
    will apply the changes to request object. If not, it will default to use the models as defined
    swagger.

    :param o: Request object.
    :return: Formatted request object.
    """
    result = {}

    if hasattr(o, "attribute_map"):
        o_map = o.attribute_map

        for attr, _ in six.iteritems(o.swagger_types):
            value = getattr(o, attr)
            if isinstance(value, list):
                result[o_map[attr]] = list(map(
                    lambda x: to_extended_dict(x) if hasattr(x, "to_dict") else x,
                    value
                ))
            elif hasattr(value, "to_dict"):
                result[o_map[attr]] = to_extended_dict(value)
            elif isinstance(value, dict):
                result[o_map[attr]] = dict(map(
                    lambda item: (item[0], to_extended_dict(item[1]))
                    if hasattr(item[1], "to_dict") else item,
                    value.items()
                ))
            else:
                result[o_map[attr]] = value
    else:
        o.to_dict() if hasattr(o, "to_dict") else o
        result = o
    return result


def generic_request_func(self, path, method, body=None, **kwargs):
    """
    This method allows for generic requests to be made against the Demisto server to endpoints that
    may not be exposed directly.
    :param path: str - Path of the endpoint.
    :param method: str - Type of API method to use.
    :param body: dict - Dict object of request body.

    :return: Response object.
    """

    all_params = ['']  # noqa: E501
    all_params.append('async_req')
    all_params.append('_return_http_data_only')
    all_params.append('_preload_content')
    all_params.append('_request_timeout')

    params = locals()
    for key, val in six.iteritems(params['kwargs']):
        if key not in all_params:
            raise TypeError(
                "Got an unexpected keyword argument '%s'"
                " to method" % key
            )
        params[key] = val
    del params['kwargs']

    collection_formats = {}

    path_params = {}

    query_params = []

    header_params = {}

    form_params = []
    local_var_files = {}

    body_params = body
    # HTTP header `Accept`
    header_params['Accept'] = self.api_client.select_header_accept(
        ['application/json'])  # noqa: E501

    # HTTP header `Content-Type`
    header_params['Content-Type'] = self.api_client.select_header_content_type(  # noqa: E501
        ['application/json', 'application/xml'])  # noqa: E501

    # Authentication setting
    auth_settings = ['api_key']  # noqa: E501

    return self.api_client.call_api(
        path, method,
        path_params,
        query_params,
        header_params,
        body=body_params,
        post_params=form_params,
        files=local_var_files,
        response_type='str',  # noqa: E501
        auth_settings=auth_settings,
        async_req=params.get('async_req'),
        _return_http_data_only=params.get('_return_http_data_only'),
        _preload_content=params.get('_preload_content', True),
        _request_timeout=params.get('_request_timeout'),
        collection_formats=collection_formats)
