import { Injectable, NotFoundException } from '@nestjs/common'; import { Product } from '../../products/entities/product.entity'; import { Cart, CartItem } from '../interfaces/cart.interface'; import { CartValidationService } from './cart-validation.service'; import { CartCalculationService } from './cart-calculation.service'; import { CartMessage } from 'src/common/enums/message.enum'; @Injectable() export class CartItemService { constructor( private readonly validationService: CartValidationService, private readonly calculationService: CartCalculationService, ) {} /** * Create a new cart item from product */ createCartItem(product: Product, quantity: number): CartItem { const itemPrice = product.price || 0; const itemDiscount = product.discount || 0; return { foodId: product.id, foodTitle: product.title, quantity, price: itemPrice, discount: itemDiscount, totalPrice: this.calculationService.calculateItemTotalPrice(itemPrice, itemDiscount, quantity), }; } /** * Build cart item from product (updating existing item if provided) */ buildCartItemFromFood(product: Product, quantity: number, previous?: CartItem): CartItem { const itemPrice = product.price || 0; const itemDiscount = product.discount || 0; return { ...(previous ?? ({} as CartItem)), foodId: product.id, foodTitle: product.title, quantity, price: itemPrice, discount: itemDiscount, totalPrice: this.calculationService.calculateItemTotalPrice(itemPrice, itemDiscount, quantity), }; } /** * Get item index in cart */ getItemIndex(cart: Cart, foodId: string): number { return cart.items.findIndex(item => item.foodId === foodId); } /** * Add or increment item in cart */ async addOrIncrementItem(cart: Cart, foodId: string, restaurantId: string, quantityToAdd: number): Promise { const product = await this.validationService.validateAndGetFood(foodId, restaurantId, quantityToAdd); const index = this.getItemIndex(cart, product.id); if (index < 0) { cart.items.push(this.createCartItem(product, quantityToAdd)); return; } const existingItem = cart.items[index]; const newQuantity = existingItem.quantity + quantityToAdd; this.validationService.validateStock(product, newQuantity); cart.items[index] = this.buildCartItemFromFood(product, newQuantity, existingItem); } /** * Remove item from cart */ removeItemOrFail(cart: Cart, foodId: string): void { const itemIndex = this.getItemIndex(cart, foodId); if (itemIndex < 0) { throw new NotFoundException(CartMessage.ITEM_NOT_FOUND); } cart.items.splice(itemIndex, 1); } /** * Decrement item quantity or remove if quantity reaches 0 */ async decrementOrRemoveItem(cart: Cart, foodId: string): Promise { const itemIndex = this.getItemIndex(cart, foodId); if (itemIndex < 0) { throw new NotFoundException(CartMessage.ITEM_NOT_FOUND); } const existingItem = cart.items[itemIndex]; const newQuantity = existingItem.quantity - 1; if (newQuantity <= 0) { cart.items.splice(itemIndex, 1); return; } const product = await this.validationService.getFoodOrFail(foodId); cart.items[itemIndex] = this.buildCartItemFromFood(product, newQuantity, existingItem); } }