import json
from typing import ClassVar
from urllib.parse import urlsplit, urlunsplit

from requests import JSONDecodeError, Response


class HuntressException(Exception):
    _code_explanation: ClassVar[str] = ""  # Ex: for 404 "Not Found"
    _error_suggestion: ClassVar[str] = ""  # Ex: for 404 "Check the URL you are using is correct"

    def __init__(self, req_response: Response, *, extra_message: str = "") -> None:
        self.response = req_response
        self.extra_message = extra_message
        super().__init__(self.message())

    def _get_sanitized_url(self) -> str:
        """
        Simplify URL down to method, hostname, and path.
        """
        url_components = urlsplit(self.response.url)
        return urlunsplit(
            (
                url_components.scheme,
                url_components.hostname,
                url_components.path,
                "",
                "",
            )
        )

    def details(self) -> str:
        try:
            # If response was json, then format it nicely
            return json.dumps(self.response.json(), indent=4)
        except JSONDecodeError:
            return self.response.text

    def message(self) -> str:
        return (
            f"A HTTP {self.response.status_code} ({self._code_explanation}) error has occurred while requesting"
            f" {self._get_sanitized_url()}.\n{self.response.reason}\n{self._error_suggestion}\n{self.extra_message}"
        ).strip()  # Remove extra whitespace (Ex: if extra_message == "")


class MalformedRequestException(HuntressException):
    _code_explanation = "Bad Request"
    _error_suggestion = (
        "The request could not be understood by the server due to malformed syntax. Please check modify your request"
        " before retrying."
    )


class AuthenticationFailedException(HuntressException):
    _code_explanation = "Unauthorized"
    _error_suggestion = "Please check your credentials are correct before retrying."


class PermissionsFailedException(HuntressException):
    _code_explanation = "Forbidden"
    _error_suggestion = "You may be attempting to access a resource you do not have the appropriate permissions for."


class NotFoundException(HuntressException):
    _code_explanation = "Not Found"
    _error_suggestion = "You may be attempting to access a resource that has been moved or deleted."


class MethodNotAllowedException(HuntressException):
    _code_explanation = "Method Not Allowed"
    _error_suggestion = "This resource does not support the HTTP method you are trying to use."


class ConflictException(HuntressException):
    _code_explanation = "Conflict"
    _error_suggestion = "This resource is possibly in use or conflicts with another record."

class TooManyRequestsException(HuntressException):
    _code_explanation = "Too Many Requests"
    _error_suggestion = "This resource is currently being rate limited. Please wait and try again."


class ServerError(HuntressException):
    _code_explanation = "Internal Server Error"


class ObjectExistsError(HuntressException):
    _code_explanation = "Object Exists"
    _error_suggestion = "This resource already exists."
