import 'dart:async';
import 'package:aitrainer_app/bloc/timer/timer_bloc.dart';
import 'package:aitrainer_app/repository/exercise_repository.dart';
import 'package:bloc/bloc.dart';
import 'package:equatable/equatable.dart';
import 'package:meta/meta.dart';

part 'exercise_control_event.dart';

part 'exercise_control_state.dart';

class ExerciseControlBloc extends Bloc<ExerciseControlEvent, ExerciseControlState> {
  final TimerBloc timerBloc;
  final ExerciseRepository exerciseRepository;
  final bool readonly;
  final double percentToCalculate;
  int step = 1;

  double initialRM;
  double unitQuantity;
  double quantity;
  double origQuantity;
  double oneRepQuantity;
  double oneRepUnitQuantity;

  double firstQuantity; // quantity of the first test
  double firstUnitQuantity; // unit quantity of the first test

  double scrollOffset = 0;

  @override
  ExerciseControlBloc({this.exerciseRepository, this.readonly, this.percentToCalculate, @required this.timerBloc})
      : super(ExerciseControlInitial()) {
    oneRepQuantity = exerciseRepository.exercise.quantity;
    oneRepUnitQuantity = exerciseRepository.exercise.unitQuantity;
    initialRM = this.calculate1RM(percent75: false);
    unitQuantity = this.calculate1RM(percent75: true).roundToDouble();
    quantity = percentToCalculate == 0.75 ? 12 : 35;
    origQuantity = quantity;

    exerciseRepository.setUnitQuantity(unitQuantity);
    exerciseRepository.setQuantity(quantity);
    print("init quantity: " + quantity.toString());
    timerBloc.add(TimerStart(duration: 300));
  }

  @override
  Stream<ExerciseControlState> mapEventToState(ExerciseControlEvent event) async* {
    try {
      if (event is ExerciseControlLoad) {
        yield ExerciseControlLoading();
        print("init quantity: " + quantity.toString());
        step = 1;
        yield ExerciseControlReady();
      } else if (event is ExerciseControlQuantityChange) {
        //yield ExerciseControlLoading();
        if (event.step == step) {
          exerciseRepository.setQuantity(event.quantity);
          quantity = event.quantity;
        }
        //yield ExerciseControlReady();
      } else if (event is ExerciseControlUnitQuantityChange) {
        yield ExerciseControlLoading();

        if (event.step == step) {
          this.unitQuantity = event.quantity;
          exerciseRepository.setUnitQuantity(event.quantity);
          unitQuantity = event.quantity;
          quantity = calculateQuantityByUnitQuantity().toDouble();
          exerciseRepository.setQuantity(quantity);
          origQuantity = quantity;
        }
        yield ExerciseControlReady();
      } else if (event is ExerciseControlSubmit) {
        yield ExerciseControlLoading();
        if (event.step == step) {
          step++;
          scrollOffset = step * 400.0;

          quantity = origQuantity;
          if (exerciseRepository.exercise.quantity == null) {
            exerciseRepository.setQuantity(quantity);
          }
          exerciseRepository.end = DateTime.now();
          await exerciseRepository.addExercise();

          exerciseRepository.setQuantity(quantity);
          exerciseRepository.exercise.exerciseId = null;
          step <= 3 ? timerBloc.add(TimerStart(duration: 300)) : timerBloc.add(TimerEnd());
        }
        yield ExerciseControlReady();
      }
    } on Exception catch (e) {
      yield ExerciseControlError(message: e.toString());
    }
  }

  double calculate1RM({bool percent75}) {
    if (exerciseRepository.exercise == null) {
      exerciseRepository.getLastExercise();
    }
    double weight = exerciseRepository.exercise.unitQuantity;
    double repeat = exerciseRepository.exercise.quantity;
    if (weight == 0 || repeat == 0) {
      return 0;
    }

    double rmWendler = weight * repeat * 0.0333 + weight;
    double rmOconner = weight * (1 + repeat / 40);
    print("Weight: $weight repeat: $repeat,  $rmWendler, Oconner: $rmOconner");
    double average = (rmWendler + rmOconner) / 2;

    return percent75 ? average * this.percentToCalculate : average;
  }

  int calculateQuantityByUnitQuantity() {
    double weight = oneRepUnitQuantity;
    double repeat = oneRepQuantity;
    final double rmWendler = weight * repeat * 0.0333 + weight;
    final double rmOconner = weight * (1 + repeat / 40);
    print("Weight: $weight oneRepQuantity: $repeat,  $rmWendler, Oconner: $rmOconner");

    weight = exerciseRepository.exercise.unitQuantity;
    repeat = exerciseRepository.exercise.quantity;

    final double repeatWendler = (rmWendler - weight) / 0.0333 / weight;
    final double repeatOconner = (rmOconner / weight - 1) * 40;
    final newRepeat = ((repeatOconner + repeatWendler) / 2).ceil();
    print("Initial 1RM: $initialRM Weight: $weight repeatWendler: $repeatWendler repeat Oconner: $repeatOconner. NEW REPEAT: $newRepeat");
    return newRepeat;
  }
}