using FluentAssertions;
using Nop.Core;
using Nop.Core.Domain;
using Nop.Core.Domain.Common;
using Nop.Core.Domain.Customers;
using Nop.Core.Domain.Forums;
using Nop.Core.Domain.Localization;
using Nop.Core.Domain.News;
using Nop.Core.Domain.Vendors;
using Nop.Services.Configuration;
using Nop.Services.Vendors;
using Nop.Web.Factories;
using Nop.Web.Models.Common;
using NUnit.Framework;

namespace Nop.Tests.Nop.Web.Tests.Public.Factories;

[TestFixture]
public class CommonModelFactoryTests : BaseNopTest
{
    private ICommonModelFactory _commonModelFactory;
    private LocalizationSettings _localizationSettings;
    private IWorkContext _workContext;
    private CustomerSettings _customerSettings;
    private ForumSettings _forumSettings;
    private StoreInformationSettings _storeInformationSettings;
    private NewsSettings _newsSettings;
    private CommonSettings _commonSettings;
    private Vendor _vendor;
    private ISettingService _settingsService;

    [OneTimeSetUp]
    public async Task SetUp()
    {
        _settingsService = GetService<ISettingService>();
        _localizationSettings = GetService<LocalizationSettings>();
        _forumSettings = GetService<ForumSettings>();

        _localizationSettings.SeoFriendlyUrlsForLanguagesEnabled = true;
        await _settingsService.SaveSettingAsync(_localizationSettings);
        _forumSettings.AllowPrivateMessages = true;
        await _settingsService.SaveSettingAsync(_forumSettings);

        _commonModelFactory = GetService<ICommonModelFactory>();

        _workContext = GetService<IWorkContext>();
        _customerSettings = GetService<CustomerSettings>();

        _storeInformationSettings = GetService<StoreInformationSettings>();
        _newsSettings = GetService<NewsSettings>();
        _commonSettings = GetService<CommonSettings>();

        _vendor = await GetService<IVendorService>().GetVendorByIdAsync(1);
    }

    [OneTimeTearDown]
    public async Task TearDown()
    {
        _localizationSettings.SeoFriendlyUrlsForLanguagesEnabled = false;
        await _settingsService.SaveSettingAsync(_localizationSettings);
        _forumSettings.AllowPrivateMessages = false;
        await _settingsService.SaveSettingAsync(_forumSettings);
    }

    [Test]
    public async Task CanPrepareLogoModel()
    {
        var model = await _commonModelFactory.PrepareLogoModelAsync();
        model.StoreName.Should().NotBeNullOrEmpty();
        model.StoreName.Should().Be("Your store name");
        model.LogoPath.Should().NotBeNullOrEmpty();
        model.LogoPath.Should()
            .Be($"http://{NopTestsDefaults.HostIpAddress}/Themes/DefaultClean/Content/images/logo.png");
    }

    [Test]
    public async Task CanPrepareLanguageSelectorModel()
    {
        var model = await _commonModelFactory.PrepareLanguageSelectorModelAsync();

        model.CurrentLanguageId.Should().Be(1);
        model.UseImages.Should().Be(_localizationSettings.UseImagesForLanguageSelection);

        model.AvailableLanguages.Should().NotBeNullOrEmpty();
        var lang = model.AvailableLanguages.FirstOrDefault();
        lang.Should().NotBeNull();
        lang?.Name.Should().Be("English");
        lang?.FlagImageFileName.Should().Be("us.png");
    }

    [Test]
    public async Task CanPrepareCurrencySelectorModel()
    {
        var model = await _commonModelFactory.PrepareCurrencySelectorModelAsync();
        model.CurrentCurrencyId.Should().Be(1);
        model.AvailableCurrencies.Should().NotBeNullOrEmpty();
        model.AvailableCurrencies.Count.Should().Be(1);
    }

    [Test]
    public async Task CanPrepareTaxTypeSelectorModel()
    {
        var model = await _commonModelFactory.PrepareTaxTypeSelectorModelAsync();
        model.CurrentTaxType.Should().Be(await _workContext.GetTaxDisplayTypeAsync());
    }

    [Test]
    public async Task CanPrepareHeaderLinksModel()
    {
        var model = await _commonModelFactory.PrepareHeaderLinksModelAsync();

        model.RegistrationType.Should().Be(_customerSettings.UserRegistrationType);
        model.IsAuthenticated.Should().BeTrue();
        model.CustomerName.Should().Be("John");
        model.ShoppingCartEnabled.Should().BeTrue();
        model.WishlistEnabled.Should().BeTrue();
        model.AllowPrivateMessages.Should().Be(_forumSettings.AllowPrivateMessages);
        model.UnreadPrivateMessages.Should().BeEmpty();
        model.AlertMessage.Should().BeEmpty();
        model.ShoppingCartItems.Should().Be(0);
        model.WishlistItems.Should().Be(0);
    }

    [Test]
    public async Task CanPrepareAdminHeaderLinksModel()
    {
        var model = await _commonModelFactory.PrepareAdminHeaderLinksModelAsync();
        model.ImpersonatedCustomerName.Should().Be("John");
        model.IsCustomerImpersonated.Should().BeFalse();
        model.DisplayAdminLink.Should().BeTrue();
        model.EditPageUrl.Should().BeNull();
    }

    [Test]
    public async Task CanPrepareSocialModel()
    {
        var model = await _commonModelFactory.PrepareSocialModelAsync();

        model.FacebookLink.Should().Be(_storeInformationSettings.FacebookLink);
        model.TwitterLink.Should().Be(_storeInformationSettings.TwitterLink);
        model.YoutubeLink.Should().Be(_storeInformationSettings.YoutubeLink);
        model.InstagramLink.Should().Be(_storeInformationSettings.InstagramLink);
        model.WorkingLanguageId.Should().Be(1);
        model.NewsEnabled.Should().Be(_newsSettings.Enabled);
    }

    [Test]
    public async Task CanPrepareFooterModel()
    {
        var model = await _commonModelFactory.PrepareFooterModelAsync();

        model.StoreName.Should().Be("Your store name");
        model.HidePoweredByNopCommerce.Should().Be(_storeInformationSettings.HidePoweredByNopCommerce);
    }

    [Test]
    public async Task CanPrepareContactUsModel()
    {
        var model = new ContactUsModel();
        model = await _commonModelFactory.PrepareContactUsModelAsync(model, true);

        model.SubjectEnabled = _commonSettings.SubjectFieldOnContactUsForm;
        model.DisplayCaptcha.Should().BeFalse();
        model.Email.Should().BeNullOrEmpty();
        model.FullName.Should().BeNullOrEmpty();

        model = await _commonModelFactory.PrepareContactUsModelAsync(model, false);
        model.SubjectEnabled = _commonSettings.SubjectFieldOnContactUsForm;
        model.DisplayCaptcha.Should().BeFalse();
        model.Email.Should().Be(NopTestsDefaults.AdminEmail);
        model.FullName.Should().Be("John Smith");
    }

    [Test]
    public void PrepareContactUsModelShouldRaiseExceptionIfModelIsNull()
    {
        Assert.Throws<AggregateException>(() =>
            _commonModelFactory.PrepareContactUsModelAsync(null, true).Wait());

        Assert.Throws<AggregateException>(() =>
            _commonModelFactory.PrepareContactUsModelAsync(null, false).Wait());
    }

    [Test]
    public async Task CanPrepareContactVendorModel()
    {
        var model = new ContactVendorModel();
        model = await _commonModelFactory.PrepareContactVendorModelAsync(model, _vendor, true);
        model.Email.Should().BeNullOrEmpty();
        model.FullName.Should().BeNullOrEmpty();

        model.SubjectEnabled = _commonSettings.SubjectFieldOnContactUsForm;
        model.DisplayCaptcha.Should().BeFalse();
        model.VendorId.Should().Be(_vendor.Id);
        model.VendorName.Should().Be(_vendor.Name);

        model = await _commonModelFactory.PrepareContactVendorModelAsync(model, _vendor, false);

        model.Email.Should().Be(NopTestsDefaults.AdminEmail);
        model.FullName.Should().Be("John Smith");

        model.SubjectEnabled = _commonSettings.SubjectFieldOnContactUsForm;
        model.DisplayCaptcha.Should().BeFalse();
        model.VendorId.Should().Be(_vendor.Id);
        model.VendorName.Should().Be(_vendor.Name);
    }

    [Test]
    public void PrepareContactVendorModelShouldRaiseExceptionIfModelOrVendorIsNull()
    {
        Assert.Throws<AggregateException>(() =>
            _commonModelFactory.PrepareContactVendorModelAsync(null, _vendor, true).Wait());

        Assert.Throws<AggregateException>(() =>
            _commonModelFactory.PrepareContactVendorModelAsync(null, _vendor, false).Wait());

        Assert.Throws<AggregateException>(() =>
            _commonModelFactory.PrepareContactVendorModelAsync(new ContactVendorModel(), null, true).Wait());

        Assert.Throws<AggregateException>(() =>
            _commonModelFactory.PrepareContactVendorModelAsync(new ContactVendorModel(), null, false).Wait());
    }

    [Test]
    public async Task CanPrepareStoreThemeSelectorModel()
    {
        var model = await _commonModelFactory.PrepareStoreThemeSelectorModelAsync();
        model.CurrentStoreTheme.Should().NotBeNull();
        model.CurrentStoreTheme.Name.Should().Be("DefaultClean");
        model.CurrentStoreTheme.Title.Should().Be("Default clean");
        model.AvailableStoreThemes.Should().NotBeNull();
        model.AvailableStoreThemes.Count.Should().BeGreaterThan(0);
    }

    [Test]
    public async Task CanPrepareFaviconAndAppIconsModel()
    {
        var model = await _commonModelFactory.PrepareFaviconAndAppIconsModelAsync();
        model.HeadCode.Should().Be(_commonSettings.FaviconAndAppIconsHeadCode);
    }

    [Test]
    public async Task CanPrepareRobotsTextFile()
    {
        var model = await _commonModelFactory.PrepareRobotsTextFileAsync();
        model.Should().NotBeNullOrEmpty();

        model.Trim().Split(Environment.NewLine).Length.Should().Be(165);
    }
}