// food_delivery_service.dart — طبقة الاتصال بـ backend/food (جهة السائق/الموصّل) import '../functions/crud.dart'; import '../../constant/links.dart'; import 'food_delivery_models.dart'; class FoodDeliveryApiResult { final bool success; final T? data; final String message; FoodDeliveryApiResult(this.success, this.data, this.message); } class FoodDeliveryService { static String get _base => '${AppLink.server}/food'; static Future> toggleAvailability(bool enabled) async { final res = await CRUD().post( link: '$_base/courier/toggle_availability.php', payload: {'enabled': enabled.toString()}, ); if (res is Map && res['status'] == 'success') return FoodDeliveryApiResult(true, enabled, 'ok'); return FoodDeliveryApiResult(false, null, _errMsg(res)); } /// حالة السائق عند فتح التبويب — وضع التوصيل مخزَّن في Redis على الخادم، /// فلا يجوز افتراض "مغلق" محلياً وإلا ظهر التبديل مطفأً والعروض تصل فعلاً. static Future> getStatus() async { final res = await CRUD().post(link: '$_base/courier/status.php'); final msg = _payload(res); if (msg != null) { return FoodDeliveryApiResult(true, FoodCourierStatus.fromJson(msg), 'ok'); } return FoodDeliveryApiResult(false, null, _errMsg(res)); } static Future>> getActiveTasks() async { final res = await CRUD().post(link: '$_base/courier/active.php'); final msg = _payload(res); if (msg != null) { return FoodDeliveryApiResult(true, _list(msg['orders'], FoodDeliveryTask.fromJson), 'ok'); } return FoodDeliveryApiResult(false, null, _errMsg(res)); } static Future>> getPendingOffers() async { final res = await CRUD().post(link: '$_base/courier/pending_offers.php'); final msg = _payload(res); if (msg != null) { return FoodDeliveryApiResult(true, _list(msg['offers'], FoodDeliveryOffer.fromJson), 'ok'); } return FoodDeliveryApiResult(false, null, _errMsg(res)); } static Future> getOrderDetails(int orderId) async { final res = await CRUD().post( link: '$_base/courier/order_details.php', payload: {'order_id': orderId.toString()}, ); final msg = _payload(res); if (msg != null && msg['order'] is Map) { return FoodDeliveryApiResult( true, FoodOrderDetails.fromJson(Map.from(msg['order'])), 'ok'); } return FoodDeliveryApiResult(false, null, _errMsg(res)); } static Future> getEarnings() async { final res = await CRUD().post(link: '$_base/courier/earnings.php'); final msg = _payload(res); if (msg != null) return FoodDeliveryApiResult(true, FoodEarnings.fromJson(msg), 'ok'); return FoodDeliveryApiResult(false, null, _errMsg(res)); } static Future>> getHistory({ int limit = 20, int offset = 0, }) async { final res = await CRUD().post( link: '$_base/courier/history.php', payload: {'limit': limit.toString(), 'offset': offset.toString()}, ); final msg = _payload(res); if (msg != null) { return FoodDeliveryApiResult(true, _list(msg['orders'], FoodHistoryEntry.fromJson), 'ok'); } return FoodDeliveryApiResult(false, null, _errMsg(res)); } static Future> respondToOffer(int orderId, bool accept) async { final res = await CRUD().post( link: '$_base/courier/offer_respond.php', payload: {'order_id': orderId.toString(), 'response': accept ? 'accept' : 'reject'}, ); final msg = _payload(res); if (msg != null) { return FoodDeliveryApiResult(true, msg['response']?.toString() ?? '', 'ok'); } return FoodDeliveryApiResult(false, null, _errMsg(res)); } /// بثّ موقع السائق للزبون أثناء المهمة. الخادم يرفضه بعد التسليم، /// وينتهي آخر موقع من Redis تلقائياً — لا تتبّع خارج نافذة العمل. static Future sendLocation({ required int orderId, required double lat, required double lng, double? heading, }) async { await CRUD().post( link: '$_base/courier/location.php', payload: { 'order_id': orderId.toString(), 'lat': lat.toString(), 'lng': lng.toString(), if (heading != null) 'heading': heading.toStringAsFixed(0), }, ); } static Future> markPickedUp(int orderId) async { final res = await CRUD().post( link: '$_base/courier/picked_up.php', payload: {'order_id': orderId.toString()}, ); if (res is Map && res['status'] == 'success') return FoodDeliveryApiResult(true, null, 'ok'); return FoodDeliveryApiResult(false, null, _errMsg(res)); } static Future> markDelivered(int orderId) async { final res = await CRUD().post( link: '$_base/courier/delivered.php', payload: {'order_id': orderId.toString()}, ); if (res is Map && res['status'] == 'success') return FoodDeliveryApiResult(true, null, 'ok'); return FoodDeliveryApiResult(false, null, _errMsg(res)); } // كل ردود backend/food تأتي بغلاف {status, message:{...}} — نستخرج المحتوى مرة واحدة static Map? _payload(dynamic res) { if (res is Map && res['status'] == 'success' && res['message'] is Map) { return Map.from(res['message']); } return null; } static List _list(dynamic raw, T Function(Map) fromJson) { if (raw is! List) return []; return raw.map((e) => fromJson(Map.from(e))).toList(); } 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 'حدث خطأ، حاول مجدداً'; } }