public async Task Single_Colour_Should_Publish_Default_Display_With_Single_Colour(string text, string hexValue)
        {
            var request = new LightsRequestBuilder()
                .ForText(text)
                .Build();

            await _lightsService.HandleRequestAsync(request);

            _busPublisher.Received().PublishAsync(Arg.Is<DefaultLightDisplay>(x => x.Colours.Contains(hexValue)));
        }
        public async Task Hex_Values_Should_Be_Published()
        {
            var request = new LightsRequestBuilder()
                .ForText("#cccccc, #101010, #abcdef")
                .Build();

            await _lightsService.HandleRequestAsync(request);

            _busPublisher.Received().PublishAsync(Arg.Is<DefaultLightDisplay>(x =>
                x.Colours[0] == "cccccc" &&
                x.Colours[1] == "101010" &&
                x.Colours[2] == "abcdef"));
        }
        public async Task Multiple_Colours_Should_Publish_Default_Display_With_Multiple_Colours(string text)
        {
            var request = new LightsRequestBuilder()
                .ForText(text)
                .Build();

            await _lightsService.HandleRequestAsync(request);

            _busPublisher.Received().PublishAsync(Arg.Is<DefaultLightDisplay>(x =>
                x.Colours[0] == "ff0000" &&
                x.Colours[1] == "00ff00" &&
                x.Colours[2] == "0000ff"));
        }
        public async Task Unknown_Colours_Should_Be_Silently_Ignored()
        {
            var request = new LightsRequestBuilder()
                .ForText("blue, purple, yellow, red")
                .Build();

            await _lightsService.HandleRequestAsync(request);

            _busPublisher.Received().PublishAsync(Arg.Is<DefaultLightDisplay>(x =>
                x.Colours[0] == "0000ff" &&
                x.Colours[1] == "ff0000"));
        }
        public async Task Given_Request_Is_Scheduled_Then_Service_Should_Return_Scheduled_Time()
        {
            var request1 = new LightsRequestBuilder()
                .ForText("red")
                .From("@photomoose")
                .Build();

            var request2 = new LightsRequestBuilder()
                .ForText("blue")
                .From("@durrylights")
                .Build();

            var now = new DateTime(2015, 1, 1, 0, 0, 0, DateTimeKind.Utc);
            var scheduledTime = now.AddMinutes(1);
            _dateTimeProvider.UtcNow().Returns(now);

            await _lightsService.HandleRequestAsync(request1);
            var result = await _lightsService.HandleRequestAsync(request2);

            result.IsSuccess.Should().BeTrue();
            result.IsScheduled.Should().BeTrue();
            result.ScheduledForUtc.Should().Be(scheduledTime);
        }
        public async Task Given_Request_Is_Not_Scheduled_Then_Service_Should_Return_Success()
        {
            var request = new LightsRequestBuilder()
                .ForText("red")
                .From("@photomoose")
                .Build();

            var result = await _lightsService.HandleRequestAsync(request);

            result.IsSuccess.Should().BeTrue();
            result.IsScheduled.Should().BeFalse();
            result.ScheduledForUtc.Should().NotHaveValue();
        }
        public async Task Invalid_Request_Should_Send_Metric_To_Elastic_Search()
        {
            var request = new LightsRequestBuilder()
                .ForText("no valid colours")
                .FromSource("twitter")
                .From("@photomoose")
                .Build();

            Metric metric = null;
            _metricWriter.SendAsync(Arg.Do<Metric>(a => metric = a));

            var now = new DateTime(2015, 1, 1, 0, 0, 0, DateTimeKind.Utc);
            _dateTimeProvider.UtcNow().Returns(now);

            await _lightsService.HandleRequestAsync(request);

            metric.IsValidCommand.Should().BeFalse();
            metric.TimestampUtc.Should().Be(now);
            metric.RequestText.Should().Be("no valid colours");
            metric.Source.Should().Be("twitter");
            metric.From.Should().Be("@photomoose");
            metric.DisplayType.Should().BeNull();
            metric.Command.Should().BeNull();
            metric.ScheduledAtUtc.Should().NotHaveValue();
            metric.ScheduledDelaySecs.Should().NotHaveValue();
        }
        public async Task Scheduled_Requests_Should_Include_Schedule_In_Metric()
        {
            var request1 = new LightsRequestBuilder()
                .ForText("red")
                .From("@photomoose")
                .Build();

            var request2 = new LightsRequestBuilder()
                .ForText("blue")
                .From("@durrylights")
                .Build();

            var now = new DateTime(2015, 1, 1, 0, 0, 0, DateTimeKind.Utc);
            var scheduledTime = now.AddMinutes(1);

            _dateTimeProvider.UtcNow().Returns(now);
            await _lightsService.HandleRequestAsync(request1);

            Metric metric = null;
            _metricWriter.SendAsync(Arg.Do<Metric>(a => metric = a));

            _dateTimeProvider.UtcNow().Returns(now.AddSeconds(10));
            await _lightsService.HandleRequestAsync(request2);

            metric.IsScheduled.Should().BeTrue();
            metric.ScheduledAtUtc.Should().Be(scheduledTime);
            metric.ScheduledDelaySecs.Should().Be(60 - 10);
        }
        public async Task Multiple_Requests_For_Same_User_After_Existing_Schedule_Should_Be_Scheduled()
        {
            var request1 = new LightsRequestBuilder()
                .ForText("red")
                .From("@photomoose")
                .Build();

            var request2 = new LightsRequestBuilder()
                .ForText("blue")
                .From("@rumr")
                .Build();

            var request3 = new LightsRequestBuilder()
                .ForText("green")
                .From("@rumr")
                .Build();

            await _lightsService.HandleRequestAsync(request1);
            await _lightsService.HandleRequestAsync(request2);
            await _lightsService.HandleRequestAsync(request3);

            _busPublisher.Received().PublishAsync(Arg.Is<DefaultLightDisplay>(x =>
                x.Colours[0] == "00ff00"), Arg.Any<DateTime>());
        }
        public async Task Multiple_Requests_For_Different_Users_Should_Be_Scheduled()
        {
            var request1 = new LightsRequestBuilder()
                .ForText("red")
                .From("@photomoose")
                .Build();

            var request2 = new LightsRequestBuilder()
                .ForText("blue")
                .From("@durrylights")
                .Build();

            var now = new DateTime(2015, 1, 1, 0, 0, 0, DateTimeKind.Utc);
            var scheduledTime = now.AddMinutes(1);
            _dateTimeProvider.UtcNow().Returns(now);

            await _lightsService.HandleRequestAsync(request1);
            await _lightsService.HandleRequestAsync(request2);

            _busPublisher.Received().PublishAsync(Arg.Is<DefaultLightDisplay>(x =>
                x.Colours[0] == "0000ff"), scheduledTime);
        }
        public async Task Cycle_Should_Publish_Cycle()
        {
            var request = new LightsRequestBuilder()
                .ForText("cycle red, green")
                .Build();

            await _lightsService.HandleRequestAsync(request);

            _busPublisher.Received().PublishAsync(Arg.Is<Cycle1LightDisplay>(x =>
                x.Colours[0] == "ff0000" &&
                x.Colours[1] == "00ff00"));
        }
        public async Task Fade_Should_Publish_Fade()
        {
            var request = new LightsRequestBuilder()
                .ForText("fade red, blue")
                .Build();

            await _lightsService.HandleRequestAsync(request);

            _busPublisher.Received().PublishAsync(Arg.Is<FadingInOutLightDisplay>(x =>
                x.Colours[0] == "ff0000" &&
                x.Colours[1] == "0000ff"));
        }
        public async Task No_Recognised_Colours_Should_Not_Publish_Command()
        {
            var request = new LightsRequestBuilder()
                .ForText("unknown")
                .Build();

            await _lightsService.HandleRequestAsync(request);

            _busPublisher.DidNotReceive().PublishAsync(Arg.Any<DefaultLightDisplay>());
        }