import { computed, inject, onMounted, provide, reactive, ref, watch, type InjectionKey } from 'vue' import { useRoute, useRouter } from 'vue-router' import { companiesApi, customersApi, mapAdminOrder, ordersApi } from '@/services/api' import { ApiError } from '@/services/http' import type { Company, Customer, Order, RawOrderStatus, SettlementMethod } from '@/types' import { rawStatusLabel } from '@/utils/orderStatus' import { useToast } from '@/composables/useToast' export function useOrdersPage() { const route = useRoute() const router = useRouter() const toast = useToast() const companies = ref([]) const customers = ref([]) const orderList = ref([]) const activeTab = ref(typeof route.query.tab === 'string' && route.query.tab.trim() ? route.query.tab.trim() : 'all') const selectedOrderId = ref('') const searchQuery = ref('') const showAddModal = ref(false) const showDetailPanel = ref(false) const showDetailModal = ref(false) const formError = ref('') const saving = ref(false) const emptyForm = () => ({ customerId: '', customerName: '', companyId: companies.value[0]?.id ?? '', settlementMethod: 'check' as SettlementMethod, meterage: 1000, customerPhone: '', }) const form = reactive(emptyForm()) const isFormValid = computed( () => form.customerId.length > 0 && form.companyId.length > 0, ) const activeCustomers = computed(() => { const list = [...customers.value] list.sort((a, b) => Number(b.isActive) - Number(a.isActive) || a.name.localeCompare(b.name, 'fa')) return list }) function applyCustomer(customerId: string) { const customer = customers.value.find((c) => c.id === customerId) form.customerId = customerId form.customerName = customer?.name ?? '' form.customerPhone = customer?.phone ?? '' } async function loadCustomers() { try { customers.value = await customersApi.list() } catch (err) { toast.error(err instanceof ApiError ? err.message : 'بارگذاری مشتریان انجام نشد.') } } const filteredOrders = computed(() => { let list = orderList.value if (activeTab.value !== 'all') { list = list.filter((o) => o.status === activeTab.value) } if (searchQuery.value.trim()) { const q = searchQuery.value.trim() list = list.filter( (o) => o.orderNumber.includes(q) || o.customerName.includes(q), ) } return list }) const selectedOrder = computed(() => orderList.value.find((o) => o.id === selectedOrderId.value) ?? null, ) function findOrderByRef(ref: string): Order | undefined { const key = ref.trim() if (!key) return undefined return orderList.value.find( (o) => o.id === key || o.orderNumber.toUpperCase() === key.toUpperCase(), ) } async function applyOrderDeepLink() { const orderRef = typeof route.query.order === 'string' ? route.query.order : '' if (!orderRef || !orderList.value.length) return const order = findOrderByRef(orderRef) if (!order) { searchQuery.value = orderRef return } const focus = typeof route.query.focus === 'string' ? route.query.focus : '' if (focus === 'pricing') { await router.replace(`/orders/${order.id}/pricing`) return } if (focus === 'checks') { await router.replace(`/orders/${order.id}/checks`) return } openOrderDetail(order) searchQuery.value = order.orderNumber } async function loadData() { try { const [ordersData, companiesData, customersData] = await Promise.all([ ordersApi.list(), companiesApi.list(), customersApi.list(), ]) orderList.value = ordersData.map((o) => mapAdminOrder(o) as Order) companies.value = companiesData customers.value = customersData if (!form.companyId && companiesData[0]) { form.companyId = companiesData[0].id } await applyOrderDeepLink() } catch (err) { toast.error(err instanceof ApiError ? err.message : 'بارگذاری سفارش‌ها انجام نشد.') } } onMounted(() => { void loadData() }) watch( () => [route.query.order, route.query.focus] as const, () => { void applyOrderDeepLink() }, ) watch( () => route.query.tab, (tab) => { if (typeof tab === 'string' && tab.trim()) { activeTab.value = tab.trim() } }, ) function selectOrder(order: Order, openDetail = false) { selectedOrderId.value = order.id if (openDetail) { showDetailPanel.value = true } } function openOrderDetail(order: Order) { selectedOrderId.value = order.id showDetailModal.value = true } function closeDetailPanel() { showDetailPanel.value = false } function closeDetailModal() { showDetailModal.value = false } function settlementLabel(method?: string | null) { if (!method) return 'انتخاب‌نشده' return method === 'check' ? 'چکی' : 'نقدی' } const statusSaving = ref(false) async function changeStatus(payload: { orderId: string status: RawOrderStatus note?: string reason?: string force?: boolean }) { if (statusSaving.value) return null statusSaving.value = true try { const updated = await ordersApi.updateStatus(payload.orderId, { status: payload.status, note: payload.note, reason: payload.reason, force: payload.force, }) const mapped = mapAdminOrder(updated) as Order const index = orderList.value.findIndex((o) => o.id === payload.orderId) if (index >= 0) orderList.value[index] = { ...orderList.value[index]!, ...mapped } toast.success(`وضعیت سفارش به «${rawStatusLabel(payload.status)}» تغییر کرد.`) return mapped } catch (err) { toast.error(err instanceof ApiError ? err.message : 'تغییر وضعیت انجام نشد.') return null } finally { statusSaving.value = false } } function goPricing(order: Order) { router.push(`/orders/${order.id}/pricing`) } function goChecks(order: Order) { router.push(`/orders/${order.id}/checks`) } function goCashReceipt(order: Order) { router.push({ path: '/cash-payments', query: { order: order.orderNumber } }) } function openAddModal() { Object.assign(form, emptyForm()) formError.value = '' showAddModal.value = true void loadCustomers() } function closeAddModal() { showAddModal.value = false formError.value = '' } async function submitAddOrder() { if (!isFormValid.value) { formError.value = 'انتخاب مشتری و شرکت الزامی است.' return } saving.value = true try { const created = await ordersApi.create({ companyId: form.companyId, customerId: form.customerId || undefined, userId: form.customerId || undefined, customerName: form.customerName.trim(), customerPhone: form.customerPhone.trim() || undefined, settlementMethod: form.settlementMethod, meterage: form.meterage, }) const mapped = mapAdminOrder(created) as Order orderList.value.unshift(mapped) selectedOrderId.value = mapped.id toast.success('سفارش جدید ثبت شد.') closeAddModal() } catch (err) { toast.error(err instanceof ApiError ? err.message : 'ثبت سفارش انجام نشد.') } finally { saving.value = false } } return { companies, customers, activeCustomers, applyCustomer, loadCustomers, orderList, activeTab, selectedOrderId, searchQuery, showAddModal, showDetailPanel, showDetailModal, formError, form, isFormValid, filteredOrders, selectedOrder, selectOrder, openOrderDetail, closeDetailPanel, closeDetailModal, settlementLabel, changeStatus, statusSaving, goPricing, goChecks, goCashReceipt, openAddModal, closeAddModal, submitAddOrder, saving, } } export type OrdersPageContext = ReturnType export const ORDERS_PAGE_KEY: InjectionKey = Symbol('orders-page') export function provideOrdersPage() { const ctx = useOrdersPage() provide(ORDERS_PAGE_KEY, ctx) return ctx } export function useOrdersPageContext() { const ctx = inject(ORDERS_PAGE_KEY) if (!ctx) throw new Error('Orders page context is missing') return ctx }