// lib/features/gamification/services/gamification_service.dart // // Real API service for the Contributor / Gamification module. // Calls the Node.js gamification server at app.eventifyplus.com. import '../../../core/api/api_client.dart'; import '../../../core/api/api_endpoints.dart'; import '../../../core/storage/token_storage.dart'; import '../models/gamification_models.dart'; class GamificationService { final ApiClient _api = ApiClient(); /// Helper: get current user's email for API calls. Future _getUserEmail() async { final email = await TokenStorage.getUsername(); return email ?? ''; } // --------------------------------------------------------------------------- // Dashboard (profile + submissions) // GET /v1/gamification/dashboard?user_id={email} // --------------------------------------------------------------------------- Future getDashboard() async { final email = await _getUserEmail(); final url = '${ApiEndpoints.gamificationDashboard}?user_id=$email'; final res = await _api.post(url, requiresAuth: false); final profileJson = res['profile'] as Map? ?? {}; final rawSubs = res['submissions'] as List? ?? []; final rawAchievements = res['achievements'] as List? ?? []; final submissions = rawSubs .map((s) => SubmissionModel.fromJson(Map.from(s as Map))) .toList(); final achievements = rawAchievements .map((a) => AchievementBadge.fromJson(Map.from(a as Map))) .toList(); return DashboardResponse( profile: UserGamificationProfile.fromJson(profileJson), submissions: submissions, achievements: achievements, ); } /// Convenience — returns just the profile (backward-compatible with provider). Future getProfile() async { final dashboard = await getDashboard(); return dashboard.profile; } // --------------------------------------------------------------------------- // Leaderboard // GET /v1/gamification/leaderboard?period=all|month&district=X&user_id=Y&limit=50 // --------------------------------------------------------------------------- Future getLeaderboard({ required String district, required String timePeriod, }) async { final email = await _getUserEmail(); // Map Flutter filter values to API params final period = timePeriod == 'this_month' ? 'month' : 'all'; final params = { 'period': period, 'user_id': email, 'limit': '50', }; if (district != 'Overall Kerala') { params['district'] = district; } final query = Uri(queryParameters: params).query; final url = '${ApiEndpoints.leaderboard}?$query'; final res = await _api.post(url, requiresAuth: false); final rawList = res['leaderboard'] as List? ?? []; final entries = rawList .map((e) => LeaderboardEntry.fromJson(Map.from(e as Map))) .toList(); CurrentUserStats? currentUser; if (res['currentUser'] != null && res['currentUser'] is Map) { currentUser = CurrentUserStats.fromJson( Map.from(res['currentUser'] as Map), ); } return LeaderboardResponse( entries: entries, currentUser: currentUser, totalParticipants: (res['totalParticipants'] as num?)?.toInt() ?? entries.length, ); } // --------------------------------------------------------------------------- // Shop Items // GET /v1/shop/items // --------------------------------------------------------------------------- Future> getShopItems() async { final res = await _api.post(ApiEndpoints.shopItems, requiresAuth: false); final rawItems = res['items'] as List? ?? []; return rawItems .map((e) => ShopItem.fromJson(Map.from(e as Map))) .toList(); } // --------------------------------------------------------------------------- // Redeem Item // POST /v1/shop/redeem body: { user_id, item_id } // --------------------------------------------------------------------------- Future redeemItem(String itemId) async { final email = await _getUserEmail(); final res = await _api.post( ApiEndpoints.shopRedeem, body: {'user_id': email, 'item_id': itemId}, requiresAuth: false, ); final voucher = res['voucher'] as Map? ?? res; return RedemptionRecord.fromJson(Map.from(voucher)); } // --------------------------------------------------------------------------- // Submit Contribution // POST /v1/gamification/submit-event body: event data // --------------------------------------------------------------------------- Future submitContribution(Map data) async { final email = await _getUserEmail(); final body = {'user_id': email, ...data}; await _api.post( ApiEndpoints.contributeSubmit, body: body, requiresAuth: false, ); } // --------------------------------------------------------------------------- // Achievements — sourced from dashboard API `achievements` array. // Falls back to default badges if API doesn't return achievements yet. // --------------------------------------------------------------------------- Future> getAchievements() async { try { final dashboard = await getDashboard(); if (dashboard.achievements.isNotEmpty) return dashboard.achievements; } catch (_) { // Fall through to defaults } return _defaultBadges; } static const _defaultBadges = [ AchievementBadge(id: 'badge-01', title: 'First Submission', description: 'Submitted your first event.', iconName: 'edit', isUnlocked: false, progress: 0.0), AchievementBadge(id: 'badge-02', title: 'Silver Streak', description: 'Reached Silver tier.', iconName: 'star', isUnlocked: false, progress: 0.0), AchievementBadge(id: 'badge-03', title: 'Gold Rush', description: 'Reach Gold tier (500 EP).', iconName: 'emoji_events', isUnlocked: false, progress: 0.0), AchievementBadge(id: 'badge-04', title: 'Top 10', description: 'Appear in the district leaderboard top 10.', iconName: 'leaderboard', isUnlocked: false, progress: 0.0), AchievementBadge(id: 'badge-05', title: 'Image Pro', description: 'Submit 10 events with 3+ images.', iconName: 'photo_library', isUnlocked: false, progress: 0.0), AchievementBadge(id: 'badge-06', title: 'Pioneer', description: 'One of the first 100 contributors.', iconName: 'verified', isUnlocked: false, progress: 0.0), ]; }