"use client"; import { create } from "zustand"; import { persist } from "zustand/middleware"; import { Product } from "../data/products"; import { orderService } from "../services/orderService"; import api from "../services/api"; export interface CartItem { product: Product; quantity: number; calculatedDose?: { quantity: number; unit: string; }; } interface Order { id: string; date: string; items: CartItem[]; total: number; charityDonation?: number; paymentMethod?: string; isRefill?: boolean; status: 'processing' | 'shipped' | 'delivered'; petId?: string; shippingAddress?: string; trackingNumber: string; } interface CartStore { items: CartItem[]; isSubscribed: boolean; charityDonation: number; coupon: { code: string; discount: number } | null; orders: Order[]; addItem: (product: Product, quantity: number, dose?: { quantity: number; unit: string }) => void; removeItem: (productId: string) => void; updateQuantity: (productId: string, quantity: number) => void; toggleSubscription: () => void; setCharityDonation: (amount: number) => void; applyCoupon: (code: string) => Promise; addOrder: (orderData: Omit) => Promise; clearCart: () => void; removeCoupon: () => void; setOrders: (orders: Record[]) => void; getTotalItems: () => number; getSubtotal: () => number; getDiscount: () => number; getTotal: () => number; } export const useCartStore = create()( persist( (set, get) => ({ items: [], isSubscribed: false, charityDonation: 0, coupon: null, orders: [], addItem: (product, quantity, dose) => { const items = get().items; const existing = items.find((i) => i.product.id === product.id); if (existing) { set({ items: items.map((i) => i.product.id === product.id ? { ...i, quantity: i.quantity + quantity } : i ), }); } else { set({ items: [...items, { product, quantity, calculatedDose: dose }] }); } }, removeItem: (productId) => { set({ items: get().items.filter((i) => i.product.id !== productId) }); }, updateQuantity: (productId, quantity) => { if (quantity <= 0) { get().removeItem(productId); return; } set({ items: get().items.map((i) => i.product.id === productId ? { ...i, quantity } : i ), }); }, toggleSubscription: () => set({ isSubscribed: !get().isSubscribed }), setCharityDonation: (amount) => set({ charityDonation: amount }), applyCoupon: async (code) => { try { const cleanCode = code.toUpperCase().trim(); const subtotal = get().getSubtotal(); const response = await api.post('/orders/validate-coupon', { code: cleanCode, cartTotal: subtotal }); if (response.data && response.data.discountValue) { set({ coupon: { code: cleanCode, discount: response.data.discountValue } }); return true; } return false; } catch (error) { console.error("Failed to apply coupon:", error); return false; } }, addOrder: async (orderData) => { const payload = { petId: orderData.petId, couponCode: get().coupon?.code, charityDonation: orderData.charityDonation, paymentMethod: orderData.paymentMethod, isRefill: orderData.isRefill || get().isSubscribed, refillIntervalDays: 60, shippingAddress: orderData.shippingAddress, items: orderData.items.map(i => ({ productId: i.product.id, quantity: i.quantity })) }; try { const backendOrder = await orderService.createOrder(payload); const bo = backendOrder as unknown as Record; const newOrder: Order = { ...orderData, id: backendOrder.id, date: backendOrder.createdAt, total: Number(backendOrder.totalAmount), charityDonation: Number(backendOrder.charityDonation), status: (['processing', 'shipped', 'delivered'].includes(backendOrder.status) ? backendOrder.status : 'processing') as Order['status'], isRefill: bo.isRefill !== undefined ? Boolean(bo.isRefill) : Boolean(orderData.isRefill || get().isSubscribed), paymentMethod: (bo.paymentMethod as string) || orderData.paymentMethod, trackingNumber: backendOrder.trackingNumber || `CN-${Math.floor(Math.random() * 90000) + 10000}` }; set({ orders: [newOrder, ...get().orders] }); return backendOrder.id; } catch (error) { console.error("Order creation failed on backend:", error); throw error; } }, clearCart: () => set({ items: [], coupon: null }), removeCoupon: () => set({ coupon: null }), setOrders: (backendOrders) => { const mappedOrders: Order[] = backendOrders.map(bo => ({ id: String(bo.id), date: String(bo.createdAt), items: (bo.orderItems as Array<{ product: Product; quantity: number }>)?.map((oi) => ({ product: oi.product, quantity: oi.quantity })) || [], total: Number(bo.totalAmount), charityDonation: Number(bo.charityDonation), status: (['processing', 'shipped', 'delivered'].includes(String(bo.status)) ? bo.status : 'processing') as Order['status'], isRefill: Boolean(bo.isRefill), paymentMethod: bo.paymentMethod as string | undefined, petId: (bo.petId as string) || ((bo.pet as { id?: string })?.id), shippingAddress: bo.shippingAddress as string | undefined, trackingNumber: (bo.trackingNumber as string) || `CN-${Math.floor(Math.random() * 90000) + 10000}` })); set({ orders: mappedOrders }); }, getTotalItems: () => get().items.reduce((acc, item) => acc + item.quantity, 0), getSubtotal: () => get().items.reduce((acc, item) => acc + item.product.priceValue * item.quantity, 0), getDiscount: () => { const subtotal = get().getSubtotal(); let discount = 0; if (get().coupon) { const c = get().coupon!; if (c.discount < 1) { discount += subtotal * c.discount; } else { discount += c.discount; } } return Math.min(discount, subtotal); }, getNextOrderReward: () => { const subtotal = get().getSubtotal(); return get().isSubscribed ? Math.round(subtotal * 0.05) : 0; }, getTotal: () => get().getSubtotal() - get().getDiscount() + get().charityDonation, }), { name: "canina-cart" } ) );