using Grand.Business.Core.Interfaces.Checkout.Shipping;
using Grand.Business.Core.Interfaces.Common.Configuration;
using Grand.Business.Core.Interfaces.Common.Directory;
using Grand.Business.Core.Interfaces.Common.Localization;
using Grand.Business.Core.Interfaces.Common.Stores;
using Grand.Domain.Stores;
using Grand.Web.Admin.Extensions.Mapping;
using Grand.Web.Admin.Interfaces;
using Grand.Web.Admin.Models.Stores;
using Microsoft.AspNetCore.Mvc.Rendering;

namespace Grand.Web.Admin.Services;

public class StoreViewModelService : IStoreViewModelService
{
    private readonly ICountryService _countryService;
    private readonly ICurrencyService _currencyService;
    private readonly ILanguageService _languageService;
    private readonly ISettingService _settingService;
    private readonly IStoreService _storeService;
    private readonly IWarehouseService _warehouseService;

    public StoreViewModelService(ILanguageService languageService, IWarehouseService warehouseService,
        IStoreService storeService, ISettingService settingService,
        ICountryService countryService, ICurrencyService currencyService)
    {
        _languageService = languageService;
        _warehouseService = warehouseService;
        _storeService = storeService;
        _settingService = settingService;
        _countryService = countryService;
        _currencyService = currencyService;
    }

    public virtual async Task PrepareLanguagesModel(StoreModel model)
    {
        ArgumentNullException.ThrowIfNull(model);

        model.AvailableLanguages.Add(new SelectListItem {
            Text = "---",
            Value = ""
        });
        var languages = await _languageService.GetAllLanguages(true);
        foreach (var language in languages)
            model.AvailableLanguages.Add(new SelectListItem {
                Text = language.Name,
                Value = language.Id
            });
    }

    public virtual async Task PrepareWarehouseModel(StoreModel model)
    {
        ArgumentNullException.ThrowIfNull(model);

        //warehouse
        model.AvailableWarehouses.Add(new SelectListItem {
            Text = "---",
            Value = ""
        });
        var warehouses = await _warehouseService.GetAllWarehouses();
        foreach (var warehouse in warehouses)
            model.AvailableWarehouses.Add(new SelectListItem {
                Text = warehouse.Name,
                Value = warehouse.Id
            });
    }

    public virtual async Task PrepareCountryModel(StoreModel model)
    {
        ArgumentNullException.ThrowIfNull(model);

        //countries
        model.AvailableCountries.Add(new SelectListItem {
            Text = "---",
            Value = ""
        });

        var countries = await _countryService.GetAllCountries();
        foreach (var country in countries)
            model.AvailableCountries.Add(new SelectListItem {
                Text = country.Name,
                Value = country.Id
            });
    }

    public virtual async Task PrepareCurrencyModel(StoreModel model)
    {
        ArgumentNullException.ThrowIfNull(model);

        //countries
        model.AvailableCurrencies.Add(new SelectListItem {
            Text = "---",
            Value = ""
        });

        var currencies = await _currencyService.GetAllCurrencies();
        foreach (var currency in currencies)
            model.AvailableCurrencies.Add(new SelectListItem {
                Text = currency.Name,
                Value = currency.Id
            });
    }

    public virtual StoreModel PrepareStoreModel()
    {
        var model = new StoreModel();
        return model;
    }

    public virtual async Task<Store> InsertStoreModel(StoreModel model)
    {
        var store = model.ToEntity();
        //ensure we have "/" at the end
        if (!store.Url.Trim().EndsWith("/"))
            store.Url = store.Url.Trim() + "/";

        if (!string.IsNullOrEmpty(store.SecureUrl) && !store.SecureUrl.Trim().EndsWith("/"))
            store.SecureUrl = store.SecureUrl.Trim() + "/";

        var storeUri = new Uri(store.Url);

        store.Domains.Add(new DomainHost {
            HostName = storeUri.Host,
            Url = store.SslEnabled ? store.SecureUrl : store.Url,
            Primary = true
        });

        await _storeService.InsertStore(store);
        return store;
    }

    public virtual async Task<Store> UpdateStoreModel(Store store, StoreModel model)
    {
        store = model.ToEntity(store);

        //ensure we have "/" at the end
        if (!store.Url.Trim().EndsWith("/"))
            store.Url = store.Url.Trim() + "/";
        if (!string.IsNullOrEmpty(store.SecureUrl) && !store.SecureUrl.Trim().EndsWith("/"))
            store.SecureUrl = store.SecureUrl.Trim() + "/";

        var domain = store.Domains.FirstOrDefault(x => x.Primary);
        if (domain == null)
        {
            var storeUri = new Uri(store.Url);
            store.Domains.Add(new DomainHost {
                HostName = storeUri.Host,
                Url = store.SslEnabled ? store.SecureUrl : store.Url,
                Primary = true
            });
        }
        else
        {
            var storeUri = new Uri(store.Url);
            domain.HostName = storeUri.Host;
            domain.Url = store.SslEnabled ? store.SecureUrl : store.Url;
        }

        await _storeService.UpdateStore(store);
        return store;
    }

    public virtual async Task DeleteStore(Store store)
    {
        await _storeService.DeleteStore(store);

        //when we delete a store we should also ensure that all "per store" settings will also be deleted
        var settingsToDelete = _settingService
            .GetAllSettings()
            .Where(s => s.StoreId == store.Id)
            .ToList();
        foreach (var setting in settingsToDelete)
            await _settingService.DeleteSetting(setting);
        //when we had two stores and now have only one store, we also should delete all "per store" settings
        var allStores = await _storeService.GetAllStores();
        if (allStores.Count == 1)
        {
            settingsToDelete = _settingService
                .GetAllSettings()
                .Where(s => s.StoreId == allStores[0].Id)
                .ToList();
            foreach (var setting in settingsToDelete)
                await _settingService.DeleteSetting(setting);
        }
    }

    #region DomainHost

    public virtual async Task InsertDomainHostModel(Store store, DomainHostModel model)
    {
        ArgumentNullException.ThrowIfNull(store);
        ArgumentNullException.ThrowIfNull(model);

        if (!model.Url.EndsWith("/"))
            model.Url += "/";

        var storeUri = new Uri(model.Url);

        store.Domains.Add(new DomainHost {
            HostName = storeUri.Host,
            Url = model.Url
        });
        await _storeService.UpdateStore(store);
    }

    public virtual async Task UpdateDomainHostModel(Store store, DomainHostModel model)
    {
        ArgumentNullException.ThrowIfNull(store);
        ArgumentNullException.ThrowIfNull(model);

        if (!model.Url.EndsWith("/"))
            model.Url += "/";

        var domain = store.Domains.FirstOrDefault(x => x.Id == model.Id);
        if (domain != null)
        {
            var storeUri = new Uri(model.Url);
            domain.HostName = storeUri.Host;
            domain.Url = model.Url;
        }

        await _storeService.UpdateStore(store);
    }

    public virtual async Task DeleteDomainHostModel(Store store, string id)
    {
        var domain = store.Domains.FirstOrDefault(x => x.Id == id);
        if (domain != null)
        {
            store.Domains.Remove(domain);
            await _storeService.UpdateStore(store);
        }
    }

    #endregion
}