// lib/features/gamification/providers/gamification_provider.dart

import 'package:flutter/foundation.dart';
import '../../../core/utils/error_utils.dart';
import '../models/gamification_models.dart';
import '../services/gamification_service.dart';
import '../../events/services/events_service.dart';
import '../../events/models/event_models.dart';

class GamificationProvider extends ChangeNotifier {
  final GamificationService _service = GamificationService();

  // State
  UserGamificationProfile? profile;
  List<LeaderboardEntry> leaderboard = [];
  List<ShopItem> shopItems = [];
  List<AchievementBadge> achievements = GamificationService.defaultBadges; // Initialize with defaults
  List<SubmissionModel> submissions = [];
  CurrentUserStats? currentUserStats;
  int totalParticipants = 0;
  List<String> eventCategories = [];

  // Leaderboard filters — matches web version
  String leaderboardDistrict = 'Overall Kerala';
  String leaderboardTimePeriod = 'all_time'; // 'all_time' | 'this_month'

  bool isLoading = false;
  bool isLeaderboardLoading = false;
  String? error;

  // TTL guard — prevents redundant API calls from multiple screens
  DateTime? _lastLoadTime;
  static const _loadTtl = Duration(minutes: 2);

  // ---------------------------------------------------------------------------
  // Load everything at once (called when ContributeScreen or ProfileScreen mounts)
  // ---------------------------------------------------------------------------
  Future<void> loadAll({bool force = false}) async {
    // Skip if recently loaded (within 2 minutes) unless forced
    if (!force && _lastLoadTime != null && DateTime.now().difference(_lastLoadTime!) < _loadTtl) {
      return;
    }

    isLoading = true;
    error = null;
    notifyListeners();

    try {
      final results = await Future.wait([
        _service.getDashboard().catchError((e) {
          debugPrint('Dashboard error: $e');
          return const DashboardResponse(profile: UserGamificationProfile(userId: '', lifetimeEp: 0, currentEp: 0, currentRp: 0, tier: ContributorTier.BRONZE));
        }),
        _service.getLeaderboard(district: leaderboardDistrict, timePeriod: leaderboardTimePeriod).catchError((e) {
          debugPrint('Leaderboard error: $e');
          return const LeaderboardResponse(entries: []);
        }),
        _service.getShopItems().catchError((e) {
          debugPrint('Shop error: $e');
          return <ShopItem>[];
        }),
        _service.getAchievements().catchError((e) {
          debugPrint('Achievements error: $e');
          return <AchievementBadge>[];
        }),
        EventsService().getEventTypes().catchError((e) {
          debugPrint('EventTypes error: $e');
          return <EventTypeModel>[];
        }),
      ]);

      final dashboard = results[0] as DashboardResponse;
      profile = dashboard.profile;
      submissions = dashboard.submissions;

      final lbResponse = results[1] as LeaderboardResponse;
      leaderboard = _filterAndReRank(lbResponse.entries, leaderboardDistrict, leaderboardTimePeriod);
      currentUserStats = lbResponse.currentUser;
      totalParticipants = lbResponse.totalParticipants;

      shopItems = results[2] as List<ShopItem>;

      // Prefer achievements from dashboard API; fall back to fetched or existing defaults
      final dashAchievements = dashboard.achievements;
      final fetchedAchievements = results[3] as List<AchievementBadge>;

      if (dashAchievements.isNotEmpty) {
        achievements = dashAchievements;
      } else if (fetchedAchievements.isNotEmpty) {
        achievements = fetchedAchievements;
      }
      
      final eventTypes = results[4] as List<EventTypeModel>;
      if (eventTypes.isNotEmpty) {
        eventCategories = eventTypes.map((e) => e.name).toList();
      }
      // Otherwise, keep current defaults

      _lastLoadTime = DateTime.now();
    } catch (e) {
      error = userFriendlyError(e);
    } finally {
      isLoading = false;
      notifyListeners();
    }
  }

  // ---------------------------------------------------------------------------
  // Load leaderboard independently (decoupled from loadAll)
  // ---------------------------------------------------------------------------
  Future<void> loadLeaderboard() async {
    isLeaderboardLoading = true;
    notifyListeners();
    try {
      final response = await _service.getLeaderboard(
        district: leaderboardDistrict,
        timePeriod: leaderboardTimePeriod,
      );
      leaderboard = response.entries;
      currentUserStats = response.currentUser;
      totalParticipants = response.totalParticipants;
    } catch (e) {
      error = userFriendlyError(e);
    } finally {
      isLeaderboardLoading = false;
      notifyListeners();
    }
  }

  // ---------------------------------------------------------------------------
  // Change district filter
  // ---------------------------------------------------------------------------
  Future<void> setDistrict(String district) async {
    if (leaderboardDistrict == district) return;
    leaderboardDistrict = district;
    isLeaderboardLoading = true;
    notifyListeners();
    try {
      final response = await _service.getLeaderboard(district: district, timePeriod: leaderboardTimePeriod);
      leaderboard = _filterAndReRank(response.entries, district, leaderboardTimePeriod);
      currentUserStats = response.currentUser;
      totalParticipants = response.totalParticipants;
    } catch (e) {
      error = userFriendlyError(e);
    } finally {
      isLeaderboardLoading = false;
    }
    notifyListeners();
  }

  // ---------------------------------------------------------------------------
  // Change time period filter
  // ---------------------------------------------------------------------------
  Future<void> setTimePeriod(String period) async {
    if (leaderboardTimePeriod == period) return;
    leaderboardTimePeriod = period;
    isLeaderboardLoading = true;
    notifyListeners();
    try {
      final response = await _service.getLeaderboard(district: leaderboardDistrict, timePeriod: period);
      leaderboard = _filterAndReRank(response.entries, leaderboardDistrict, period);
      currentUserStats = response.currentUser;
      totalParticipants = response.totalParticipants;
    } catch (e) {
      error = userFriendlyError(e);
    } finally {
      isLeaderboardLoading = false;
    }
    notifyListeners();
  }

  // ---------------------------------------------------------------------------
  // Redeem a shop item — deducts RP locally optimistically, returns voucher code
  // ---------------------------------------------------------------------------
  Future<String> redeemItem(String itemId) async {
    final item = shopItems.firstWhere((s) => s.id == itemId);

    // Optimistically deduct RP
    if (profile != null) {
      profile = UserGamificationProfile(
        userId: profile!.userId,
        lifetimeEp: profile!.lifetimeEp,
        currentEp: profile!.currentEp,
        currentRp: profile!.currentRp - item.rpCost,
        tier: profile!.tier,
      );
      notifyListeners();
    }

    try {
      final record = await _service.redeemItem(itemId);
      return record.voucherCode;
    } catch (e) {
      // Rollback on failure
      if (profile != null) {
        profile = UserGamificationProfile(
          userId: profile!.userId,
          lifetimeEp: profile!.lifetimeEp,
          currentEp: profile!.currentEp,
          currentRp: profile!.currentRp + item.rpCost,
          tier: profile!.tier,
        );
        notifyListeners();
      }
      rethrow;
    }
  }

  // ---------------------------------------------------------------------------
  // Submit a contribution
  // ---------------------------------------------------------------------------
  Future<void> submitContribution(Map<String, dynamic> data) async {
    await _service.submitContribution(data);
  }

  // ---------------------------------------------------------------------------
  // Helper: Filter by district and re-rank results locally.
  // This is a fallback in case the backend returns a global list for a district-specific query.
  // ---------------------------------------------------------------------------
  List<LeaderboardEntry> _filterAndReRank(List<LeaderboardEntry> entries, String district, String period) {
    if (entries.isEmpty) return [];
    
    List<LeaderboardEntry> result = entries;
    if (district != 'Overall Kerala') {
      // Case-insensitive filtering to be robust
      result = entries.where((e) => e.district?.toLowerCase() == district.toLowerCase()).toList();
    }
    
    // Sort based on period
    if (period == 'this_month') {
      result.sort((a, b) => b.monthlyPoints.compareTo(a.monthlyPoints));
    } else {
      result.sort((a, b) => b.lifetimeEp.compareTo(a.lifetimeEp));
    }
    
    // Assign new ranks based on local sort order
    return List.generate(result.length, (i) {
      final e = result[i];
      return LeaderboardEntry(
        rank: i + 1,
        username: e.username,
        avatarUrl: e.avatarUrl,
        lifetimeEp: e.lifetimeEp,
        monthlyPoints: e.monthlyPoints,
        tier: e.tier,
        eventsCount: e.eventsCount,
        isCurrentUser: e.isCurrentUser,
        district: e.district,
      );
    });
  }
}
