import 'package:flutter_riverpod/flutter_riverpod.dart';
import 'package:slrpg_app/src/shared/data/local/app_database.dart';
import 'package:slrpg_app/src/shared/data/repositories/cycle_repository.dart';
import 'package:slrpg_app/src/shared/data/repositories/user_repository.dart';
import 'package:slrpg_app/src/shared/data/repositories/workout_repository.dart';
import 'package:slrpg_app/src/shared/domain/entities/exercise.dart';
import 'package:slrpg_app/src/shared/domain/entities/workout_set.dart';
import 'package:slrpg_app/src/shared/domain/logic/wendler_calculator.dart';

final workoutLoaderServiceProvider =
    Provider((ref) => WorkoutLoaderService(ref));

class WorkoutLoaderService {
  final Ref _ref;

  WorkoutLoaderService(this._ref);

  Future<List<Exercise>> loadWorkout({
    required int week,
    required int day,
    int? workoutId,
  }) async {
    final userRepo = _ref.read(userRepositoryProvider);
    final workoutRepo = _ref.read(workoutRepositoryProvider);
    final cycleRepo = _ref.read(cycleRepositoryProvider);

    final user = await userRepo.getLocalUser();
    if (user == null) throw Exception('User not found');

    List<Exercise> exercises = [];

    if (workoutId != null) {
      try {
        final allWorkouts = await workoutRepo.getAllWorkouts();
        final loaded = allWorkouts.where((w) => w.id == workoutId).firstOrNull;
        if (loaded != null && loaded.exercises.isNotEmpty) {
          exercises =
              loaded.exercises.map((e) => Exercise.fromJson(e)).toList();
        }
      } catch (e) {
        // Fallback: Generieren
      }
    }

    if (exercises.isEmpty) {
      final tms = await cycleRepo.getCurrentTrainingMaxesAsync();
      exercises = _generateExercises(week, day, user, tms);
    }

    if (exercises.isEmpty) {
      throw Exception('No exercises configured');
    }

    return exercises;
  }

  List<Exercise> _generateExercises(
      int week, int day, UserCollection user, Map<String, double> tms) {
    final exercises = <Exercise>[];
    final variants = user.exerciseVariants ?? {};

    (String, String, ExerciseType) resolveVariant(String slot, String defaultId,
        String defaultName, ExerciseType defaultType) {
      final variant = variants[slot];
      if (slot == 'pull') {
        if (variant == 'row') return ('row', 'Pendlay Row', ExerciseType.row);
        return ('pullup', 'Weighted Pull-up', ExerciseType.pullup);
      }
      if (slot == 'push') {
        if (variant == 'bench') {
          return ('bench', 'Bench Press', ExerciseType.bench);
        }
        return ('dip', 'Weighted Dip', ExerciseType.dip);
      }
      return (defaultId, defaultName, defaultType);
    }

    void addEx(String slot, String defId, String defName, ExerciseType defType,
        bool isMain) {
      final (id, name, type) = resolveVariant(slot, defId, defName, defType);

      String tmKey = id;
      if (id == 'bench') tmKey = 'dip';
      if (id == 'row') tmKey = 'pullup';

      final tm = tms[tmKey] ?? 0.0;
      List<WorkoutSet> sets = [];

      if (isMain) {
        sets = WendlerCalculator.generateSets(
          week: week,
          trainingMax: tm,
          exerciseType: type,
          currentBodyweight: user.currentBodyweight,
        );
      } else {
        if (week != 4) {
          sets = WendlerCalculator.generateFSLSets(
            trainingMax: tm,
            exerciseType: type,
            currentBodyweight: user.currentBodyweight,
          );
        }
      }

      if (sets.isNotEmpty) {
        exercises.add(Exercise(
          exerciseId: id,
          exerciseName: isMain ? name : '$name (FSL)',
          bodyweightAtSession: user.currentBodyweight,
          sets: sets,
        ));
      }
    }

    if (day == 1) {
      addEx('legs', 'squat', 'Back Squat', ExerciseType.squat, true);
      addEx('pull', 'pullup', 'Weighted Pull-up', ExerciseType.pullup, false);
    } else if (day == 2) {
      addEx('push', 'dip', 'Weighted Dip', ExerciseType.dip, true);
      addEx('legs', 'squat', 'Back Squat', ExerciseType.squat, false);
    } else if (day == 3) {
      addEx('pull', 'pullup', 'Weighted Pull-up', ExerciseType.pullup, true);
      addEx('push', 'dip', 'Weighted Dip', ExerciseType.dip, false);
    }

    return exercises;
  }
}
