public async Task WhenGettingDroneId_ThenInvokesDroneSchedulerAPI()
        {
            string        actualDeliveryId = null;
            DroneDelivery actualDelivery   = null;

            _handleHttpRequest = async ctx =>
            {
                if (ctx.Request.Path.Value.StartsWith(DroneSchedulerPath))
                {
                    await ctx.WriteResultAsync(new ContentResult { Content = "someDroneId", StatusCode = StatusCodes.Status201Created });

                    actualDeliveryId = ctx.Request.Path;
                    actualDelivery   =
                        new JsonSerializer().Deserialize <DroneDelivery>(new JsonTextReader(new StreamReader(ctx.Request.Body, Encoding.UTF8)));
                }
                else
                {
                    ctx.Response.StatusCode = StatusCodes.Status500InternalServerError;
                }
            };

            var delivery =
                new Delivery
            {
                DeliveryId  = "someDeliveryId",
                PackageInfo = new PackageInfo {
                    PackageId = "somePackageId", Size = ContainerSize.Medium, Tag = "sometag", Weight = 100d
                }
            };
            await _caller.GetDroneIdAsync(delivery);

            Assert.NotNull(actualDeliveryId);
            Assert.Equal($"{DroneSchedulerPath}/{delivery.DeliveryId}", actualDeliveryId);

            Assert.NotNull(actualDelivery);
            Assert.Equal(delivery.DeliveryId, actualDelivery.DeliveryId);
            Assert.Equal(delivery.PackageInfo.PackageId, actualDelivery.PackageDetail.Id);
            Assert.Equal((int)delivery.PackageInfo.Size, (int)actualDelivery.PackageDetail.Size);
        }
        public async Task WhenGettingDroneId_ThenInvokesDroneSchedulerAPI()
        {
            string        actualDeliveryId = null;
            DroneDelivery actualDelivery   = null;

            _handleHttpRequest = ctx =>
            {
                if (ctx.Request.Host.Host == DroneSchedulerHost)
                {
                    actualDeliveryId = ctx.Request.Path;
                    actualDelivery   =
                        new JsonSerializer().Deserialize <DroneDelivery>(new JsonTextReader(new StreamReader(ctx.Request.Body, Encoding.UTF8)));
                }
                else
                {
                    ctx.Response.StatusCode = StatusCodes.Status500InternalServerError;
                }

                return(Task.CompletedTask);
            };

            var delivery =
                new Delivery
            {
                DeliveryId  = "someDeliveryId",
                PackageInfo = new PackageInfo {
                    PackageId = "somePackageId", Size = ContainerSize.Medium, Tag = "sometag", Weight = 100d
                }
            };
            await _caller.GetDroneIdAsync(delivery);

            Assert.NotNull(actualDeliveryId);
            Assert.Equal($"/api/DroneDeliveries/{delivery.DeliveryId}", actualDeliveryId);

            Assert.NotNull(actualDelivery);
            Assert.Equal(delivery.DeliveryId, actualDelivery.DeliveryId);
            Assert.Equal(delivery.PackageInfo.PackageId, actualDelivery.PackageDetail.Id);
            Assert.Equal((int)delivery.PackageInfo.Size, (int)actualDelivery.PackageDetail.Size);
        }
        public async Task <bool> ProcessDeliveryRequestAsync(Delivery deliveryRequest, IReadOnlyDictionary <string, object> properties)
        {
            _logger.LogInformation("Processing delivery request {deliveryId}", deliveryRequest.DeliveryId);

            try
            {
                var packageGen = await _packageServiceCaller.UpsertPackageAsync(deliveryRequest.PackageInfo).ConfigureAwait(false);

                if (packageGen != null)
                {
                    _logger.LogInformation("Generated package {packageId} for delivery {deliveryId}", packageGen.Id, deliveryRequest.DeliveryId);

                    var droneId = await _droneSchedulerServiceCaller.GetDroneIdAsync(deliveryRequest).ConfigureAwait(false);

                    if (droneId != null)
                    {
                        _logger.LogInformation("Assigned drone {droneId} for delivery {deliveryId}", droneId, deliveryRequest.DeliveryId);

                        var deliverySchedule = await _deliveryServiceCaller.ScheduleDeliveryAsync(deliveryRequest, droneId);

                        if (deliverySchedule != null)
                        {
                            _logger.LogInformation("Completed delivery {deliveryId}", deliveryRequest.DeliveryId);
                            return(true);
                        }
                        else
                        {
                            _logger.LogError("Failed delivery for request {deliveryId}", deliveryRequest.DeliveryId);
                        }
                    }
                }
            }
            catch (Exception e)
            {
                _logger.LogError(e, "Error processing delivery request {deliveryId}", deliveryRequest.DeliveryId);
            }

            return(false);
        }
        public async Task <IActionResult> Operation([FromBody] EventGridEvent[] events)
        {
            if (events == null)
            {
                logger.LogError("event is  Null");
                return(BadRequest("No Event for Choreography"));
            }

            if (events[0].EventType is EventTypes.EventGridSubscriptionValidationEvent)
            {
                try
                {
                    var data     = Operations.ConvertDataEventToType <SubscriptionValidationEventData>(events[0].Data);
                    var response = new SubscriptionValidationResponse(data.ValidationCode);
                    return(Ok(response));
                }
                catch (NullReferenceException ex)
                {
                    logger.LogError("Event Grid Subscription validation error", ex);
                    return(BadRequest(ex));
                }
            }

            foreach (var e in events)
            {
                Delivery delivery;

                try
                {
                    delivery = Operations.ConvertDataEventToType <Delivery>(e.Data);
                }
                catch (InvalidCastException ex)
                {
                    logger.LogError("Invalid delivery Object for delivery payload", ex);
                    return(BadRequest(ex));
                }

                if (delivery is null)
                {
                    logger.LogError("null delivery in delivery data");
                    return(BadRequest("Invalid delivery"));
                }

                List <EventGridEvent> listEvents = new List <EventGridEvent>();
                e.Topic     = eventRepository.GetTopic();
                e.EventTime = DateTime.Now;
                switch (e.EventType)
                {
                case Operations.ChoreographyOperation.ScheduleDelivery:
                {
                    try
                    {
                        var packageGen = await packageServiceCaller.UpsertPackageAsync(delivery.PackageInfo).ConfigureAwait(false);

                        if (packageGen is null)
                        {
                            //we return bad request and allow the event to be reprocessed by event grid
                            return(BadRequest("could not get a package object from package service"));
                        }

                        //we set the eventype to the next choreography step
                        e.EventType = Operations.ChoreographyOperation.CreatePackage;
                        listEvents.Add(e);
                        await eventRepository.SendEventAsync(listEvents);

                        return(Ok("Created Package Completed"));
                    }
                    catch (Exception ex) when(ex is BackendServiceCallFailedException ||
                                              ex is EventException || ex is Exception)
                    {
                        logger.LogError(ex.Message, ex);
                        return(BadRequest(ex));
                    }
                }

                case Operations.ChoreographyOperation.CreatePackage:
                {
                    try
                    {
                        var droneId = await droneSchedulerServiceCaller.GetDroneIdAsync(delivery).ConfigureAwait(false);

                        if (droneId is null)
                        {
                            //we return bad request and allow the event to be reprocessed by event grid
                            return(BadRequest("could not get a drone id"));
                        }
                        e.Subject   = droneId;
                        e.EventType = Operations.ChoreographyOperation.GetDrone;
                        listEvents.Add(e);
                        await eventRepository.SendEventAsync(listEvents);

                        return(Ok("Drone Completed"));
                    }
                    catch (Exception ex) when(ex is BackendServiceCallFailedException ||
                                              ex is EventException)
                    {
                        logger.LogError(ex.Message, ex);
                        return(BadRequest(ex));
                    }
                }

                case Operations.ChoreographyOperation.GetDrone:
                {
                    try
                    {
                        var deliverySchedule = await deliveryServiceCaller.ScheduleDeliveryAsync(delivery, e.Subject);

                        return(Ok("Delivery Completed"));
                    }
                    catch (Exception ex) when(ex is BackendServiceCallFailedException)
                    {
                        logger.LogError(ex.Message, ex);
                        return(BadRequest(ex));
                    }
                }
                }
            }


            return(BadRequest());
        }