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

enum ExerciseType {
  // Main Lifts
  squat,
  pullup,
  dip,
  row,
  bench,

  // Hypertrophy Accessories
  deadliftRomanian,
  curlBarbell,
  pressOverhead,
  facePull,
  abWheel,
  plank,

  // Conditioning (Kettlebell)
  kbSwing,
  kbSnatch,
  kbThruster,
  kbCleanPress,

  // pullup journey
  scapularPull,
  invertedRow,
  negativePullup,
}

enum AccessoryTemplate { none, hypertrophy, conditioning, journeyPullup }

class WendlerCalculator {
  static const Map<int, List<double>> weekPercentages = {
    1: [0.65, 0.75, 0.85],
    2: [0.70, 0.80, 0.90],
    3: [0.75, 0.85, 0.95],
    4: [0.40, 0.50, 0.60],
  };

  static const Map<int, List<int>> weekReps = {
    1: [5, 5, 5],
    2: [3, 3, 3],
    3: [5, 3, 1],
    4: [5, 5, 5],
  };

  static List<WorkoutSet> generateSets({
    required int week,
    required double trainingMax,
    required ExerciseType exerciseType,
    required double currentBodyweight,
  }) {
    final percentages = weekPercentages[week]!;
    final reps = weekReps[week]!;
    final sets = <WorkoutSet>[];

    for (int i = 0; i < 3; i++) {
      final targetTotal = trainingMax * percentages[i];
      final rounded = _roundWeight(targetTotal, exerciseType);

      double plateWeight = 0;
      if (exerciseType != ExerciseType.squat ||
          exerciseType != ExerciseType.row ||
          exerciseType != ExerciseType.bench) {
        plateWeight = max(0, rounded - currentBodyweight);
      }

      sets.add(WorkoutSet(
        setNumber: i + 1,
        targetPercentage: (percentages[i] * 100).round(),
        targetWeightTotal: rounded,
        plateWeight: plateWeight,
        repsTarget: reps[i],
        isAmrap: (i == 2 && week != 4),
      ));
    }

    return sets;
  }

  static List<WorkoutSet> generateLinearSets({
    required double trainingMax,
    required ExerciseType exerciseType,
    required double currentBodyweight,
    int setsCount = 3,
    int repsCount = 5,
  }) {
    final sets = <WorkoutSet>[];

    final targetTotal = _roundWeight(trainingMax, exerciseType);

    double plateWeight = 0;

    for (int i = 0; i < setsCount; i++) {
      sets.add(WorkoutSet(
        setNumber: i + 1,
        targetPercentage: 100,
        targetWeightTotal: targetTotal,
        plateWeight: plateWeight,
        repsTarget: repsCount,
        repsActual: 0,
        isAmrap: (i == setsCount - 1),
      ));
    }

    return sets;
  }

  static double _roundWeight(double weight, ExerciseType type) {
    final step = (type == ExerciseType.squat ||
            type == ExerciseType.row ||
            type == ExerciseType.bench)
        ? AppConstants.squatRoundingStep
        : AppConstants.calisthenicsRoundingStep;
    return (weight / step).floor() * step;
  }

  static double calculate1RM(double weight, int reps) {
    if (reps == 1) return weight;
    return weight * (1 + reps / 30.0);
  }

  static double calculateTrainingMax(double oneRM) {
    return oneRM * AppConstants.trainingMaxPercentage;
  }

  static double progressTrainingMax(double currentTM, ExerciseType type) {
    if (type == ExerciseType.squat) {
      return currentTM + AppConstants.lowerBodyIncrement;
    }
    return currentTM + AppConstants.upperBodyIncrement;
  }

  static List<WorkoutSet> generateFSLSets({
    required double trainingMax,
    required ExerciseType exerciseType,
    required double currentBodyweight,
  }) {
    final sets = <WorkoutSet>[];
    final firstSetPercentage = 0.65;

    final targetTotal = trainingMax * firstSetPercentage;
    final rounded = _roundWeight(targetTotal, exerciseType);

    double plateWeight = 0;
    if (exerciseType != ExerciseType.squat ||
        exerciseType != ExerciseType.row ||
        exerciseType != ExerciseType.bench) {
      plateWeight = max(0, rounded - currentBodyweight);
    }

    for (int i = 0; i < 5; i++) {
      sets.add(WorkoutSet(
        setNumber: i + 1,
        targetPercentage: 65,
        targetWeightTotal: rounded,
        plateWeight: plateWeight,
        repsTarget: 5,
        isAmrap: false,
      ));
    }

    return sets;
  }
}
