"""
Python SDK for OpenFGA

API version: 1.x
Website: https://openfga.dev
Documentation: https://openfga.dev/docs
Support: https://openfga.dev/community
License: [Apache-2.0](https://github.com/openfga/python-sdk/blob/main/LICENSE)

NOTE: This file was auto generated by OpenAPI Generator (https://openapi-generator.tech). DO NOT EDIT.
"""

# Specifc FGA header to be parsed
X_RATELIMIT_LIMIT = "x-ratelimit-limit"
X_RATELIMIT_REMAINING = "x_ratelimit_remaining"
X_RATELIMIT_RESET = "x_ratelimit_reset"
FGA_REQUEST_ID = "fga-request-id"
FGA_QUERY_DURATION_MS = "fga-query-duration-ms"
OPENFGA_AUTHORIZATION_MODEL_ID = "openfga_authorization_model_id"
RESPONSE_HEADERS_TO_KEEP = [
    X_RATELIMIT_LIMIT,
    X_RATELIMIT_REMAINING,
    X_RATELIMIT_RESET,
    FGA_REQUEST_ID,
    FGA_QUERY_DURATION_MS,
    OPENFGA_AUTHORIZATION_MODEL_ID,
]


class OpenApiException(Exception):
    """The base exception class for all OpenAPIExceptions"""


class FgaValidationException(OpenApiException, TypeError):
    def __init__(self, msg, path_to_item=None, valid_classes=None, key_type=None):
        """Raises an exception for TypeErrors

        Args:
            msg (str): the exception message

        Keyword Args:
            path_to_item (list): a list of keys an indices to get to the
                                 current_item
                                 None if unset
            valid_classes (tuple): the primitive classes that current item
                                   should be an instance of
                                   None if unset
            key_type (bool): False if our value is a value in a dict
                             True if it is a key in a dict
                             False if our item is an item in a list
                             None if unset
        """
        self.path_to_item = path_to_item
        self.valid_classes = valid_classes
        self.key_type = key_type
        full_msg = msg
        if path_to_item:
            full_msg = f"{msg} at {render_path(path_to_item)}"
        super().__init__(full_msg)


class ApiValueError(OpenApiException, ValueError):
    def __init__(self, msg, path_to_item=None):
        """
        Args:
            msg (str): the exception message

        Keyword Args:
            path_to_item (list) the path to the exception in the
                received_data dict. None if unset
        """

        self.path_to_item = path_to_item
        full_msg = msg
        if path_to_item:
            full_msg = f"{msg} at {render_path(path_to_item)}"
        super().__init__(full_msg)


class ApiAttributeError(OpenApiException, AttributeError):
    def __init__(self, msg, path_to_item=None):
        """
        Raised when an attribute reference or assignment fails.

        Args:
            msg (str): the exception message

        Keyword Args:
            path_to_item (None/list) the path to the exception in the
                received_data dict
        """
        self.path_to_item = path_to_item
        full_msg = msg
        if path_to_item:
            full_msg = f"{msg} at {render_path(path_to_item)}"
        super().__init__(full_msg)


class ApiKeyError(OpenApiException, KeyError):
    def __init__(self, msg, path_to_item=None):
        """
        Args:
            msg (str): the exception message

        Keyword Args:
            path_to_item (None/list) the path to the exception in the
                received_data dict
        """
        self.path_to_item = path_to_item
        full_msg = msg
        if path_to_item:
            full_msg = f"{msg} at {render_path(path_to_item)}"
        super().__init__(full_msg)


class ApiException(OpenApiException):
    def __init__(self, status=None, reason=None, http_resp=None):
        if http_resp:
            try:
                headers = http_resp.headers.items()
            except AttributeError:
                headers = http_resp.getheaders().items()

            self.status = http_resp.status
            self.reason = http_resp.reason
            self.body = http_resp.data
            self._parsed_exception = None
            normalized_headers = {k.lower(): v for k, v in headers}
            self.header = dict()
            for key in RESPONSE_HEADERS_TO_KEEP:
                self.header[key] = normalized_headers.get(key)
        else:
            self.status = status
            self.reason = reason
            self.body = None
            self._parsed_exception = None
            self.header = dict()

    def __str__(self):
        """Custom error messages for exception"""
        error_message = f"({self.status})\nReason: {self.reason}\n"

        if self.body:
            error_message += f"HTTP response body: {self.body}\n"

        return error_message

    @property
    def parsed_exception(self):
        """
        Return the parsed body of the exception
        """
        return self._parsed_exception

    @parsed_exception.setter
    def parsed_exception(self, content):
        """
        Update the deserialized content
        """
        self._parsed_exception = content


class NotFoundException(ApiException):
    def __init__(self, status=None, reason=None, http_resp=None):
        super().__init__(status, reason, http_resp)


class UnauthorizedException(ApiException):
    def __init__(self, status=None, reason=None, http_resp=None):
        super().__init__(status, reason, http_resp)


class ForbiddenException(ApiException):
    def __init__(self, status=None, reason=None, http_resp=None):
        super().__init__(status, reason, http_resp)


class ServiceException(ApiException):
    def __init__(self, status=None, reason=None, http_resp=None):
        super().__init__(status, reason, http_resp)


class ValidationException(ApiException):
    def __init__(self, status=None, reason=None, http_resp=None):
        super().__init__(status, reason, http_resp)


class AuthenticationError(ApiException):
    def __init__(self, status=None, reason=None, http_resp=None):
        super().__init__(status, reason, http_resp)


class RateLimitExceededError(ApiException):
    def __init__(self, status=None, reason=None, http_resp=None):
        super().__init__(status, reason, http_resp)


def render_path(path_to_item):
    """Returns a string representation of a path"""
    result = ""
    for pth in path_to_item:
        if isinstance(pth, int):
            result += f"[{pth}]"
        else:
            result += f"['{pth}']"
    return result
