// food_service.dart — طبقة الاتصال بـ backend/food (جهة الراكب) import 'dart:convert'; import '../functions/crud.dart'; import '../../constant/links.dart'; import 'food_models.dart'; class FoodApiResult { final bool success; final T? data; final String message; final int? code; FoodApiResult(this.success, this.data, this.message, {this.code}); } class FoodService { static String get _base => '${AppLink.server}/food'; static Future>> browseMerchants({ required String city, String? category, }) async { final payload = {'city': city}; if (category != null && category.isNotEmpty) payload['category'] = category; final res = await CRUD().post(link: '$_base/merchant/browse.php', payload: payload); if (res is Map && res['status'] == 'success') { final msg = res['message']; final list = (msg is Map && msg['merchants'] is List) ? (msg['merchants'] as List) .map((m) => FoodMerchant.fromJson(Map.from(m))) .toList() : []; return FoodApiResult(true, list, 'ok'); } return FoodApiResult(false, null, _errMsg(res)); } static Future>> searchMerchants({ required String city, required String query, }) async { final res = await CRUD().post( link: '$_base/merchant/search.php', payload: {'city': city, 'q': query}, ); if (res is Map && res['status'] == 'success') { final msg = res['message']; final list = (msg is Map && msg['merchants'] is List) ? (msg['merchants'] as List) .map((m) => FoodMerchant.fromJson(Map.from(m))) .toList() : []; return FoodApiResult(true, list, 'ok'); } return FoodApiResult(false, null, _errMsg(res)); } static Future>> merchantDetails(int merchantId) async { final res = await CRUD().post( link: '$_base/merchant/details.php', payload: {'merchant_id': merchantId.toString()}, ); if (res is Map && res['status'] == 'success') { final msg = res['message']; if (msg is Map) { final merchant = FoodMerchant.fromJson(Map.from(msg['merchant'])); final categories = (msg['categories'] is List) ? (msg['categories'] as List) .map((c) => FoodMenuCategory.fromJson(Map.from(c))) .toList() : []; return FoodApiResult(true, {'merchant': merchant, 'categories': categories}, 'ok'); } } return FoodApiResult(false, null, _errMsg(res)); } static Future> getQuote({ required int merchantId, required List lines, }) async { final res = await CRUD().post( link: '$_base/cart/quote.php', payload: { 'merchant_id': merchantId.toString(), 'items': jsonEncode(lines.map((l) => l.toQuotePayload()).toList()), }, ); if (res is Map && res['status'] == 'success') { final msg = res['message']; if (msg is Map) return FoodApiResult(true, FoodQuote.fromJson(Map.from(msg)), 'ok'); } return FoodApiResult(false, null, _errMsg(res), code: _errCode(res)); } static Future> createOrder({ required String quoteToken, required String clientOrderUuid, required String deliveryAddress, required double deliveryLat, required double deliveryLng, required String paymentMethod, // wallet | cash String? customerNote, }) async { final res = await CRUD().post( link: '$_base/order/create.php', payload: { 'quote_token': quoteToken, 'client_order_uuid': clientOrderUuid, 'delivery_address': deliveryAddress, 'delivery_lat': deliveryLat.toString(), 'delivery_lng': deliveryLng.toString(), 'payment_method': paymentMethod, if (customerNote != null && customerNote.isNotEmpty) 'customer_note': customerNote, }, ); if (res is Map && res['status'] == 'success') { final msg = res['message']; if (msg is Map && msg['order_id'] != null) { return FoodApiResult(true, int.tryParse(msg['order_id'].toString()) ?? 0, 'ok'); } } return FoodApiResult(false, null, _errMsg(res), code: _errCode(res)); } static Future> getOrderStatus(int orderId) async { final res = await CRUD().post( link: '$_base/order/status.php', payload: {'order_id': orderId.toString()}, ); if (res is Map && res['status'] == 'success') { final msg = res['message']; if (msg is Map && msg['order'] is Map) { return FoodApiResult(true, FoodOrder.fromJson(Map.from(msg['order'])), 'ok'); } } return FoodApiResult(false, null, _errMsg(res)); } static Future> cancelOrder(int orderId, {String? reason}) async { final res = await CRUD().post( link: '$_base/order/cancel.php', payload: {'order_id': orderId.toString(), if (reason != null) 'reason': reason}, ); if (res is Map && res['status'] == 'success') return FoodApiResult(true, null, 'ok'); return FoodApiResult(false, null, _errMsg(res)); } static Future> rateOrder(int orderId, int rating, {String? comment}) async { final res = await CRUD().post( link: '$_base/order/rate.php', payload: { 'order_id': orderId.toString(), 'rating': rating.toString(), if (comment != null && comment.isNotEmpty) 'comment': comment, }, ); if (res is Map && res['status'] == 'success') return FoodApiResult(true, null, 'ok'); return FoodApiResult(false, null, _errMsg(res)); } static Future>> getHistory({int page = 1}) async { final res = await CRUD().post( link: '$_base/order/history.php', payload: {'page': page.toString()}, ); if (res is Map && res['status'] == 'success') { final msg = res['message']; final list = (msg is Map && msg['orders'] is List) ? (msg['orders'] as List) .map((o) => FoodOrder.fromJson(Map.from(o))) .toList() : []; return FoodApiResult(true, list, 'ok'); } return FoodApiResult(false, null, _errMsg(res)); } static int? _errCode(dynamic res) { if (res is Map && res['code'] != null) return int.tryParse(res['code'].toString()); return null; } static String _errMsg(dynamic res) { if (res == 'no_internet') return 'تحقق من اتصالك بالإنترنت'; if (res == 'token_expired') return 'انتهت الجلسة، حاول مجدداً'; if (res is Map && res['message'] is String) return res['message']; return 'حدث خطأ، حاول مجدداً'; } }