import { apiClient } from '@/services/api/client'; import { Purchase, Product } from '../types'; interface OrderItemApi { id?: string; product_id: string; price: number; title?: string; } interface OrderApi { id: string; status: string; total_amount?: number; total?: number; created_at: string; items?: OrderItemApi[]; } interface SellerSale { order_id: string; product_id: string; product_title: string; buyer_id: string; amount: number; date: string; } interface StatsEvolutionPoint { date: string; revenue: number; sales_count: number; } interface TopProductStats { product_id: string; title: string; revenue: number; sales_count: number; } export interface SellerTransfer { id: string; seller_id?: string; order_id: string; amount_cents: number; platform_fee_cents: number; currency: string; status: 'pending' | 'completed' | 'failed' | 'permanently_failed' | 'skipped'; error_message?: string; retry_count?: number; next_retry_at?: string; created_at: string; } function formatRelativeDate(dateStr: string): string { const d = new Date(dateStr); const now = new Date(); const diffMs = now.getTime() - d.getTime(); const diffMins = Math.floor(diffMs / 60000); const diffHours = Math.floor(diffMs / 3600000); const diffDays = Math.floor(diffMs / 86400000); if (diffMins < 60) return `${diffMins} mins ago`; if (diffHours < 24) return `${diffHours} hour${diffHours > 1 ? 's' : ''} ago`; if (diffDays < 7) return `${diffDays} day${diffDays > 1 ? 's' : ''} ago`; return d.toLocaleDateString(); } function mapOrderToPurchases(order: OrderApi): Purchase[] { const orderId = typeof order.id === 'string' ? order.id : String(order.id); const dateStr = order.created_at ? new Date(order.created_at).toISOString().slice(0, 10) : ''; const items = order.items ?? []; if (items.length === 0) { const total = order.total_amount ?? order.total ?? 0; return [ { id: orderId, orderId, date: dateStr, price: total, status: order.status, downloadUrl: '#', license: { id: 'lic-default', name: 'Standard', price: total, features: [] }, product: { id: 'unknown', title: 'Order', type: 'pack', price: total, currency: 'USD', coverUrl: '', } as Partial as Product, }, ]; } return items.map((item, idx) => { const productId = item.product_id ?? 'unknown'; const price = item.price ?? 0; const title = item.title ?? productId; return { id: `${orderId}-${item.id ?? idx}`, orderId, date: dateStr, price, status: order.status, downloadUrl: '#', license: { id: `lic-${productId}`, name: 'Standard', price, features: [] }, product: { id: productId, title, type: 'pack', price, currency: 'USD', coverUrl: '', } as Partial as Product, }; }); } export const commerceService = { getPurchases: async (): Promise => { const response = await apiClient.get('/marketplace/orders'); const orders = Array.isArray(response.data) ? response.data : []; return orders.flatMap(mapOrderToPurchases); }, // v0.401 M3: Real API call to GET /sell/sales getSales: async () => { const response = await apiClient.get<{ data?: { sales?: SellerSale[] }; sales?: SellerSale[] }>('/sell/sales'); const data = response.data?.data ?? response.data; const sales = (data as { sales?: SellerSale[] })?.sales ?? []; return sales.map((s) => ({ id: s.order_id, product: s.product_title, date: formatRelativeDate(s.date), amount: s.amount, buyer: s.buyer_id?.slice(0, 8) ?? '—', })); }, getSellerStats: async () => { const response = await apiClient.get<{ data?: { revenue?: number; sales?: number; sales_count?: number } }>( '/sell/stats' ); const data = (response.data?.data ?? response.data) as Record | undefined; return { revenue: (data?.revenue as number) ?? 0, sales: (data?.sales_count ?? data?.sales) as number ?? 0, views: 0, conversion: null as number | null, }; }, // v0.401 M3: Stats evolution for chart getSellerStatsEvolution: async (period: 'day' | 'week' | 'month' = 'week') => { const response = await apiClient.get<{ data?: { evolution?: StatsEvolutionPoint[] }; evolution?: StatsEvolutionPoint[] }>( `/sell/stats/evolution?period=${period}` ); const data = response.data?.data ?? response.data; return (data as { evolution?: StatsEvolutionPoint[] })?.evolution ?? []; }, // v0.401 M3: Top products by revenue getSellerTopProducts: async (limit = 10) => { const response = await apiClient.get<{ data?: { top_products?: TopProductStats[] }; top_products?: TopProductStats[] }>( `/sell/stats/top-products?limit=${limit}` ); const data = response.data?.data ?? response.data; return (data as { top_products?: TopProductStats[] })?.top_products ?? []; }, requestRefund: async (orderId: string, reason: string) => { await apiClient.post(`/marketplace/orders/${orderId}/refund`, { reason: reason || 'Requested by customer', details: '', }); return { success: true }; }, // v0.602 P3: Stripe Connect seller balance (amounts in cents from API, returned in euros) getSellerBalance: async (): Promise<{ connected: boolean; available: number; pending: number }> => { const res = await apiClient.get<{ data?: { connected?: boolean; available?: number; pending?: number }; }>('/sell/balance'); const data = res.data?.data ?? res.data; const raw = data as { connected?: boolean; available?: number; pending?: number }; return { connected: raw?.connected ?? false, available: (raw?.available ?? 0) / 100, pending: (raw?.pending ?? 0) / 100, }; }, // v0.603: Seller transfer history getSellerTransfers: async (): Promise => { const res = await apiClient.get<{ data?: SellerTransfer[] }>('/sell/transfers'); return (res.data?.data ?? []) as SellerTransfer[]; }, // v0.701: Admin transfer management getAdminTransfers: async (params?: { status?: string; seller_id?: string; from?: string; to?: string; limit?: number; offset?: number; }): Promise<{ transfers: SellerTransfer[]; total: number }> => { const res = await apiClient.get<{ data?: { transfers: SellerTransfer[]; total: number } }>( '/admin/transfers', { params } ); return (res.data?.data ?? { transfers: [], total: 0 }) as { transfers: SellerTransfer[]; total: number; }; }, retryAdminTransfer: async (transferId: string): Promise => { const res = await apiClient.post<{ data?: SellerTransfer }>( `/admin/transfers/${transferId}/retry` ); return (res.data?.data ?? res.data) as SellerTransfer; }, // v0.602 P3: Stripe Connect onboarding connectStripeOnboard: async (): Promise<{ onboarding_url: string }> => { const res = await apiClient.post<{ data?: { onboarding_url?: string } }>('/sell/connect/onboard', {}); const data = res.data?.data ?? res.data; return { onboarding_url: (data as { onboarding_url?: string })?.onboarding_url ?? '', }; }, };