using e_suite.API.Common.exceptions;
using e_suite.API.Common.models;
using e_suite.Database.Audit;
using e_suite.Service.SigmaImporter.Repository;
using eSuite.Core.Miscellaneous;
using Moq;
using NUnit.Framework;
using SigmaImporter.UnitTests.Helpers;

namespace SigmaImporter.UnitTests.GmgProfileImporter;

[TestFixture]
public class ImportGmgProfilesUnitTestsWithMySql : GmgProfileImporterTestBaseWithMySql
{
    [SetUp]
    public override async Task Setup()
    {
        await base.Setup();
    }

    [Test]
    public async Task WhenGmgProfilesNotPresent_CreatesNewGmgProfile()
    {
        //Arrange
        var getGmgProfileCounter = 0;

        var gmgGlossaryItem = new GlossaryItem
        {
            Parent = new GlossaryItem
            {
                Guid = new Guid("FA6566F8-B4B0-48C5-9985-336C9284796E"),
                Name = "System"
            }, 
            Name = "GMG Profile",
            Guid = new Guid("BBA078CF-8326-40B8-92EC-ECD9A2017702")
        };

        GlossariesManagerMock.Setup(x =>
                x.GetGlossaryItem(It.IsAny<AuditUserDetails>(), It.IsAny<GeneralIdRef>(),
                    It.IsAny<CancellationToken>()))
            .Returns<AuditUserDetails, GeneralIdRef, CancellationToken>(
                (auditUserDetails, generalIdRef, cancellationToken) =>
                {
                    if (generalIdRef?.Guid == GmgProfileGuid)
                    {
                        getGmgProfileCounter++;
                        if (getGmgProfileCounter == 1)
                            throw new NotFoundException("Unable to find glossary");
                        else
                        {
                            return Task.FromResult(gmgGlossaryItem)!;
                        }

                    }
                    
                    throw new NotFoundException("Unable to find glossary"); 
                });

        //Act
        await GmgProfileImporter.DoGmgProfileImport(AuditUserDetails);

        //Assert
        GlossariesManagerMock.Verify(x => x.GetGlossaryItem(It.IsAny<AuditUserDetails>(), It.IsAny<GeneralIdRef>(), It.IsAny<CancellationToken>()), Times.Exactly(2));
        GlossariesManagerMock.Verify( x => x.AddGlossaryItem(It.IsAny<AuditUserDetails>(), It.IsAny<NewGlossaryItem>(), It.IsAny<CancellationToken>()), Times.Once);
    }

    [Test]
    public async Task WhenGmgProfilesIsPresent_DoesNotCreateNewItem()
    {
        //Arrange
        var getGmgProfileCounter = 0;

        var gmgGlossaryItem = new GlossaryItem
        {
            Parent = new GlossaryItem
            {
                Guid = new Guid("FA6566F8-B4B0-48C5-9985-336C9284796E"),
                Name = "System"
            },
            Name = "GMG Profile",
            Guid = new Guid("BBA078CF-8326-40B8-92EC-ECD9A2017702")
        };

        GlossariesManagerMock.Setup(x =>
                x.GetGlossaryItem(It.IsAny<AuditUserDetails>(), It.IsAny<GeneralIdRef>(),
                    It.IsAny<CancellationToken>()))
            .Returns<AuditUserDetails, GeneralIdRef, CancellationToken>(
                (auditUserDetails, generalIdRef, cancellationToken) =>
                {
                    if (generalIdRef?.Guid == GmgProfileGuid)
                    {
                        getGmgProfileCounter++;
                        if (getGmgProfileCounter == 1)
                            return Task.FromResult(gmgGlossaryItem)!;

                    }

                    throw new NotFoundException("Unable to find glossary");
                });

        //Act
        await GmgProfileImporter.DoGmgProfileImport(AuditUserDetails);

        //Assert
        GlossariesManagerMock.Verify(x => x.GetGlossaryItem(It.IsAny<AuditUserDetails>(), It.IsAny<GeneralIdRef>(), It.IsAny<CancellationToken>()), Times.Once);
        GlossariesManagerMock.Verify(x => x.AddGlossaryItem(It.IsAny<AuditUserDetails>(), It.IsAny<NewGlossaryItem>(), It.IsAny<CancellationToken>()), Times.Never);
    }

    [Test]
    public async Task NoGMGProfilesReturned_AddGlossaryItemsCalledOnce()
    {
        //Arrange
        var getGmgProfileCounter = 0;

        var gmgGlossaryItem = new GlossaryItem
        {
            Parent = new GlossaryItem
            {
                Guid = new Guid("FA6566F8-B4B0-48C5-9985-336C9284796E"),
                Name = "System"
            },
            Name = "GMG Profile",
            Guid = new Guid("BBA078CF-8326-40B8-92EC-ECD9A2017702")
        };

        GlossariesManagerMock.Setup(x =>
                x.GetGlossaryItem(It.IsAny<AuditUserDetails>(), It.IsAny<GeneralIdRef>(),
                    It.IsAny<CancellationToken>()))
            .Returns<AuditUserDetails, GeneralIdRef, CancellationToken>(
                (auditUserDetails, generalIdRef, cancellationToken) =>
                {
                    if (generalIdRef?.Guid == GmgProfileGuid)
                    {
                        getGmgProfileCounter++;
                        if (getGmgProfileCounter == 1)
                            return Task.FromResult(gmgGlossaryItem)!;

                    }

                    throw new NotFoundException("Unable to find glossary");
                });

        List<GmgProfile> gmgProfiles = [];

        SigmaFileBrowserRepositoryMock.Setup(x => x.GetActiveGmgProfiles()).ReturnsAsync( gmgProfiles );

        var newGlossaryItemCount = 0;

        GlossariesManagerMock
            .Setup(x => x.AddGlossaryItems(It.IsAny<AuditUserDetails>(), It.IsAny<IEnumerable<NewGlossaryItem>>(),
                It.IsAny<CancellationToken>()))
            .Returns<AuditUserDetails, IEnumerable<NewGlossaryItem>, CancellationToken>(
                ((auditUserDetails, newGlossaryItem, cancellationToken) =>
                {
                    newGlossaryItemCount = newGlossaryItem.Count();
                    return Task.FromResult(gmgProfiles);
                } )
                );

        //Act
        await GmgProfileImporter.DoGmgProfileImport(AuditUserDetails);

        //Assert
        GlossariesManagerMock.Verify(x => x.AddGlossaryItems(It.IsAny<AuditUserDetails>(), It.IsAny<IEnumerable<NewGlossaryItem>>(), It.IsAny<CancellationToken>()), Times.Once);
        Assert.That(newGlossaryItemCount, Is.EqualTo(0));
    }

    [Test]
    public async Task OneGMGProfilesReturned_AddGlossaryItemsCalledWithOneItem()
    {
        //Arrange
        var getGmgProfileCounter = 0;

        var gmgGlossaryItem = new GlossaryItem
        {
            Parent = new GlossaryItem
            {
                Guid = new Guid("FA6566F8-B4B0-48C5-9985-336C9284796E"),
                Name = "System"
            },
            Name = "GMG Profile",
            Guid = new Guid("BBA078CF-8326-40B8-92EC-ECD9A2017702")
        };

        GlossariesManagerMock.Setup(x =>
                x.GetGlossaryItem(It.IsAny<AuditUserDetails>(), It.IsAny<GeneralIdRef>(),
                    It.IsAny<CancellationToken>()))
            .Returns<AuditUserDetails, GeneralIdRef, CancellationToken>(
                (auditUserDetails, generalIdRef, cancellationToken) =>
                {
                    if (generalIdRef?.Guid == GmgProfileGuid)
                    {
                        getGmgProfileCounter++;
                        if (getGmgProfileCounter == 1)
                            return Task.FromResult(gmgGlossaryItem)!;

                    }

                    throw new NotFoundException("Unable to find glossary");
                });

        List<GmgProfile> gmgProfiles =
        [
            new() { Name = "Test Profile", Number = 1 }
        ];

        SigmaFileBrowserRepositoryMock.Setup(x => x.GetActiveGmgProfiles()).ReturnsAsync(gmgProfiles);

        var newGlossaryItemCount = 0;

        GlossariesManagerMock
            .Setup(x => x.AddGlossaryItems(It.IsAny<AuditUserDetails>(), It.IsAny<IEnumerable<NewGlossaryItem>>(),
                It.IsAny<CancellationToken>()))
            .Returns<AuditUserDetails, IEnumerable<NewGlossaryItem>, CancellationToken>(
                ((auditUserDetails, newGlossaryItem, cancellationToken) =>
                {
                    newGlossaryItemCount = newGlossaryItem.Count();
                    return Task.FromResult(gmgProfiles);
                })
                );

        //Act
        await GmgProfileImporter.DoGmgProfileImport(AuditUserDetails);

        //Assert
        GlossariesManagerMock.Verify(x => x.AddGlossaryItems(It.IsAny<AuditUserDetails>(), It.IsAny<IEnumerable<NewGlossaryItem>>(), It.IsAny<CancellationToken>()), Times.Once);
        Assert.That(newGlossaryItemCount, Is.EqualTo(1));
    }
}