private BatchStatus UploadNextBatch(int batchSize, int keyAgeLimitInDays)
        {
            var lastSyncState = _settingsService.GetGatewayUploadState();

            // Select only keys from last N days (by date of record creation)
            var uploadedOnAndAfterTicks = lastSyncState.CreationDateOfLastUploadedKey;
            var uploadedOnAndAfter      = uploadedOnAndAfterTicks.HasValue ? new DateTime(uploadedOnAndAfterTicks.Value, DateTimeKind.Utc) : DateTime.UnixEpoch;

            int batchSizePlusOne = batchSize + 1; // if it will return n + 1 then there is at last one more records to send

            // Get key package - collection of the records created (uploaded by mobile app) in the db after {uploadedOn}
            IList <TemporaryExposureKey> keyPackage = _tempKeyRepository.GetKeysOnlyFromApiOriginCountryUploadedAfterTheDateForGatewayUploadForWhichConsentWasGiven(
                uploadedOnAndLater: uploadedOnAndAfter,
                numberOfRecordToSkip: lastSyncState.NumberOfKeysProcessedFromTheLastCreationDate,
                maxCount: batchSizePlusOne,
                new KeySource[] { KeySource.SmitteStopApiVersion3 });

            // Take all record uploaded after the date.
            var currBatchStatus = new BatchStatus()
            {
                NextBatchExists = keyPackage.Count == batchSizePlusOne
            };

            keyPackage = keyPackage.Take(batchSize).ToList();
            currBatchStatus.KeysProcessed         = keyPackage.Count;
            currBatchStatus.ProcessedSuccessfully = true;

            if (!keyPackage.Any())
            {
                _logger.LogInformation("KeyPackage is empty. Stopping the upload process.");
                return(currBatchStatus);
            }
            _logger.LogInformation($"{keyPackage.Count} records picked.");

            var oldestKeyFromPackage = keyPackage.Last(); // be aware that it could not be present in the batch. This is the last record (have oldest CreationOn) that has been processed.

            // Create Batch based on package but filter in on RollingStartNumber. Batch.Size <= Package.Size
            // We can send data not older than N days ago (age of the key save in key.RollingStartNumber)
            DateTime createdAfter          = DateTime.UtcNow.AddDays(-keyAgeLimitInDays);
            var      createdAfterTimestamp = _epochConverter.ConvertToEpoch(createdAfter);

            var filteredKeysForBatch =
                keyPackage
                .Where(k => k.RollingStartNumber > createdAfterTimestamp)
                .Where(k => k.DaysSinceOnsetOfSymptoms >= KeyValidator.DaysSinceOnsetOfSymptomsValidRangeMin)
                .Where(k => k.DaysSinceOnsetOfSymptoms <= KeyValidator.DaysSinceOnsetOfSymptomsValidRangeMax)
                .ToList();

            currBatchStatus.KeysToSend = filteredKeysForBatch.Count;

            var batch = CreateGatewayBatchFromKeys(filteredKeysForBatch);
            TemporaryExposureKeyGatewayBatchProtoDto protoBatch = MapBatchDtoToProtoAndSortForSigning(batch);

            _logger.LogInformation($"{currBatchStatus.KeysToSend} records to send after filtering by age.");

            if (protoBatch.Keys.Any())
            {
                _logger.LogInformation($"Sending batch...");
                currBatchStatus.ProcessedSuccessfully = TrySendKeyBatchToTheGateway(protoBatch, KeysSortOrderUsedToCreateAndVerifyUploadRequestSignature);
            }
            else
            {
                _logger.LogInformation($"Nothing to sent for this package. All picked keys are older then {keyAgeLimitInDays} days or have incorrect value of DaysSinceOnsetOfSymptoms.");
            }

            if (currBatchStatus.ProcessedSuccessfully)
            {
                currBatchStatus.KeysSent = protoBatch.Keys.Count;

                var currSyncState    = new GatewayUploadState();
                var lastSentKeyTicks = oldestKeyFromPackage.CreatedOn.Ticks;
                // If the date of the last sent element (recently) has changed in compare the date from the previous batch?
                //  NO - Update the state: Do not change the date, only offset (+=)
                //  YES - Update the state: Change date to the date from last sent element. Update the index to the offset from the first appearance of that date.)
                if (lastSyncState.CreationDateOfLastUploadedKey == lastSentKeyTicks)
                {
                    currSyncState.CreationDateOfLastUploadedKey = lastSyncState.CreationDateOfLastUploadedKey;
                    currSyncState.NumberOfKeysProcessedFromTheLastCreationDate = lastSyncState.NumberOfKeysProcessedFromTheLastCreationDate + currBatchStatus.KeysProcessed;
                }
                else
                {
                    currSyncState.CreationDateOfLastUploadedKey = oldestKeyFromPackage.CreatedOn.Ticks;
                    // find offset form fist element with CreationDateOfLastUploadedKey to last sent element
                    var indexOfTheFirstKeyWithTheDate = keyPackage.Select((k, i) => new { Key = k, Index = i })
                                                        .First(o => o.Key.CreatedOn.Ticks == lastSentKeyTicks)
                                                        .Index;

                    currSyncState.NumberOfKeysProcessedFromTheLastCreationDate = currBatchStatus.KeysProcessed - indexOfTheFirstKeyWithTheDate;
                }
                // save new sync status
                _settingsService.SaveGatewaySyncState(currSyncState);
            }
            else
            {
                _logger.LogError($"Error sending the batch! Stopping upload process.");
            }
            return(currBatchStatus);
        }