# coding: utf-8

""" TODO: смержить с /opt/crm/cmf/bin/cmf_api и class RPC """
import json
import uuid

import requests


class ApiClientError(Exception):
    pass


class ApiClientUserError(ApiClientError):
    pass


class ApiClient:
    endpoint = 'http://127.0.0.1:8080/api/?mode=root'
    data = None

    def call(self, method: str, path: list, obj: str or None = None, **kwargs):
        """
        :param method:
        :param path: ['result', 'id'] for 'CmfItem1490 in {'result': {'id': 'CmfItem:1490'}}
        :param obj: id объекта, автоматически сформирует filter выражение для вызова object.method.
        :param kwargs:
        :return:
        """
        # Кэшируем чтобы потом можно было принтовать при ошибках для удобства дебага
        self.data = self._prepare_request_payload(method, obj, **kwargs)
        res = requests.post(self.endpoint, self.data)
        self._validate_response(res)
        return self._extract_result(path, res)

    @staticmethod
    def _prepare_request_payload(method, obj=None, **kwargs):
        data = {
            "jsonrpc": "2.0-fox",
            "access_token": None,
            "method": method,
            "kwargs": kwargs,
            "callid": str(uuid.uuid4())
        }
        fields = data['kwargs'].get('fields')
        if fields:
            del data['kwargs']['fields']
            data['fields'] = fields
        if obj is not None:
            data['filter'] = ['id', '==', obj]
        # try:
        return json.dumps(data)
        # except TypeError as err:
        #     for key, value in data['kwargs'].items():
        #         print(key, type(key), value, type(value))
        #     raise err

    def _validate_response(self, res):
        if res.status_code != 200:
            raise ApiClientError(
                'http error', res.url, self.data, res, res.content.decode('utf-8', errors='backslashreplace'))
        res_json = res.json()
        error = res_json.get('error')
        abort = res_json.get('abort')
        if error or abort:
            raise ApiClientUserError('api error', res.url, self.data, error, abort)

    @staticmethod
    def _extract_result(path, res):
        r = res.json()
        for key in path:
            r = r[key]
        return r
