Clear        


                
                    using APP.Models;
using CORE.APP.Services;
using CORE.APP.Services.Session.MVC;

namespace APP.Services
{
    /// <summary>
    /// Provides operations for managing a user's shopping cart.
    /// Stores cart data in session and retrieves product details using the product service.
    /// </summary>
    public class CartService : ICartService
    {
        /// <summary>
        /// The private constant session key used to store and retrieve cart data.
        /// </summary>
        const string SESSIONKEY = "cart";

        /// <summary>
        /// Service for session management, used to store and retrieve cart items.
        /// </summary>
        private readonly SessionServiceBase _sessionService;

        /// <summary>
        /// Service for accessing product data.
        /// </summary>
        private readonly IService<ProductRequest, ProductResponse> _productService;

        /// <summary>
        /// Initializes a new instance of the <see cref="CartService"/> class with the injection of session and product services.
        /// </summary>
        /// <param name="sessionService">Session service for managing cart data in session.</param>
        /// <param name="productService">Product service for retrieving product details.</param>
        public CartService(SessionServiceBase sessionService, IService<ProductRequest, ProductResponse> productService)
        {
            _productService = productService;
            _sessionService = sessionService;
        }

        /// <summary>
        /// Retrieves the list of items in the user's cart by user ID.
        /// </summary>
        /// <param name="userId">The unique identifier of the user.</param>
        /// <returns>A list of <see cref="CartItem"/> objects representing the user's cart contents.</returns>
        public List<CartItem> GetCart(int userId)
        {
            var cart = _sessionService.GetSession<List<CartItem>>(SESSIONKEY);
            if (cart is not null)
                return cart.Where(c => c.UserId == userId).ToList();
            return new List<CartItem>();
        }

        /// <summary>
        /// Retrieves a grouped summary of the user's cart items by product.
        /// Groups items by user ID, product ID and product name, then aggregates the product count and total price for each product.
        /// </summary>
        /// <param name="userId">The unique identifier of the user.</param>
        /// <returns>
        /// A list of <see cref="CartItemGroupedBy"/> objects, each representing a product in the user's cart
        /// with the total quantity and total price for that product.
        /// </returns>
        public List<CartItemGroupedBy> GetCartGroupedBy(int userId)
        {
            // Get all cart items for the specified user.
            var cart = GetCart(userId);

            // Group cart items by user ID, product ID and product name, then project each group into a summary object.
            return cart
                .GroupBy(cartItem => new // group cart items with key user ID, product ID and product name
                { 
                    cartItem.UserId, 
                    cartItem.ProductId, 
                    cartItem.ProductName 
                }) 
                .Select(cartItemGroupedBy => new CartItemGroupedBy
                {
                    UserId = cartItemGroupedBy.Key.UserId, // grouped cart item key's user ID
                    ProductId = cartItemGroupedBy.Key.ProductId, // grouped cart item key's product ID
                    ProductName = cartItemGroupedBy.Key.ProductName, // grouped cart item key's product name
                    ProductCount = cartItemGroupedBy.Count(), // Total quantity of this product according to the key
                    TotalPrice = cartItemGroupedBy.Sum(cartItem => cartItem.UnitPrice), // Aggregate price according to the key
                    TotalPriceF = cartItemGroupedBy.Sum(cartItem => cartItem.UnitPrice).ToString("C2") // Formatted price for display
                }).ToList();
        }

        /// <summary>
        /// Adds a product to the user's cart by user ID.
        /// Retrieves product details and updates the session cart.
        /// </summary>
        /// <param name="userId">The unique identifier of the user.</param>
        /// <param name="productId">The unique identifier of the product to add.</param>
        public void AddToCart(int userId, int productId)
        {
            var product = _productService.Item(productId);
            if (product is not null)
            {
                var cart = GetCart(userId);
                cart.Add(new CartItem
                {
                    UserId = userId,
                    ProductId = product.Id,
                    ProductName = product.Name,
                    UnitPrice = product.UnitPrice,
                    UnitPriceF = product.UnitPrice.ToString("C2")
                });
                _sessionService.SetSession(SESSIONKEY, cart);
            }
        }

        /// <summary>
        /// Removes a product from the user's cart by user ID.
        /// Updates the session cart after removal.
        /// </summary>
        /// <param name="userId">The unique identifier of the user.</param>
        /// <param name="productId">The unique identifier of the product to remove.</param>
        public void RemoveFromCart(int userId, int productId)
        {
            var cart = GetCart(userId);
            var cartItem = cart.FirstOrDefault(c => c.UserId == userId && c.ProductId == productId);
            if (cartItem is not null)
                cart.Remove(cartItem);
            _sessionService.SetSession(SESSIONKEY, cart);
        }

        /// <summary>
        /// Clears all items from the user's cart by user ID.
        /// Updates the session cart after clearing.
        /// </summary>
        /// <param name="userId">The unique identifier of the user.</param>
        public void ClearCart(int userId)
        {
            var cart = GetCart(userId);
            cart.RemoveAll(c => c.UserId == userId);
            _sessionService.SetSession(SESSIONKEY, cart);
        }
    }
}