private function createByReason(string $reason, array $json): SendNotificationException
    {
        $reason = strtolower($reason);

        switch ($reason) {
            case 'badcollapseid':
                return new BadCollapseIdException();

            case 'baddevicetoken':
                return new BadDeviceTokenException();

            case 'badexpirationdate':
                return new BadExpirationDateException();

            case 'badmessageid':
                return new BadMessageIdException();

            case 'badpriority':
                return new BadPriorityException();

            case 'badtopic':
                return new BadTopicException();

            case 'devicetokennotfortopic':
                return new DeviceTokenNotForTopicException();

            case 'duplicateheaders':
                return new DuplicateHeadersException();

            case 'idletimeout':
                return new IdleTimeoutException();

            case 'missingdevicetoken':
                return new MissingDeviceTokenException();

            case 'missingtopic':
                return new MissingTopicException();

            case 'payloadempty':
                return new PayloadEmptyException();

            case 'topicdisallowed':
                return new TopicDisallowedException();

            case 'badcertificate':
                return new BadCertificateException();

            case 'badcertificateenvironment':
                return new BadCertificateEnvironmentException();

            case 'expiredprovidertoken':
                return new ExpiredProviderTokenException();

            case 'forbidden':
                return new ForbiddenException();

            case 'invalidprovidertoken':
                return new InvalidProviderTokenException();

            case 'missingprovidertoken':
                return new MissingProviderTokenException();

            case 'badpath':
                return new BadPathException();

            case 'methodnotallowed':
                return new MethodNotAllowedException();

            case 'unregistered':
                $timestamp = array_key_exists('timestamp', $json) ? $json['timestamp'] : 0;
                $lastConfirmed = new \DateTime('now', new \DateTimeZone('UTC'));
                $lastConfirmed->setTimestamp($timestamp);

                return new UnregisteredException($lastConfirmed);

            case 'payloadtoolarge':
                return new PayloadTooLargeException();

            case 'toomanyprovidertokenupdates':
                return new TooManyProviderTokenUpdatesException();

            case 'toomanyrequests':
                return new TooManyRequestsException();

            case 'internalservererror':
                return new InternalServerErrorException();

            case 'serviceunavailable':
                return new ServiceUnavailableException();

            case 'shutdown':
                return new ShutdownException();

            default:
                return new UndefinedErrorException();
        }
    }