# coding: utf-8
#
# This code was auto generated by AfterShip SDK Generator.
# Do not edit the class manually.

import json
from typing import Union

import httpx

from tracking.exceptions import (
    ErrorCodeEnum,
    UnknownError,
    BadRequestError,
    UnauthorizedError,
    ForbiddenError,
    NotFoundError,
    InternalError,
    TooManyRequestsError,
    TimedOutError,
)

error_mapping = {
    "BadRequest": BadRequestError,
    "Unauthorized": UnauthorizedError,
    "Forbidden": ForbiddenError,
    "NotFound": NotFoundError,
    "TooManyRequests": TooManyRequestsError,
    "InternalError": InternalError,
    "TimedOutError": TimedOutError,
}

_error_meta_code_mapping = {
    "400": ErrorCodeEnum.INTERNAL_ERROR,
    "4001": ErrorCodeEnum.INVALID_JSON,
    "4003": ErrorCodeEnum.TRACKING_ALREADY_EXIST,
    "4004": ErrorCodeEnum.TRACKING_DOES_NOT_EXIST,
    "4005": ErrorCodeEnum.TRACKING_NUMBER_INVALID,
    "4006": ErrorCodeEnum.TRACKING_REQUIRED,
    "4007": ErrorCodeEnum.TRACKING_NUMBER_REQUIRED,
    "4008": ErrorCodeEnum.VALUE_INVALID,
    "4009": ErrorCodeEnum.VALUE_REQUIRED,
    "4010": ErrorCodeEnum.SLUG_INVALID,
    "4011": ErrorCodeEnum.MISSING_OR_INVALID_REQUIRED_FIELD,
    "4012": ErrorCodeEnum.BAD_COURIER,
    "4013": ErrorCodeEnum.INACTIVE_RETRACK_NOT_ALLOWED,
    "4014": ErrorCodeEnum.NOTIFICATION_REUQIRED,
    "4015": ErrorCodeEnum.ID_INVALID,
    "4016": ErrorCodeEnum.RETRACK_ONCE_ALLOWED,
    "4017": ErrorCodeEnum.TRACKING_NUMBER_FORMAT_INVALID,
    "401": ErrorCodeEnum.API_KEY_INVALID,
    "403": ErrorCodeEnum.REQUEST_NOT_ALLOWED,
    "404": ErrorCodeEnum.NOT_FOUND,
    "429": ErrorCodeEnum.TOO_MANY_REQUEST,
    "500": ErrorCodeEnum.INTERNAL_ERROR,
    "502": ErrorCodeEnum.INTERNAL_ERROR,
    "504": ErrorCodeEnum.INTERNAL_ERROR,
}


def get_error_code(meta_code: int) -> str:
    if _error_meta_code_mapping.get(str(meta_code)):
        return str(_error_meta_code_mapping[str(meta_code)])
    return str(ErrorCodeEnum.INTERNAL_ERROR)


def parse_response(response: httpx.Response) -> Union[dict, None]:
    try:
        json_data = response.json()

        if response.status_code < 300:
            return json_data["data"]

        error_type = json_data["meta"]["type"]
        if error_type in error_mapping:
            error_cls = error_mapping[error_type]
        else:
            error_cls = UnknownError

        raise error_cls(
            code=get_error_code(json_data["meta"]["code"]),
            meta_code=json_data["meta"]["code"],
            status_code=response.status_code,
            message=json_data["meta"]["message"],
            response_body=response.text,
            response_header=response.headers,
        )
    except (json.JSONDecodeError, KeyError) as e:
        raise UnknownError(
            code=ErrorCodeEnum.UNKNOW_ERROR,
            meta_code=500,
            status_code=response.status_code,
            message=f"{e.__module__}.{e.__class__.__name__}: {e}",
            response_body=response.text,
            response_header=response.headers,
        )
