package com.imprimelibros.erp.cart; import jakarta.transaction.Transactional; import org.springframework.context.MessageSource; import org.springframework.stereotype.Service; import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Locale; import java.util.Map; import com.imprimelibros.erp.presupuesto.classes.PresupuestoFormatter; import com.imprimelibros.erp.presupuesto.dto.Presupuesto; import com.imprimelibros.erp.common.Utils; import com.imprimelibros.erp.presupuesto.PresupuestoRepository; @Service public class CartService { private final CartRepository cartRepo; private final CartItemRepository itemRepo; private final MessageSource messageSource; private final PresupuestoFormatter presupuestoFormatter; private final PresupuestoRepository presupuestoRepo; private final Utils utils; public CartService(CartRepository cartRepo, CartItemRepository itemRepo, MessageSource messageSource, PresupuestoFormatter presupuestoFormatter, PresupuestoRepository presupuestoRepo, Utils utils) { this.cartRepo = cartRepo; this.itemRepo = itemRepo; this.messageSource = messageSource; this.presupuestoFormatter = presupuestoFormatter; this.presupuestoRepo = presupuestoRepo; this.utils = utils; } /** Devuelve el carrito activo o lo crea si no existe. */ @Transactional public Cart getOrCreateActiveCart(Long userId) { return cartRepo.findByUserIdAndStatus(userId, Cart.Status.ACTIVE) .orElseGet(() -> { Cart c = new Cart(); c.setUserId(userId); c.setStatus(Cart.Status.ACTIVE); return cartRepo.save(c); }); } /** Lista items (presupuestos) del carrito activo del usuario. */ @Transactional public List> listItems(Long userId, Locale locale) { Cart cart = getOrCreateActiveCart(userId); List> resultados = new ArrayList<>(); List items = itemRepo.findByCartId(cart.getId()); for (CartItem item : items) { Presupuesto p = presupuestoRepo.findById(item.getPresupuestoId()) .orElseThrow(() -> new IllegalStateException("Presupuesto no encontrado: " + item.getPresupuestoId())); Map elemento = getElementoCart(p, locale); elemento.put("cartItemId", item.getId()); resultados.add(elemento); } //System.out.println("Cart items: " + resultados); return resultados; } /** Añade un presupuesto al carrito. Si ya está, no hace nada (idempotente). */ @Transactional public void addPresupuesto(Long userId, Long presupuestoId) { Cart cart = getOrCreateActiveCart(userId); boolean exists = itemRepo.existsByCartIdAndPresupuestoId(cart.getId(), presupuestoId); if (!exists) { CartItem ci = new CartItem(); ci.setCart(cart); ci.setPresupuestoId(presupuestoId); itemRepo.save(ci); } } /** Elimina una línea del carrito por ID de item (validando pertenencia). */ @Transactional public void removeItem(Long userId, Long itemId) { Cart cart = getOrCreateActiveCart(userId); CartItem item = itemRepo.findById(itemId).orElseThrow(() -> new IllegalArgumentException("Item no existe")); if (!item.getCart().getId().equals(cart.getId())) throw new IllegalStateException("El item no pertenece a tu carrito"); itemRepo.delete(item); } /** Elimina una línea del carrito buscando por presupuesto_id. */ @Transactional public void removeByPresupuesto(Long userId, Long presupuestoId) { Cart cart = getOrCreateActiveCart(userId); itemRepo.findByCartIdAndPresupuestoId(cart.getId(), presupuestoId) .ifPresent(itemRepo::delete); } /** Vacía todo el carrito activo. */ @Transactional public void clear(Long userId) { Cart cart = getOrCreateActiveCart(userId); itemRepo.deleteByCartId(cart.getId()); } /** Marca el carrito como bloqueado (por ejemplo, antes de crear un pedido). */ @Transactional public void lockCart(Long userId) { Cart cart = getOrCreateActiveCart(userId); cart.setStatus(Cart.Status.LOCKED); cartRepo.save(cart); } @Transactional public long countItems(Long userId) { Cart cart = getOrCreateActiveCart(userId); return itemRepo.findByCartId(cart.getId()).size(); } private Map getElementoCart(Presupuesto presupuesto, Locale locale) { Map resumen = new HashMap<>(); resumen.put("titulo", presupuesto.getTitulo()); resumen.put("imagen", "/assets/images/imprimelibros/presupuestador/" + presupuesto.getTipoEncuadernacion() + ".png"); resumen.put("imagen_alt", messageSource.getMessage("presupuesto." + presupuesto.getTipoEncuadernacion(), null, locale)); resumen.put("presupuestoId", presupuesto.getId()); Map detalles = utils.getTextoPresupuesto(presupuesto, locale); resumen.put("baseTotal", Utils.formatCurrency(presupuesto.getBaseImponible(), locale)); resumen.put("base", presupuesto.getBaseImponible()); resumen.put("iva4", presupuesto.getIvaImporte4()); resumen.put("iva21", presupuesto.getIvaImporte21()); resumen.put("resumen", detalles); return resumen; } }