using DomainResults.Common;

using DataProviders.Collections;

using Core.Abstractions;
using Core.Enumerations;

using WeatherForecast.Models.Requests;
using WeatherForecast.Models.Responses;

namespace WeatherForecast.Services {

  /// <summary>
  /// 
  /// </summary>
  public interface IShopCartItemService {

    /// <summary>
    /// 
    /// </summary>
    /// <param name="siteId"></param>
    /// <param name="userId"></param>
    /// <param name="sku"></param>
    /// <param name="requestModel"></param>
    /// <returns></returns>
    (Guid?, IDomainResult) Post(Guid siteId, Guid userId, string sku, ShopCartItemRequestModel requestModel);
    
    /// <summary>
    /// 
    /// </summary>
    /// <param name="siteId"></param>
    /// <param name="userId"></param>
    /// <param name="sku"></param>
    /// <param name="locale"></param>
    /// <returns></returns>
    (ShopCartItemResponseModel?, IDomainResult) Get(Guid siteId, Guid userId, string sku, string? locale);
    
    /// <summary>
    /// 
    /// </summary>
    /// <param name="siteId"></param>
    /// <param name="userId"></param>
    /// <param name="sku"></param>
    /// <param name="requestData"></param>
    /// <returns></returns>
    (Guid?, IDomainResult) Update(Guid siteId, Guid userId, string sku, ShopCartItemRequestModel requestData);
    
    /// <summary>
    /// 
    /// </summary>
    /// <param name="siteId"></param>
    /// <param name="userId"></param>
    /// <param name="sku"></param>
    /// <returns></returns>
    IDomainResult Delete(Guid siteId, Guid userId, string sku);
  }

  /// <summary>
  /// 
  /// </summary>
  public class ShopCartItemService : ServiceBase<ShopCartItemService>, IShopCartItemService {

    private readonly IShopCatalogDataProvider _shopCatalogDataProvider;
    private readonly IShopCartDataProvider _shopCartDataProvider;

    /// <summary>
    /// 
    /// </summary>
    /// <param name="logger"></param>
    /// <param name="shopCatalogDataProvider"></param>
    /// <param name="shopCartDataprovider"></param>
    public ShopCartItemService(
      ILogger<ShopCartItemService> logger,
      IShopCatalogDataProvider shopCatalogDataProvider,
      IShopCartDataProvider shopCartDataprovider
    ) : base(logger) {
      _shopCatalogDataProvider = shopCatalogDataProvider;
      _shopCartDataProvider = shopCartDataprovider;
    }

    /// <summary>
    /// 
    /// </summary>
    /// <param name="siteId"></param>
    /// <param name="userId"></param>
    /// <param name="sku"></param>
    /// <param name="requestModel"></param>
    /// <returns></returns>
    public (Guid?, IDomainResult) Post(Guid siteId, Guid userId, string sku, ShopCartItemRequestModel requestModel) {
      try {
        var (_, getResult) = _shopCartDataProvider.Get(siteId, userId, sku);
        if (getResult.IsSuccess)
          return IDomainResult.Failed<Guid?>();

        var item = requestModel.ToDomainObject();

        item.SiteId = siteId;
        item.UserId = userId;
        item.Sku = sku;

        var (id, insertResult) = _shopCartDataProvider.Insert(item);

        if (!insertResult.IsSuccess)
          return IDomainResult.Failed<Guid?>();

        return IDomainResult.Success(id);
      }
      catch (Exception ex) {
        _logger.LogError(ex, "Unhandled exception");
        return IDomainResult.Failed<Guid?>(ex.Message);
      }
    }

    /// <summary>
    /// 
    /// </summary>
    /// <param name="siteId"></param>
    /// <param name="userId"></param>
    /// <param name="sku"></param>
    /// <param name="locale"></param>
    /// <returns></returns>
    public (ShopCartItemResponseModel?, IDomainResult) Get(Guid siteId, Guid userId, string sku, string? locale) {
      try {
        var (cartItem, getCartItemResult) = _shopCartDataProvider.Get(siteId, userId, sku);
        if (!getCartItemResult.IsSuccess || cartItem == null)
          return (null, getCartItemResult);

        var (item, result) = _shopCatalogDataProvider.Get(siteId, cartItem.Sku);
        if (!result.IsSuccess || item == null) {
          var delteResult = _shopCartDataProvider.Delete(cartItem.Id);
          if (!delteResult.IsSuccess)
            return (null, delteResult);

          return IDomainResult.NotFound<ShopCartItemResponseModel?>();
        }
        else
          return IDomainResult.Success(new ShopCartItemResponseModel(item, cartItem, Enumeration.FromDisplayName<Locales>(locale ?? "en-US")));
      }
      catch (Exception ex) {
        _logger.LogError(ex, "Unhandled exception");
        return IDomainResult.Failed<ShopCartItemResponseModel?>(ex.Message);
      }
    }

    /// <summary>
    /// 
    /// </summary>
    /// <param name="siteId"></param>
    /// <param name="userId"></param>
    /// <param name="sku"></param>
    /// <param name="requestData"></param>
    /// <returns></returns>
    public (Guid?, IDomainResult) Update(Guid siteId, Guid userId, string sku, ShopCartItemRequestModel requestData) {
      try {
        var (item, getResult) = _shopCartDataProvider.Get(siteId, userId, sku);
        if (!getResult.IsSuccess || item == null)
          return (null, getResult);

        // construct domain object from model
        var newItem = requestData.ToDomainObject();
        newItem.Id = item.Id;
        newItem.SiteId = siteId;
        newItem.UserId = userId;
        newItem.Sku = sku;
        newItem.Created = item.Created;

        if (!item.Equals(newItem)) {
          var (id, updateResult) = _shopCartDataProvider.Update(newItem);
          if (!updateResult.IsSuccess || id == null)
            return (null, updateResult);
        }

        return IDomainResult.Success(item.Id);
      }
      catch (Exception ex) {
        _logger.LogError(ex, "Unhandled exception");
        return IDomainResult.Failed<Guid?>(ex.Message); 
      }
    }

    /// <summary>
    /// 
    /// </summary>
    /// <param name="siteId"></param>
    /// <param name="userId"></param>
    /// <param name="sku"></param>
    /// <returns></returns>
    public IDomainResult Delete(Guid siteId, Guid userId, string sku) {
      try {
        var (item, getResult) = _shopCartDataProvider.Get(siteId, userId, sku);
        if (!getResult.IsSuccess || item == null)
          return getResult;

        var result = _shopCartDataProvider.Delete(item.Id);
        if (!result.IsSuccess)
          return result;

        return IDomainResult.Success();
      }
      catch (Exception ex) {
        _logger.LogError(ex, "Unhandled exception");
        return IDomainResult.Failed(ex.Message);
      }
    }
  }
}
