using System;
using System.Collections.Generic;
using System.IO;
using Autofac;
using FluentAssertions;
using Microsoft.AspNetCore.Http;
using Microsoft.Extensions.Primitives;
using MockContainer;
using Moq;
using NUnit.Framework;

namespace IntegrationTests;

[TestFixture]
public class CallbackTest {
    [SetUp]
    public void Setup() {
        // POST /callbacks/fit-connect
        // callback-authentication: 798cd0edb70c08e5b32aa8a18cbbc8ff6b3078c51af6d011ff4e32e470c746234fc4314821fe5185264b029e962bd37de33f3b9fc5f1a93c40ce6672845e90df
        // callback-timestamp: 1672527599
        //
        // {"type":"https://schema.fitko.de/fit-connect/submission-api/callbacks/new-submissions","submissionIds":["f39ab143-d91a-474a-b69f-b00f1a1873c2"]}

        // HttpRequest request = null!;
        // request.Headers
        // request.Headers.Add("callback-authentication",
        //     "798cd0edb70c08e5b32aa8a18cbbc8ff6b3078c51af6d011ff4e32e470c746234fc4314821fe5185264b029e962bd37de33f3b9fc5f1a93c40ce6672845e90df");
        // request.Headers.Add("callback-timestamp", DateTime.Now.ToEpochTime().ToString());
        // request.Method = "POST";
        // request.ContentType = "application/json";

        var memoryStream = new MemoryStream();
        var streamWriter = new StreamWriter(memoryStream);

        streamWriter.WriteLine(
            "{\"type\":\"https://schema.fitko.de/fit-connect/submission-api/callbacks/new-submissions\",\"submissionIds\":[\"f39ab143-d91a-474a-b69f-b00f1a1873c2\"]}");
        streamWriter.Flush();
        memoryStream.Position = 0;

        // Request = new DefaultHttpRequest(new DefaultHttpContext()) {
        //     Body = new StreamBody(memoryStream)
        // };

        var headers = new HeaderDictionary(new Dictionary<string, StringValues> {
            { "callback-timestamp", "1672527599" }, {
                "callback-authentication",
                "798cd0edb70c08e5b32aa8a18cbbc8ff6b3078c51af6d011ff4e32e470c746234fc4314821fe5185264b029e962bd37de33f3b9fc5f1a93c40ce6672845e90df"
            }
        });


        var mock =
            new Mock<HttpRequest>();
        mock.Setup(w => w.ContentType).Returns("application/json");
        mock.Setup(w => w.Headers).Returns(headers);
        mock.Setup(w => w.Method).Returns("POST");
        mock.Setup(w => w.Body).Returns(memoryStream);

        Request = mock.Object;

        _callbackSecret = Container.Create().Resolve<MockSettings>().CallbackSecret;
    }

    private HttpRequest Request = null!;
    private string _callbackSecret = "";

    [Test]
    public void ValidRequest_WithSingeValues() {
        // Arrange

        //Act
        var authentication = FitConnect.Subscriber.VerifyCallback(_callbackSecret, 1672527599,
            "{\"type\":\"https://schema.fitko.de/fit-connect/submission-api/callbacks/new-submissions\",\"submissionIds\":[\"f39ab143-d91a-474a-b69f-b00f1a1873c2\"]}"
        );

        // Assert
        authentication.Should()
            .Be(
                "798cd0edb70c08e5b32aa8a18cbbc8ff6b3078c51af6d011ff4e32e470c746234fc4314821fe5185264b029e962bd37de33f3b9fc5f1a93c40ce6672845e90df");
    }

    [Test]
    public void ValidRequest() {
        // Assert
        FitConnect.Subscriber.VerifyCallback(_callbackSecret, Request).Should().Be(true);
    }

    [Test]
    public void RequestAge_Fails() {
        // Arrange
        Request.Headers["callback-timestamp"] = "1641066653";

        // Atc
        // Assert
        Assert.Throws<ArgumentException>(() => {
                FitConnect.Subscriber.VerifyCallback(_callbackSecret, Request);
            })!
            .Message.Should().Be("Request is too old");
    }

    [Test]
    public void RequestAuthentication_Fails() {
        // Arrange
        Request.Headers["callback-authentication"] =
            "898cd0edb70c08e5b32aa8a18cbbc8ff6b3078c51af6d011ff4e32e470c746234fc4314821fe5185264b029e962bd37de33f3b9fc5f1a93c40ce6672845e90df";

        // Atc
        // Assert
        Assert.Throws<ArgumentException>(() => {
                FitConnect.Subscriber.VerifyCallback(_callbackSecret, Request);
            })!
            .Message.Should().Be("Request is not authentic");
    }
}