﻿using NUnit.Framework;
using System;

namespace GenderPayGap.Core.Tests.AzureQueue
{
    using GenderPayGap.Core.Classes.Queues;
    using GenderPayGap.Core.Interfaces;
    using Moq;
    using System.Text;
    using System.Threading.Tasks;

    [TestFixture]
    public class AddMessageAsyncTests
    {
        string testConnectionString = "LogEventUnitTests";
        string testQueueName = "LogEventUnitTests";
        AzureQueue testAzureQueue;

        [SetUp]
        public void BeforeEach()
        {
            testAzureQueue = new AzureQueue(testConnectionString, testQueueName);
        }

        [TestCase]
        public void ThrowsWhenInstanceIsNull()
        {
            // Act
            var actualExpection = Assert.ThrowsAsync<ArgumentNullException>(async () => await testAzureQueue.AddMessageAsync<object>(null));

            // Assert
            Assert.AreEqual("Value cannot be null.\r\nParameter name: instance", actualExpection.Message);
        }

        [TestCase]
        public void ThrowsWhenInstanceIsDefault()
        {
            // Act
            var actualExpection = Assert.ThrowsAsync<ArgumentNullException>(async () => await testAzureQueue.AddMessageAsync(default(object)));

            // Assert
            Assert.AreEqual("Value cannot be null.\r\nParameter name: instance", actualExpection.Message);
        }

        [TestCase("")]
        [TestCase("  ")]
        [TestCase(null)]
        public void ThrowsWhenMessageIsIllegal(string testMessage)
        {
            // Act
            var actualExpection = Assert.ThrowsAsync<ArgumentNullException>(async () => await testAzureQueue.AddMessageAsync(testMessage));

            // Assert
            Assert.AreEqual("Value cannot be null.\r\nParameter name: message", actualExpection.Message);
        }

        [TestCase]
        public void ThrowsWhenLargeMessageAndNotSupported()
        {
            // Arrange
            string testLargeMessage = new string('a', 66000);

            // Act
            var actualExpection = Assert.ThrowsAsync<ArgumentException>(async () => await testAzureQueue.AddMessageAsync(testLargeMessage));

            // Assert
            Assert.AreEqual(
                $"AzureQueue: Queue message exceeds maximum message size for azure queues. The message size was {testLargeMessage.Length}. Azure's maximum message size is 65536.\r\nParameter name: message",
                actualExpection.Message
            );
        }

        [TestCase]
        public void WritesLargeMessagesToStorage()
        {
            // Arrange
            bool WriteAsyncAsyncWasCalled = false;
            var mockFileRepo = new Mock<IFileRepository>();
            string testLargeMessage = new string('a', 66000);
            testAzureQueue = new AzureQueue(testConnectionString, testQueueName, mockFileRepo.Object);

            mockFileRepo.Setup(f => f.WriteAsync(It.IsAny<String>(), It.IsAny<byte[]>()))
                .Callback((string filePath, byte[] data) => {
                    // Assert
                    Assert.IsTrue(filePath.StartsWith("LargeQueueFiles\\LogEventUnitTests\\"), "Expected large filepath to match");
                    Assert.IsTrue(filePath.EndsWith(".json"), "Expected large filepath to be a json file");

                    Assert.AreEqual(testLargeMessage, Encoding.UTF8.GetString(data), "Expected large message to be the same");
                    
                    WriteAsyncAsyncWasCalled = true;
                })
                .Returns(Task.CompletedTask);

            // Act (We expect an exception here because we cant actually connect to azure so we get a connection error)
            Assert.ThrowsAsync<FormatException>(async () => await testAzureQueue.AddMessageAsync(testLargeMessage));

            // Assert
            Assert.IsTrue(WriteAsyncAsyncWasCalled, "Expected IFileRepository.WriteAsyncAsync to be called.");
        }

    }
}
