import { defineStore } from 'pinia' import { ref, computed } from 'vue' import type { Cart, CartItem, Company, Product } from '@/types' import { generateId } from '@/utils/format' import { validateMeterage } from '@/utils/validation' import { getItem, setItem, STORAGE_KEYS } from '@/services/storage' import { getCompanyById } from '@/data/mockData' const DEFAULT_MAX_METERAGE = 5000 function loadCarts(): Cart[] { return getItem(STORAGE_KEYS.carts, []) } function saveCarts(carts: Cart[]) { setItem(STORAGE_KEYS.carts, carts) } function loadActiveCartId(): string | null { return getItem(STORAGE_KEYS.activeCartId, null) } function saveActiveCartId(id: string | null) { setItem(STORAGE_KEYS.activeCartId, id) } function getCartTotalMeterage(cart: Cart): number { return cart.items.reduce((sum, item) => sum + item.meterage, 0) } function companyMeterage(cart: Cart, companyId: string): number { return cart.items .filter((item) => item.companyId === companyId) .reduce((sum, item) => sum + item.meterage, 0) } function uniqueCompanyNames(items: CartItem[]): string { const names = [...new Set(items.map((item) => item.companyName).filter(Boolean))] return names.join('، ') } function syncCartCompanyMeta(cart: Cart) { if (cart.items.length === 0) return const first = cart.items[0]! cart.companyId = first.companyId cart.companyName = uniqueCompanyNames(cart.items) || first.companyName } function migrateCartItems(carts: Cart[]): Cart[] { return carts.map((cart) => ({ ...cart, items: cart.items.map((item) => ({ ...item, companyId: item.companyId || cart.companyId, companyName: item.companyName || cart.companyName, })), })) } export const useCartStore = defineStore('cart', () => { const carts = ref(migrateCartItems(loadCarts())) const activeCartId = ref(loadActiveCartId()) const selectedCompanyId = ref(null) const activeCart = computed(() => carts.value.find((c) => c.id === activeCartId.value) ?? null) const totalMeterage = computed( () => activeCart.value?.items.reduce((sum, i) => sum + i.meterage, 0) ?? 0, ) const itemCount = computed(() => activeCart.value?.items.length ?? 0) const companyNamesLabel = computed(() => { if (!activeCart.value?.items.length) return '' return uniqueCompanyNames(activeCart.value.items) }) const maxMeterage = computed(() => { if (!activeCart.value?.items.length) { const selected = selectedCompanyId.value ? getCompanyById(selectedCompanyId.value) : null return selected?.maxMeteragePerInvoice ?? DEFAULT_MAX_METERAGE } const companyIds = [...new Set(activeCart.value.items.map((item) => item.companyId))] return companyIds.reduce((sum, id) => { const company = getCompanyById(id) return sum + (company?.maxMeteragePerInvoice ?? DEFAULT_MAX_METERAGE) }, 0) }) const remainingCapacity = computed(() => Math.max(0, maxMeterage.value - totalMeterage.value)) const isFull = computed(() => totalMeterage.value >= maxMeterage.value) function persist() { saveCarts(carts.value) saveActiveCartId(activeCartId.value) } function createEmptyCart(company?: Company): Cart { const cart: Cart = { id: generateId(), companyId: company?.id ?? '', companyName: company?.name ?? '', items: [], } carts.value.push(cart) activeCartId.value = cart.id if (company) selectedCompanyId.value = company.id persist() return cart } function getOrCreateCart(company?: Company): Cart { if (activeCart.value) return activeCart.value const withItems = carts.value.find((cart) => cart.items.length > 0) if (withItems) { activeCartId.value = withItems.id selectedCompanyId.value = selectedCompanyId.value ?? withItems.companyId persist() return withItems } const open = carts.value.find( (cart) => getCartTotalMeterage(cart) < DEFAULT_MAX_METERAGE, ) if (open) { activeCartId.value = open.id if (company) selectedCompanyId.value = company.id persist() return open } return createEmptyCart(company) } /** @deprecated Prefer getOrCreateCart / selectCompany — kept for callers. */ function initCartForCompany(company: Company): Cart { selectedCompanyId.value = company.id const cart = getOrCreateCart(company) if (!cart.companyId) { cart.companyId = company.id cart.companyName = company.name persist() } return cart } function selectCompany(company: Company): void { selectedCompanyId.value = company.id getOrCreateCart(company) } function createNewCartForSameCompany(): Cart | null { const company = selectedCompanyId.value ? getCompanyById(selectedCompanyId.value) : activeCart.value?.companyId ? getCompanyById(activeCart.value.companyId) : undefined return createEmptyCart(company) } function addItem( product: Product, catalogCode: string, meterage: number, ): { success: boolean; message?: string } { const company = getCompanyById(product.companyId) if (!company) { return { success: false, message: 'شرکت محصول یافت نشد.' } } const cart = getOrCreateCart(company) selectedCompanyId.value = company.id const companyMax = company.maxMeteragePerInvoice const currentCompanyMeterage = companyMeterage(cart, company.id) const existing = cart.items.find((i) => i.productId === product.id) const previousMeterage = existing?.meterage ?? 0 const validation = validateMeterage( meterage, product, currentCompanyMeterage, companyMax, previousMeterage, ) if (!validation.valid) { return { success: false, message: validation.message } } if (existing) { existing.meterage = meterage existing.catalogCode = catalogCode existing.companyId = company.id existing.companyName = company.name } else { cart.items.push({ id: generateId(), productId: product.id, catalogCode, productName: product.name, productCode: product.code, color: product.color, meterage, unitPrice: product.basePrice, companyId: company.id, companyName: company.name, }) } syncCartCompanyMeta(cart) persist() return { success: true } } function updateItemMeterage( itemId: string, meterage: number, product: Product, ): { success: boolean; message?: string } { if (!activeCart.value) return { success: false, message: 'سبد خرید یافت نشد.' } const item = activeCart.value.items.find((i) => i.id === itemId) if (!item) return { success: false, message: 'آیتم یافت نشد.' } const company = getCompanyById(item.companyId || product.companyId) const companyMax = company?.maxMeteragePerInvoice ?? DEFAULT_MAX_METERAGE const currentCompanyMeterage = companyMeterage(activeCart.value, item.companyId) const validation = validateMeterage( meterage, product, currentCompanyMeterage, companyMax, item.meterage, ) if (!validation.valid) { return { success: false, message: validation.message } } item.meterage = meterage persist() return { success: true } } function removeItem(itemId: string) { if (!activeCart.value) return activeCart.value.items = activeCart.value.items.filter((i) => i.id !== itemId) syncCartCompanyMeta(activeCart.value) persist() } function setNotes(notes: string) { if (!activeCart.value) return activeCart.value.notes = notes persist() } function clearActiveCart() { if (!activeCart.value) return activeCart.value.items = [] activeCart.value.notes = undefined persist() } function ensureActiveCartForCartPage() { if (activeCart.value?.items.length) return const cartWithItems = carts.value.find((cart) => cart.items.length > 0) if (!cartWithItems) return activeCartId.value = cartWithItems.id selectedCompanyId.value = selectedCompanyId.value || cartWithItems.companyId persist() } function hydrate() { carts.value = migrateCartItems(loadCarts()) activeCartId.value = loadActiveCartId() if (activeCart.value) { syncCartCompanyMeta(activeCart.value) selectedCompanyId.value = selectedCompanyId.value || activeCart.value.companyId persist() } } return { carts, activeCartId, selectedCompanyId, activeCart, totalMeterage, itemCount, companyNamesLabel, maxMeterage, remainingCapacity, isFull, initCartForCompany, selectCompany, createNewCartForSameCompany, addItem, updateItemMeterage, removeItem, setNotes, clearActiveCart, ensureActiveCartForCartPage, hydrate, } })