using e_suite.Database.Core.Extensions;
using e_suite.Database.Core.Extensions.Exceptions;
using e_suite.Database.Core.UnitTests.Models;
using eSuite.Core.Miscellaneous;
using MockQueryable;
using NUnit.Framework;


namespace e_suite.Database.Core.UnitTests;

[TestFixture]
public class QueryableExtensionsIQueryableUnitTests
{

    [Test]
    public async Task FindByGeneralIdRefAsync_IdNotFound_ReturnsNull()
    {
        //Arrange
        var data = new List<TestCargo>
        {
            new()
            {
                Id = 1,
                Guid = new Guid("{F81F58DB-ACB0-404E-B5DB-C480DE3F2016}"),
                Name = "Test Item"
            }
        };

        var mock = data.BuildMock();

        //Act
        var generalIdRef = new GeneralIdRef
        {
            Id = 100
        };

        var result = await mock.AsQueryable().FindByGeneralIdRefAsync(generalIdRef, default);

        //Assert
        Assert.That(result, Is.Null);
    }

    [Test]
    public async Task FindByGeneralIdRefAsync_IdFound_ReturnsExpectedValue()
    {
        //Arrange
        var keyId = 1;
        var keyGuid = new Guid("{F81F58DB-ACB0-404E-B5DB-C480DE3F2016}");

        var testIrem = new TestCargo()
        {
            Id = keyId,
            Guid = keyGuid,
            Name = "Test Item"
        };

        var items = new List<TestCargo>
        {
            testIrem
        };

        var mock = items.BuildMock();

        //Act
        var generalIdRef = new GeneralIdRef
        {
            Id = keyId
        };

        var result = await mock.FindByGeneralIdRefAsync(generalIdRef, default);

        //Assert
        Assert.That(result, Is.EqualTo(testIrem));
    }

    [Test]
    public async Task FindByGeneralIdRefAsync_GuidFound_ReturnsExpectedValue()
    {
        //Arrange
        var keyId = 1;
        var keyGuid = new Guid("{F81F58DB-ACB0-404E-B5DB-C480DE3F2016}");

        var testIrem = new TestCargo()
        {
            Id = keyId,
            Guid = keyGuid,
            Name = "Test Item"
        };

        var items = new List<TestCargo>
        {
            testIrem
        };

        var mock = items.BuildMock();

        //Act
        var generalIdRef = new GeneralIdRef
        {
            Guid = keyGuid
        };

        var result = await mock.FindByGeneralIdRefAsync(generalIdRef, default);

        //Assert
        Assert.That(result, Is.EqualTo(testIrem));
    }

    [Test]
    public async Task FindByGeneralIdRefAsync_IdAndGuid_ReturnsExpectedValue()
    {
        //Arrange
        var keyId = 1;
        var keyGuid = new Guid("{F81F58DB-ACB0-404E-B5DB-C480DE3F2016}");

        var testIrem = new TestCargo()
        {
            Id = keyId,
            Guid = keyGuid,
            Name = "Test Item"
        };

        var items = new List<TestCargo>
        {
            testIrem
        };

        var mock = items.BuildMock();

        //Act
        var generalIdRef = new GeneralIdRef
        {
            Id = keyId,
            Guid = keyGuid
        };

        var result = await mock.FindByGeneralIdRefAsync(generalIdRef, default);

        //Assert
        Assert.That(result, Is.EqualTo(testIrem));
    }

    [Test]
    public async Task FindByGeneralIdRefAsync_WrongIdAndCorrectGuid_ReturnsNullWhenIdDoesNotExist()
    {
        //Arrange
        var keyId = 1;
        var keyGuid = new Guid("{F81F58DB-ACB0-404E-B5DB-C480DE3F2016}");

        var testIrem = new TestCargo()
        {
            Id = keyId,
            Guid = keyGuid,
            Name = "Test Item"
        };

        var items = new List<TestCargo>
        {
            testIrem
        };

        var mock = items.BuildMock();

        //Act
        var generalIdRef = new GeneralIdRef
        {
            Id = keyId + 1,
            Guid = keyGuid
        };

        var result = await mock.FindByGeneralIdRefAsync(generalIdRef, default);

        //Assert
        Assert.That(result, Is.Null);
    }

    [Test]
    public void FindByGeneralIdRefAsync_CorrectIfAndWrongGuid_ThrowsExpectedException()
    {
        //Arrange
        var keyId = 1;
        var keyGuid = new Guid("{F81F58DB-ACB0-404E-B5DB-C480DE3F2016}");
        var wrongGuid = new Guid("{C3BC5BAC-39F9-40B8-A191-0F25CD366FE4}");

        var testItem = new TestCargo
        {
            Id = keyId,
            Guid = keyGuid,
            Name = "Test Item"
        };

        var items = new List<TestCargo>
        {
            testItem
        };

        var mock = items.BuildMock();

        //Act and Assert
        var generalIdRef = new GeneralIdRef
        {
            Id = keyId,
            Guid = wrongGuid
        };

        var result = Assert.ThrowsAsync<GuidMismatchException>(async () => { await mock.FindByGeneralIdRefAsync(generalIdRef, default); });

        Assert.That(result?.Message, Is.EqualTo($"The retrieved guid {keyGuid} does not match the expected guid {wrongGuid}"));
    }

    [Test]
    public async Task FindByIdAsync_IdNotFound_ReturnsNull()
    {
        //Arrange
        var items = new List<TestCargo>
        {
            new()
            {
                Id = 1,
                Guid = new Guid("{F81F58DB-ACB0-404E-B5DB-C480DE3F2016}"),
                Name = "Test Item"
            }
        };

        var mock = items.BuildMock();

        //Act
        var result = await mock.FindByIdAsync(100, default);

        //Assert
        Assert.That(result, Is.Null);
    }

    [Test]
    public async Task FindByIdAsync_IdFound_ReturnsExpectedValue()
    {
        //Arrange
        var keyId = 1;
        var keyGuid = new Guid("{F81F58DB-ACB0-404E-B5DB-C480DE3F2016}");

        var testIrem = new TestCargo()
        {
            Id = keyId,
            Guid = keyGuid,
            Name = "Test Item"
        };

        var items = new List<TestCargo>
        {
            testIrem
        };

        var mock = items.BuildMock();

        //Act
        var result = await mock.FindByIdAsync(keyId, default);

        //Assert
        Assert.That(result, Is.EqualTo(testIrem));
    }
}