import 'package:riverpod_annotation/riverpod_annotation.dart';
import 'package:slrpg_app/src/shared/domain/entities/exercise.dart';
import 'package:slrpg_app/src/shared/domain/entities/workout_set.dart';

part 'battle_controller.g.dart';

class BattleState {
  final List<Exercise> exercises;
  final int currentExerciseIndex;
  final int currentSetIndex;
  final int repsCompleted;
  final bool isLoading;
  final bool isResting;
  final int restSeconds;
  final String? error;

  const BattleState({
    this.exercises = const [],
    this.currentExerciseIndex = 0,
    this.currentSetIndex = 0,
    this.repsCompleted = 0,
    this.isLoading = true,
    this.isResting = false,
    this.restSeconds = 0,
    this.error,
  });

  BattleState copyWith({
    List<Exercise>? exercises,
    int? currentExerciseIndex,
    int? currentSetIndex,
    int? repsCompleted,
    bool? isLoading,
    bool? isResting,
    int? restSeconds,
    String? error,
  }) {
    return BattleState(
      exercises: exercises ?? this.exercises,
      currentExerciseIndex: currentExerciseIndex ?? this.currentExerciseIndex,
      currentSetIndex: currentSetIndex ?? this.currentSetIndex,
      repsCompleted: repsCompleted ?? this.repsCompleted,
      isLoading: isLoading ?? this.isLoading,
      isResting: isResting ?? this.isResting,
      restSeconds: restSeconds ?? this.restSeconds,
      error: error ?? this.error,
    );
  }
}

@riverpod
class BattleController extends _$BattleController {
  @override
  BattleState build() {
    return const BattleState();
  }

  void setExercises(List<Exercise> exercises) {
    state = state.copyWith(
      exercises: exercises,
      isLoading: false,
      repsCompleted: exercises.isNotEmpty && exercises.first.sets.isNotEmpty
          ? exercises.first.sets.first.repsTarget
          : 0,
    );
  }

  void setLoading(bool loading) {
    state = state.copyWith(isLoading: loading);
  }

  void setError(String error) {
    state = state.copyWith(error: error, isLoading: false);
  }

  void updateRepsCompleted(int reps) {
    state = state.copyWith(repsCompleted: reps);
  }

  void startRest(int seconds) {
    state = state.copyWith(isResting: true, restSeconds: seconds);
  }

  void tickRest() {
    if (state.restSeconds > 0) {
      state = state.copyWith(restSeconds: state.restSeconds - 1);
    } else {
      state = state.copyWith(isResting: false);
    }
  }

  void skipRest() {
    state = state.copyWith(isResting: false, restSeconds: 0);
  }

  void completeSet({required int repsActual}) {
    final currentExercise = state.exercises[state.currentExerciseIndex];
    final currentSet = currentExercise.sets[state.currentSetIndex];

    final updatedSet = currentSet.copyWith(
      repsActual: repsActual,
      completed: true,
    );

    final updatedSets = List<WorkoutSet>.from(currentExercise.sets);
    updatedSets[state.currentSetIndex] = updatedSet;

    final updatedExercise = currentExercise.copyWith(sets: updatedSets);
    final updatedExercises = List<Exercise>.from(state.exercises);
    updatedExercises[state.currentExerciseIndex] = updatedExercise;

    state = state.copyWith(exercises: updatedExercises);
  }

  void moveToNextSet() {
    final currentExercise = state.exercises[state.currentExerciseIndex];

    if (state.currentSetIndex < currentExercise.sets.length - 1) {
      final nextSet = currentExercise.sets[state.currentSetIndex + 1];
      state = state.copyWith(
        currentSetIndex: state.currentSetIndex + 1,
        repsCompleted: nextSet.repsTarget,
      );
    }
  }

  void moveToNextExercise() {
    if (state.currentExerciseIndex < state.exercises.length - 1) {
      final nextExercise = state.exercises[state.currentExerciseIndex + 1];
      final nextReps =
          nextExercise.sets.isNotEmpty ? nextExercise.sets.first.repsTarget : 0;

      state = state.copyWith(
        currentExerciseIndex: state.currentExerciseIndex + 1,
        currentSetIndex: 0,
        repsCompleted: nextReps,
      );
    }
  }

  void adjustEmomSets(int newTotalSets) {
    final currentEx = state.exercises[state.currentExerciseIndex];

    if (newTotalSets == currentEx.sets.length) return;

    List<WorkoutSet> currentSets = List.from(currentEx.sets);

    if (newTotalSets > currentSets.length) {
      final templateSet = currentSets.last;
      for (int i = currentSets.length; i < newTotalSets; i++) {
        currentSets.add(templateSet.copyWith(
          setNumber: i + 1,
          completed: true,
          repsActual: templateSet.repsTarget,
        ));
      }
    } else {
      currentSets = currentSets.sublist(0, newTotalSets);
    }

    final updatedEx = currentEx.copyWith(sets: currentSets);
    final updatedExercises = List<Exercise>.from(state.exercises);
    updatedExercises[state.currentExerciseIndex] = updatedEx;

    state = state.copyWith(
      exercises: updatedExercises,
      currentSetIndex: newTotalSets - 1,
      repsCompleted: updatedEx.sets.last.repsTarget,
    );
  }

  Exercise get currentExercise => state.exercises[state.currentExerciseIndex];
  WorkoutSet get currentSet => currentExercise.sets[state.currentSetIndex];

  bool get isLastSet =>
      state.currentSetIndex >= currentExercise.sets.length - 1;

  bool get isLastExercise =>
      state.currentExerciseIndex >= state.exercises.length - 1;

  int get totalHP => state.exercises.fold<int>(
        0,
        (sum, ex) => sum + ex.sets.fold<int>(0, (s, set) => s + set.repsTarget),
      );

  int get completedHP {
    int hp = 0;

    for (int i = 0; i < state.currentExerciseIndex; i++) {
      hp += state.exercises[i].sets.fold<int>(
        0,
        (sum, set) => sum + set.repsActual,
      );
    }

    final currentExercise = state.exercises[state.currentExerciseIndex];
    for (int i = 0; i < state.currentSetIndex; i++) {
      hp += currentExercise.sets[i].repsActual;
    }

    return hp;
  }
}
