import 'dart:convert'; import 'package:flutter/material.dart'; import 'package:get/get.dart'; import 'package:siro_driver/constant/box_name.dart'; import 'package:siro_driver/constant/links.dart'; import 'package:siro_driver/controller/functions/crud.dart'; import '../../../main.dart'; // ════════════════════════════════════════════ // نموذج التحدي // ════════════════════════════════════════════ class Challenge { final String id; final String titleEn; final String titleAr; final String descriptionEn; final String descriptionAr; final IconData icon; final Color color; final int target; final int reward; // نقاط final String type; // 'daily' or 'weekly' final String metric; // 'trips', 'earnings', 'hours', 'acceptance_rate' int currentProgress; bool isClaimed; Challenge({ required this.id, required this.titleEn, required this.titleAr, required this.descriptionEn, required this.descriptionAr, required this.icon, required this.color, required this.target, required this.reward, required this.type, required this.metric, this.currentProgress = 0, this.isClaimed = false, }); double get progress => (currentProgress / target).clamp(0.0, 1.0); bool get isCompleted => currentProgress >= target; } // ════════════════════════════════════════════ // Controller // ════════════════════════════════════════════ class ChallengesController extends GetxController { bool isLoading = false; List dailyChallenges = []; List weeklyChallenges = []; @override void onInit() { super.onInit(); _generateChallenges(); _loadProgress(); fetchChallengeProgress(); } void _generateChallenges() { final now = DateTime.now(); final isWeekend = now.weekday == 5 || now.weekday == 6; // الجمعة والسبت dailyChallenges = [ Challenge( id: 'daily_trips_5', titleEn: 'Road Runner', titleAr: 'سائق سريع', descriptionEn: 'Complete 5 trips today', descriptionAr: 'أكمل 5 رحلات اليوم', icon: Icons.local_taxi_rounded, color: const Color(0xFF2196F3), target: 5, reward: 50, type: 'daily', metric: 'trips', ), Challenge( id: 'daily_trips_10', titleEn: 'Marathon Driver', titleAr: 'سائق الماراثون', descriptionEn: 'Complete 10 trips today', descriptionAr: 'أكمل 10 رحلات اليوم', icon: Icons.directions_car_rounded, color: const Color(0xFFFF9800), target: 10, reward: 150, type: 'daily', metric: 'trips', ), Challenge( id: 'daily_earnings', titleEn: 'Money Maker', titleAr: 'صانع المال', descriptionEn: 'Earn 3000 SYP today', descriptionAr: 'اربح 3000 ل.س اليوم', icon: Icons.monetization_on_rounded, color: const Color(0xFF4CAF50), target: 3000, reward: 100, type: 'daily', metric: 'earnings', ), if (isWeekend) Challenge( id: 'daily_weekend_bonus', titleEn: 'Weekend Warrior', titleAr: 'محارب عطلة نهاية الأسبوع', descriptionEn: 'Complete 8 trips on the weekend', descriptionAr: 'أكمل 8 رحلات في عطلة نهاية الأسبوع', icon: Icons.celebration_rounded, color: const Color(0xFFE91E63), target: 8, reward: 200, type: 'daily', metric: 'trips', ), ]; weeklyChallenges = [ Challenge( id: 'weekly_trips_30', titleEn: 'Weekly Champion', titleAr: 'بطل الأسبوع', descriptionEn: 'Complete 30 trips this week', descriptionAr: 'أكمل 30 رحلة هذا الأسبوع', icon: Icons.emoji_events_rounded, color: const Color(0xFFFFD700), target: 30, reward: 300, type: 'weekly', metric: 'trips', ), Challenge( id: 'weekly_earnings', titleEn: 'Big Earner', titleAr: 'الربح الكبير', descriptionEn: 'Earn 20,000 SYP this week', descriptionAr: 'اربح 20,000 ل.س هذا الأسبوع', icon: Icons.account_balance_wallet_rounded, color: const Color(0xFF9C27B0), target: 20000, reward: 500, type: 'weekly', metric: 'earnings', ), Challenge( id: 'weekly_hours', titleEn: 'Time Master', titleAr: 'سيد الوقت', descriptionEn: 'Drive for 20 hours this week', descriptionAr: 'اقضِ 20 ساعة في القيادة هذا الأسبوع', icon: Icons.timer_rounded, color: const Color(0xFF00BCD4), target: 20, reward: 400, type: 'weekly', metric: 'hours', ), ]; } void _loadProgress() { final today = DateTime.now().toIso8601String().split('T')[0]; final savedDate = box.read('challenges_date'); if (savedDate != today) { // يوم جديد — إعادة تعيين التحديات اليومية box.write('challenges_date', today); for (var c in dailyChallenges) { box.write('challenge_${c.id}_claimed', false); } } // تحميل حالة المطالبة for (var c in dailyChallenges) { c.isClaimed = box.read('challenge_${c.id}_claimed') ?? false; } for (var c in weeklyChallenges) { c.isClaimed = box.read('challenge_${c.id}_claimed') ?? false; } } Future fetchChallengeProgress() async { isLoading = true; update(); try { // جلب رحلات اليوم var todayRes = await CRUD().getWallet( link: AppLink.getDriverPaymentToday, payload: {'driverID': box.read(BoxName.driverID).toString()}, ); int todayTrips = 0; double todayEarnings = 0; if (todayRes != null && todayRes != 'failure') { var data = jsonDecode(todayRes); todayEarnings = double.tryParse(data['message']?[0]?['todayAmount']?.toString() ?? '0') ?? 0; todayTrips = int.tryParse(data['message']?[0]?['todayCount']?.toString() ?? '0') ?? 0; } // تحديث التحديات اليومية for (var c in dailyChallenges) { switch (c.metric) { case 'trips': c.currentProgress = todayTrips; break; case 'earnings': c.currentProgress = todayEarnings.toInt(); break; } } // 2. Fetch weekly earnings from PAYMENT server var weeklyEarningsRes = await CRUD().getWallet( link: AppLink.getDriverWeekPaymentMove, payload: {'driverID': box.read(BoxName.driverID).toString()}, ); double weeklyEarnings = 0; if (weeklyEarningsRes != null && weeklyEarningsRes != 'failure') { var data = jsonDecode(weeklyEarningsRes); if (data['message'] is List && data['message'].isNotEmpty) { weeklyEarnings = double.tryParse(data['message'][0]['totalAmount']?.toString() ?? '0') ?? 0; } } // 3. Fetch weekly trips and hours from RIDES server (avoiding earnings join) var weeklyAggregateRes = await CRUD().get( link: AppLink.getWeeklyAggregate, payload: {'driver_id': box.read(BoxName.driverID).toString()}, ); int weeklyTrips = 0; double weeklyHours = 0; if (weeklyAggregateRes != null && weeklyAggregateRes != 'failure') { var data = jsonDecode(weeklyAggregateRes); if (data['message'] is List) { for (var day in data['message']) { weeklyTrips += int.tryParse(day['trips']?.toString() ?? '0') ?? 0; weeklyHours += double.tryParse(day['hours']?.toString() ?? '0') ?? 0; } } } for (var c in weeklyChallenges) { switch (c.metric) { case 'trips': c.currentProgress = weeklyTrips; break; case 'earnings': c.currentProgress = weeklyEarnings.toInt(); break; case 'hours': c.currentProgress = weeklyHours.toInt(); break; } } } catch (e) { debugPrint('❌ [Challenges] Error: $e'); } isLoading = false; update(); } Future claimReward(Challenge challenge) async { if (!challenge.isCompleted || challenge.isClaimed) return; try { var res = await CRUD().post( link: AppLink.claimChallengeReward, payload: { 'driver_id': box.read(BoxName.driverID).toString(), 'challenge_id': challenge.id, 'points': challenge.reward.toString(), }, ); if (res != null && res != 'failure') { challenge.isClaimed = true; box.write('challenge_${challenge.id}_claimed', true); debugPrint('🎉 Claimed ${challenge.reward} points for ${challenge.id}'); update(); } } catch (e) { debugPrint('❌ [Challenges] Claim error: $e'); } } }