import 'dart:math';
import '../../../core/constants/app_constants.dart';
import '../entities/exercise.dart';

class XPCalculator {
  /// Calculate level from total XP
  static int calculateLevelFromXP(int xp) {
    int level = 1;
    while (level <= AppConstants.maxLevel) {
      final requiredXP = xpRequiredForLevel(level + 1);
      if (xp < requiredXP) {
        return level;
      }
      level++;
    }
    return AppConstants.maxLevel;
  }

  /// Calculate XP required to reach a specific level
  static int xpRequiredForLevel(int level) {
    if (level <= 1) return 0;
    return (AppConstants.baseXP * 
            pow(AppConstants.xpMultiplier, level - 1)).round();
  }

  /// Calculate XP for next level
  static int xpForNextLevel(int currentLevel) {
    return xpRequiredForLevel(currentLevel + 1);
  }

  /// Calculate XP progress percentage
  static double xpProgressPercentage(int currentXP, int currentLevel) {
    final currentLevelXP = xpRequiredForLevel(currentLevel);
    final nextLevelXP = xpRequiredForLevel(currentLevel + 1);
    final xpInCurrentLevel = currentXP - currentLevelXP;
    final xpNeededForLevel = nextLevelXP - currentLevelXP;
    
    if (xpNeededForLevel <= 0) return 1.0;
    return (xpInCurrentLevel / xpNeededForLevel).clamp(0.0, 1.0);
  }

  /// Calculate XP earned from a completed workout
  static int calculateWorkoutXP(List<Exercise> exercises, {bool isPR = false}) {
    int totalXP = AppConstants.workoutCompleteXP; // Base completion bonus

    for (final exercise in exercises) {
      for (final set in exercise.sets) {
        if (!set.completed) continue;

        // Volume XP: 0.1 XP per kg moved
        final volume = set.targetWeightTotal * set.repsActual;
        totalXP += (volume * AppConstants.volumeXPRate).round();

        // AMRAP bonus: 25 XP per extra rep
        if (set.isAmrap) {
          final extraReps = set.repsActual - set.repsTarget;
          if (extraReps > 0) {
            totalXP += extraReps * AppConstants.amrapBonusXPPerRep;
          }
        }
      }
    }

    // PR bonus
    if (isPR) {
      totalXP += AppConstants.prBonusXP;
    }

    return totalXP;
  }

  /// Add XP and check for level up
  static LevelUpResult addXP({
    required int currentXP,
    required int currentLevel,
    required int xpToAdd,
  }) {
    int newXP = currentXP + xpToAdd;
    int newLevel = currentLevel;
    final levelsGained = <int>[];

    while (newLevel < AppConstants.maxLevel) {
      final requiredForNext = xpRequiredForLevel(newLevel + 1);
      if (newXP >= requiredForNext) {
        newLevel++;
        levelsGained.add(newLevel);
      } else {
        break;
      }
    }

    return LevelUpResult(
      newXP: newXP,
      newLevel: newLevel,
      levelsGained: levelsGained,
      xpForNextLevel: xpRequiredForLevel(newLevel + 1),
    );
  }
}

class LevelUpResult {
  final int newXP;
  final int newLevel;
  final List<int> levelsGained;
  final int xpForNextLevel;

  LevelUpResult({
    required this.newXP,
    required this.newLevel,
    required this.levelsGained,
    required this.xpForNextLevel,
  });

  bool get didLevelUp => levelsGained.isNotEmpty;
}

