# WARNING: Do not edit by hand, this file was generated by Crank:
#
#   https://github.com/gocardless/crank
#

import re
import time
from requests import Timeout, ConnectionError
from uuid import uuid4

from .. import list_response
from ..api_response import ApiResponse
from ..errors import MalformedResponseError

class BaseService(object):
    """Base class for API service classes."""
    def __init__(self, api_client, max_network_retries=3, retry_delay_in_seconds=0.5, raise_on_idempotency_conflict=False):
        self._api_client = api_client
        self.max_network_retries = max_network_retries
        self.retry_delay_in_seconds = retry_delay_in_seconds
        self.raise_on_idempotency_conflict = raise_on_idempotency_conflict

    def _perform_request(self, method, path, params, headers=None, retry_failures=False):
        if method == 'POST':
            headers = self._inject_idempotency_key(headers)

        if retry_failures:
            for retries_left in range(self.max_network_retries-1, -1, -1):
                try:
                    return self._attempt_request(method, path, params, headers)
                except (Timeout, ConnectionError, MalformedResponseError) as err:
                    if retries_left > 0:
                        time.sleep(self.retry_delay_in_seconds)
                    else:
                        raise err
        else:
            return self._attempt_request(method, path, params, headers)

    def _attempt_request(self, method, path, params, headers):
        if method == 'GET':
            return self._api_client.get(path, params=params, headers=headers)

        if method == 'POST':
            return self._api_client.post(path, body=params, headers=headers)

        if method == 'PUT':
            return self._api_client.put(path, body=params, headers=headers)

        if method == 'DELETE':
            return self._api_client.delete(path, body=params, headers=headers)

        raise ValueError('Invalid method "{}"'.format(method))


    def _inject_idempotency_key(self, headers):
        headers = headers or {}
        if 'Idempotency-Key' not in headers:
            headers['Idempotency-Key'] = str(uuid4())

        return headers

    def _envelope_key(self):
        return type(self).RESOURCE_NAME

    def _resource_for(self, response):
        api_response = ApiResponse(response)

        data = api_response.body[self._envelope_key()]
        klass = type(self).RESOURCE_CLASS
        if isinstance(data, dict):
            return klass(data, api_response)
        else:
            records = [klass(item, api_response) for item in data]
            return list_response.ListResponse(records, api_response)

    def _sub_url_params(self, url, params):
        return re.sub(r':(\w+)', lambda match: params[match.group(1)], url)
