namespace ByteBard.AsyncAPI.Tests.Bindings.AMQP
{
    using System.Collections.Generic;
    using FluentAssertions;
    using ByteBard.AsyncAPI.Bindings;
    using ByteBard.AsyncAPI.Bindings.AMQP;
    using ByteBard.AsyncAPI.Models;
    using ByteBard.AsyncAPI.Readers;
    using NUnit.Framework;

    public class AMQPBindings_Should
    {
        [Test]
        public void V2_AMQPChannelBinding_WithRoutingKey_SerializesAndDeserializes()
        {
            // Arrange
            var expected =
                """
                bindings:
                  amqp:
                    is: routingKey
                    exchange:
                      name: myExchange
                      type: topic
                      durable: true
                      autoDelete: false
                      vhost: /
                """;

            var channel = new AsyncApiChannel();
            channel.Bindings.Add(new AMQPChannelBinding
            {
                Is = ChannelType.RoutingKey,
                Exchange = new Exchange
                {
                    Name = "myExchange",
                    Type = ExchangeType.Topic,
                    Durable = true,
                    AutoDelete = false,
                    Vhost = "/",
                },
            });

            // Act
            var actual = channel.SerializeAsYaml(AsyncApiVersion.AsyncApi2_0);

            // Assert
            var settings = new AsyncApiReaderSettings();
            settings.Bindings = BindingsCollection.AMQP;
            var binding = new AsyncApiStringReader(settings).ReadFragment<AsyncApiChannel>(actual, AsyncApiVersion.AsyncApi2_0, out _);

            // Assert
            actual.Should()
                .BePlatformAgnosticEquivalentTo(expected);
            binding.Should().BeEquivalentTo(channel);
        }

        [Test]
        public void V2_AMQPChannelBinding_WithQueue_SerializesAndDeserializes()
        {
            // Arrange
            var expected =
                """
                bindings:
                  amqp:
                    is: queue
                    queue:
                      name: my-queue-name
                      durable: true
                      exclusive: true
                      autoDelete: false
                      vhost: /
                """;

            var channel = new AsyncApiChannel();
            channel.Bindings.Add(new AMQPChannelBinding
            {
                Is = ChannelType.Queue,
                Queue = new Queue
                {
                    Name = "my-queue-name",
                    Durable = true,
                    Exclusive = true,
                    AutoDelete = false,
                    Vhost = "/",
                },
            });

            // Act
            var actual = channel.SerializeAsYaml(AsyncApiVersion.AsyncApi2_0);

            // Assert
            var settings = new AsyncApiReaderSettings();
            settings.Bindings = BindingsCollection.AMQP;
            var binding = new AsyncApiStringReader(settings).ReadFragment<AsyncApiChannel>(actual, AsyncApiVersion.AsyncApi2_0, out _);

            // Assert
            actual.Should()
                .BePlatformAgnosticEquivalentTo(expected);
            binding.Should().BeEquivalentTo(channel);
        }

        [Test]
        public void V2_AMQPMessageBinding_WithFilledObject_SerializesAndDeserializes()
        {
            // Arrange
            var expected =
                """
                bindings:
                  amqp:
                    contentEncoding: gzip
                    messageType: user.signup
                """;

            var message = new AsyncApiMessage();

            message.Bindings.Add(new AMQPMessageBinding
            {
                ContentEncoding = "gzip",
                MessageType = "user.signup",
            });

            // Act
            var actual = message.SerializeAsYaml(AsyncApiVersion.AsyncApi2_0);
            var settings = new AsyncApiReaderSettings();
            settings.Bindings = BindingsCollection.AMQP;
            var binding = new AsyncApiStringReader(settings).ReadFragment<AsyncApiMessage>(actual, AsyncApiVersion.AsyncApi2_0, out _);

            // Assert
            actual.Should()
                .BePlatformAgnosticEquivalentTo(expected);
            binding.Should().BeEquivalentTo(message);
        }

        [Test]
        public void V2_AMQPOperationBinding_WithFilledObject_SerializesAndDeserializes()
        {
            // Arrange
            var expected =
                """
                bindings:
                  amqp:
                    expiration: 100000
                    userId: guest
                    cc:
                      - user.logs
                    priority: 10
                    deliveryMode: 2
                    mandatory: false
                    bcc:
                      - external.audit
                    timestamp: true
                    ack: false
                """;

            var operation = new AsyncApiOperation();
            operation.Bindings.Add(new AMQPOperationBinding
            {
                Expiration = 100000,
                UserId = "guest",
                Cc = new List<string> { "user.logs" },
                Priority = 10,
                DeliveryMode = DeliveryMode.Persistent,
                Mandatory = false,
                Bcc = new List<string> { "external.audit" },
                Timestamp = true,
                Ack = false,
            }); ;

            // Act
            var actual = operation.SerializeAsYaml(AsyncApiVersion.AsyncApi2_0);

            var settings = new AsyncApiReaderSettings();
            settings.Bindings = BindingsCollection.AMQP;
            var binding = new AsyncApiStringReader(settings).ReadFragment<AsyncApiOperation>(actual, AsyncApiVersion.AsyncApi2_0, out _);

            // Assert
            actual.Should()
                .BePlatformAgnosticEquivalentTo(expected);
            binding.Should().BeEquivalentTo(operation);
        }
    }
}
