{%- set messagegroups = root.messagegroups -%}
{%- set function_name = project_name | pascal | strip_dots -%}
{%- set function_class_name = (project_name | pascal)+"."+((project_name | pascal | strip_namespace)+"Function") -%}
{%- import "cloudevents.jinja.include" as cloudEvents -%}
{%- import "eventhubs.jinja.include" as eventhubs -%}
{%- import "util.jinja.include" as util -%}
{{ util.CommonFileHeader() }}

#pragma warning disable CS8602 // Dereference of a possibly null reference.
#pragma warning disable CS8618 // Non-nullable field must contain a non-null value when exiting constructor. Consider declaring as nullable.

using System;
using System.Collections.Generic;
using System.Threading.Tasks;
using Azure.Messaging.EventHubs;
using Microsoft.Extensions.Logging;
using Moq;
using NUnit.Framework;

namespace {{ project_name | pascal }}.Tests
{
    [TestFixture]
    public class {{ function_class_name | strip_dots }}Tests
    {
        {%- set function_class_field = "_"+(function_class_name | pascal | strip_dots | camel) %}
        {%- set function_class_ref = "global::"+ function_class_name %}
        private {{ function_class_ref }} {{ function_class_field }};
        private Mock<ILoggerFactory> loggerFactoryMock;
        private Mock<ILogger<{{ function_class_ref }}>> loggerMock;
        {{ cloudEvents.DeclareDispatchObjectMocks( project_name, messagegroups ) | indent(8) }}

        [SetUp]
        public void Setup()
        {
            loggerFactoryMock = new Mock<ILoggerFactory>();
            loggerMock = new Mock<ILogger<{{ function_class_ref }}>>();
            loggerFactoryMock.Setup(x => x.CreateLogger(typeof({{ function_class_ref }}).FullName!)).Returns(loggerMock.Object);
            {{ cloudEvents.SetupDispatchObjectMocks( project_name, messagegroups ) | indent(12) }}
            

            {{ function_class_field }} = new {{ function_class_ref }}(
                loggerFactoryMock.Object,
                {%- for messagegroupid, messagegroup in messagegroups.items() if (messagegroup | exists("envelope","CloudEvents/1.0")) -%}
                _{{ messagegroupid | strip_namespace | camel }}DispatcherMock.Object{% if not loop.last %},
                {% endif -%}
                {%- endfor -%});
        }

        [Test]
        public async Task Run_WithNoEvents_ShouldNotInvokeAnyDispatcherMethods()
        {
            // Arrange
            var events = new EventData[0];

            // Act
            await {{ function_class_field }}.Run(events, loggerMock.Object);

            // Assert
            {%- for messagegroupid, messagegroup in messagegroups.items() if (messagegroup | exists("envelope","CloudEvents/1.0")) -%}
            {%- for messageid, message in messagegroup.messages.items() -%}
            {%- if message.envelope.startswith("CloudEvents") -%}  
            {%- set messagename = messageid | pascal %}
            _{{ messagegroupid | strip_namespace | camel }}DispatcherMock.Verify(
                x => x.On{{ messageid | strip_namespace | pascal }}Async(It.IsAny<CloudNative.CloudEvents.CloudEvent>(), It.IsAny<{{ util.body_type(data_project_name, root, message) }}>()),
                Times.Never
            );
            {%- endif -%}
            {%- endfor -%}
            {%- endfor -%}
        }

        {%- for messagegroupid, messagegroup in messagegroups.items() if (messagegroup | exists("envelope","CloudEvents/1.0")) -%}
        {%- for messageid, message in messagegroup.messages.items() -%}
        {%- if message.envelope.startswith("CloudEvents") -%}     
        {%- set messagename = messageid | pascal %}
        {%- set message_body_type = util.body_type(data_project_name, root, message) -%}
        [Test]
        public async Task Run_With{{ messageid | strip_namespace | pascal }}_ShouldInvoke{{ messagegroupid | strip_namespace | pascal }}DispatcherOn{{ messageid | strip_namespace | pascal }}Async()
        {
            {%- if message_body_type != "byte[]" %}
            var eventDataTest = new {{ message_body_type }}Tests();
            var eventDataInstance = eventDataTest.CreateInstance();
            var eventData = new EventData(new BinaryData(eventDataInstance.ToByteArray("application/json")));
            {%- else %}
            var eventData = new EventData(new BinaryData(""));
            {%- endif %}
            eventData.Properties.Add("cloudEvents:specversion", "1.0");
            eventData.Properties.Add("cloudEvents_type", "{{ messageid }}");
            eventData.ContentType = "application/json";
            var events = new[] { eventData };
            await {{ function_class_field }}.Run(events, loggerMock.Object);
            _{{ messagegroupid | strip_namespace | camel }}DispatcherMock.Verify(
                x => x.On{{ messageid | strip_namespace | pascal }}Async(It.IsAny<CloudNative.CloudEvents.CloudEvent>(), It.IsAny<{{ message_body_type if message_body_type != "byte[]" else "BinaryData" }}>()),
                Times.Once
            );
        }
        {%- endif -%}
        {%- endfor -%}        
        {%- endfor -%}
    }
}
