using FluentAssertions;
using Nop.Core.Domain.Affiliates;
using Nop.Services.Affiliates;
using Nop.Services.Common;
using NUnit.Framework;

namespace Nop.Tests.Nop.Services.Tests.Affiliates;

[TestFixture]
public class AffiliateServiceTests : ServiceTest
{
    private IAffiliateService _affiliateService;
    private IAddressService _addressService;
    private Affiliate _activeAffiliate1;
    private Affiliate _activeAffiliate2;
    private Affiliate _notActiveAffiliate;
    private Affiliate _activeDeletedAffiliate;
    private Affiliate _notActiveDeletedAffiliate;

    [OneTimeSetUp]
    public async Task SetUp()
    {
        _affiliateService = GetService<IAffiliateService>();
        _addressService = GetService<IAddressService>();
        _activeAffiliate1 = new Affiliate
        {
            Active = true,
            AddressId = 1,
            AdminComment = "Test admin comment",
            FriendlyUrlName = "TestActiveAffiliate1"
        };
        _activeAffiliate2 = new Affiliate
        {
            Active = true,
            AddressId = 1,
            AdminComment = "Test admin comment",
            FriendlyUrlName = "TestActiveAffiliate2"
        };
        _notActiveAffiliate = new Affiliate
        {
            Active = false,
            AddressId = 1,
            AdminComment = "Test admin comment",
            FriendlyUrlName = "TestNotActiveAffiliate"
        };
        _activeDeletedAffiliate = new Affiliate
        {
            Active = true,
            AddressId = 1,
            AdminComment = "Test admin comment",
            FriendlyUrlName = "TestActiveDeletedAffiliate",
            Deleted = true
        };
        _notActiveDeletedAffiliate = new Affiliate
        {
            Active = false,
            AddressId = 1,
            AdminComment = "Test admin comment",
            FriendlyUrlName = "TestNotActiveDeletedAffiliate",
            Deleted = true
        };

        await _affiliateService.InsertAffiliateAsync(_activeAffiliate1);
        await _affiliateService.InsertAffiliateAsync(_notActiveAffiliate);
        await _affiliateService.InsertAffiliateAsync(_activeDeletedAffiliate);
        await _affiliateService.InsertAffiliateAsync(_notActiveDeletedAffiliate);
    }

    [OneTimeTearDown]
    public async Task TearDown()
    {
        await _affiliateService.DeleteAffiliateAsync(_activeAffiliate1);
        await _affiliateService.DeleteAffiliateAsync(_notActiveAffiliate);
        await _affiliateService.DeleteAffiliateAsync(_activeDeletedAffiliate);
        await _affiliateService.DeleteAffiliateAsync(_notActiveDeletedAffiliate);
    }

    [Test]
    public async Task CanGetAffiliateByFriendlyUrlName()
    {
        var affiliate = await _affiliateService.GetAffiliateByFriendlyUrlNameAsync(_activeAffiliate1.FriendlyUrlName);

        affiliate.Should().NotBeNull();
        affiliate.Active.Should().BeTrue();
        affiliate.FriendlyUrlName.Should().Be(_activeAffiliate1.FriendlyUrlName);
    }

    [Test]
    public async Task CanGetAllAffiliates()
    {
        var affiliates = await _affiliateService.GetAllAffiliatesAsync();
        affiliates.TotalCount.Should().Be(2);
        affiliates = await _affiliateService.GetAllAffiliatesAsync(showHidden: true);
        affiliates.TotalCount.Should().Be(3);
        affiliates = await _affiliateService.GetAllAffiliatesAsync(_activeDeletedAffiliate.FriendlyUrlName);
        affiliates.TotalCount.Should().Be(0);
        affiliates = await _affiliateService.GetAllAffiliatesAsync(_activeAffiliate1.FriendlyUrlName, showHidden: true);
        affiliates.TotalCount.Should().Be(1);

        var address = await _addressService.GetAddressByIdAsync(1);

        affiliates = await _affiliateService.GetAllAffiliatesAsync(firstName: address.FirstName, showHidden: true);
        affiliates.TotalCount.Should().Be(3);
        affiliates = await _affiliateService.GetAllAffiliatesAsync(firstName: address.FirstName);
        affiliates.TotalCount.Should().Be(2);
        affiliates = await _affiliateService.GetAllAffiliatesAsync(loadOnlyWithOrders: true, showHidden: true);
        affiliates.TotalCount.Should().Be(0);
    }

    [Test]
    public async Task CanGetAffiliateFullName()
    {
        var fullName = await _affiliateService.GetAffiliateFullNameAsync(_activeAffiliate1);
        var address = await _addressService.GetAddressByIdAsync(1);

        fullName.Should().Be($"{address.FirstName} {address.LastName}");
    }

    [Test]
    public async Task CanGenerateUrl()
    {
        var url = await _affiliateService.GenerateUrlAsync(_activeAffiliate1);
        url.Should().Be($"http://{NopTestsDefaults.HostIpAddress}/?{NopAffiliateDefaults.AffiliateQueryParameter}={_activeAffiliate1.FriendlyUrlName}");

        _notActiveDeletedAffiliate.FriendlyUrlName = string.Empty;
        url = await _affiliateService.GenerateUrlAsync(_notActiveDeletedAffiliate);
        url.Should().Be($"http://{NopTestsDefaults.HostIpAddress}/?{NopAffiliateDefaults.AffiliateIdQueryParameter}={_notActiveDeletedAffiliate.Id}");
    }

    [Test]
    public async Task CanValidateFriendlyUrlName()
    {
        var friendlyUrlName = await _affiliateService.ValidateFriendlyUrlNameAsync(_activeAffiliate1, _activeAffiliate2.FriendlyUrlName);
        friendlyUrlName.Should().Be(_activeAffiliate2.FriendlyUrlName.ToLowerInvariant());

        friendlyUrlName = await _affiliateService.ValidateFriendlyUrlNameAsync(_activeAffiliate1, "not/valid/url*name");
        friendlyUrlName.Should().Be("notvalidurlname");
    }
}