from typing import List, Any, Optional, Tuple, Type, Union


class GatewayServerError(Exception):
    def __init__(self, server_error: str, response: Optional[dict], client_request: Optional[str]):
        Exception.__init__(self, server_error, response, client_request)

    @property
    def error(self):
        return self.args[0]

    @property
    def response(self):
        return self.args[1]

    @property
    def context(self):
        return self.args[2]


def check_single_response(resp: List[Any], response_types: Union[Type, Tuple[Type, ...]], request_description: str):
    if len(resp) != 1:
        raise Exception(f"failed to {request_description}: {resp}")
    if isinstance(resp[0], dict):
        # Response may be data or error payload; later must be recognised by the used keys, because collection
        # loses the response-type.
        if "message" in resp[0]:
            raise GatewayServerError(resp[0]["message"], resp[0], request_description)
        if resp[0].get("errors"):
            raise GatewayServerError(resp[0]["errors"][0]["message"], resp[0], request_description)
    # Check the type of the response to be expected. At this point it exists and does not seem to be an error.
    if not isinstance(resp[0], response_types):
        raise Exception(f"unexpected response type for {request_description}: {resp}")
    return resp[0]
