using System;
using System.Net.Mime;
using System.Text.RegularExpressions;
using Autofac;
using FitConnect;
using FitConnect.Encryption;
using FitConnect.Interfaces;
using FitConnect.Models;
using FitConnect.Models.Api.Metadata;
using FitConnect.Models.Api.Set;
using FitConnect.Services;
using FluentAssertions;
using Microsoft.Extensions.Logging;
using MockContainer;
using NUnit.Framework;
using Attachment = FitConnect.Models.Attachment;

namespace BasicUnitTest;

public class SenderTests {
    private IContainer _container = null!;
    protected string clientId = null!;
    protected string clientSecret = null!;
    private string serviceIdentifier = null!;
    private ILogger? logger;

    [OneTimeSetUp]
    public void OneTimeSetup() {
        _container = Container.Create();
        logger = _container.Resolve<ILogger>();
        var settings = _container.Resolve<IFitConnectSettings>();
        clientId = settings.SenderClientId;
        clientSecret = settings.SenderClientSecret;
        serviceIdentifier = settings.ServiceIdentifier;
    }

    [SetUp]
    public void Setup() {
        logger = _container.Resolve<ILogger>();
    }

    [Test]
    public void FluentSender_ShouldNotThrowAnError_ArgumentExceptionLeikaKeyInvalid() {
        Assert.Throws<ArgumentException>(() => {
            var sender = ClientFactory.GetSenderClient(Container.Create());
            var outgoing = SendableSubmission.Builder()
                .SetDestination(Guid.NewGuid())
                .SetServiceType("", "")
                .SetJsonData("")
                .AddAttachments(Array.Empty<Attachment>())
                .Build();


            sender.SendAsync(outgoing).Wait();
        })!.Message.Should().Be("Invalid leika key");
    }

    [Test]
    public void AddReplyChannelToSubmission() {
        const string email = "dummy@trashmail.com";
        var sender = ClientFactory.GetSenderClient(Container.Create());

        var submission = SendableSubmission.Builder().SetDestination(Guid.NewGuid())
            .SetServiceType(serviceIdentifier, "Dummy")
            .SetJsonData(@"{""Name"":""Test""}")
            .SetReplyChannel(new EMail(email))
            .Build();

        submission.ReplyChannel?.EMail?.Address.Should().Be(email);
    }

    [Test]
    public void AddPaymentInfoToSubmission() {
        const string email = "dummy@trashmail.com";
        var sender = ClientFactory.GetSenderClient(Container.Create());

        var submission = SendableSubmission.Builder().SetDestination(Guid.NewGuid())
            .SetServiceType(serviceIdentifier, "Dummy")
            .SetJsonData(@"{""Name"":""Test""}")
            .SetAuthenticationInformation(
                new AuthenticationInformation("Ausweis",
                    AuthenticationInformationType.IdentificationReport, "1.0.1"),
                new AuthenticationInformation("Fingerabdruck",
                    AuthenticationInformationType.IdentificationReport, "1.0.1")
            )
            .SetPaymentInformation(
                new PaymentInformation(PaymentMethod.Creditcard, PaymentStatus.Booked, "1234",
                    "dummy") {
                })
            .Build();

        submission.ReplyChannel?.EMail?.Address.Should().Be(email);
    }

    [Test]
    public void FluentSender_ShouldNotThrowAnError_MockingServicesWithData() {
        var sender = ClientFactory.GetSenderClient(Container.Create());

        var outgoing = SendableSubmission.Builder()
            .SetDestination(Guid.NewGuid())
            .SetServiceType(serviceIdentifier, "")
            .SetJsonData("")
            .AddAttachments(Array.Empty<Attachment>())
            .Build();
        sender.SendAsync(outgoing).Wait();
    }

    [Test]
    public void CheckVersionStringHeader() {
        var version = RestCallService.GetVersionHeader();

        var regex =
            new Regex(FitConnectClient.VersionHeaderPattern);

        version.Should().MatchRegex(regex);
        Console.WriteLine(version);
    }

    [Test]
    public void FluentSender_ShouldNotThrowAnError_MockingServicesWithXmlData() {
        var sender = new Sender(FitConnectEnvironment.Testing,
            clientId, clientSecret,
            Container.Create());

        var outgoing = SendableSubmission.Builder()
            .SetDestination(Guid.NewGuid())
            .SetServiceType(serviceIdentifier, "")
            .SetXmlData(
                @"<?xml version=""1.0"" encoding=""UTF-8""?> <root> <child>value</child> </root> ")
            .AddAttachments(Array.Empty<Attachment>())
            .Build();
        sender.SendAsync(outgoing).Wait();
    }

    [Test]
    public void FluentSender_ShouldNotThrowAnError_MockingServicesWithoutData() {
        var sender = ClientFactory.GetSenderClient(Container.Create());
        var outgoing = SendableSubmission.Builder()
            .SetDestination(Guid.NewGuid())
            .SetServiceType(serviceIdentifier, "")
            .SetJsonData(@"{""data"":""value""}")
            .AddAttachments(Array.Empty<Attachment>())
            .Build();

        sender.SendAsync(outgoing).Wait();
    }

    [Test]
    public void VerifyMetadata_ValidData_Fine() {
        // Arrange
        var submission = new Submission() {
            Data = @"{""data"":""value""}",
            ServiceType = new ServiceType(serviceIdentifier, ""),
            DataMimeType = MediaTypeNames.Application.Json,
        };

        // Act
        var metadata = Sender.CreateMetadata(submission);

        // Assert
        var valid = JsonHelper.VerifyMetadata(metadata, null, logger).Result;

        if (!valid)
            logger?.LogWarning(metadata);

        valid.Valid.Should().BeTrue();
    }

    [Test]
    public void VerifyMetadata_MissingLeikaKey_ThrowsAnError() {
        // Arrange
        var submission = new Submission() {
            Data = @"{""data"":""value""}"
        };

        // Act
        var metadata = Sender.CreateMetadata(submission);

        // Assert
        var valid = JsonHelper.VerifyMetadata(metadata, null, logger).Result;
        valid.Valid.Should().BeFalse();
    }
}