import 'dart:async';

import 'package:aitrainer_app/bloc/menu/menu_bloc.dart';
import 'package:aitrainer_app/model/cache.dart';
import 'package:aitrainer_app/model/customer_training_plan.dart';
import 'package:aitrainer_app/model/customer_training_plan_details.dart';
import 'package:aitrainer_app/model/customer_training_plan_exercise.dart';
import 'package:aitrainer_app/model/exercise.dart';
import 'package:aitrainer_app/model/exercise_plan_detail.dart';
import 'package:aitrainer_app/model/workout_menu_tree.dart';
import 'package:aitrainer_app/repository/training_plan_repository.dart';
import 'package:aitrainer_app/service/exercise_service.dart';
import 'package:aitrainer_app/service/training_plan_service.dart';
import 'package:bloc/bloc.dart';
import 'package:equatable/equatable.dart';

part 'training_plan_event.dart';
part 'training_plan_state.dart';

class TrainingPlanBloc extends Bloc<TrainingPlanEvent, TrainingPlanState> {
  final TrainingPlanRepository trainingPlanRepository;
  final MenuBloc menuBloc;
  TrainingPlanBloc({required this.trainingPlanRepository, required this.menuBloc}) : super(TrainingPlanInitial());

  CustomerTrainingPlan? myPlan;
  bool started = false;

  CustomerTrainingPlan? getMyPlan() => this.myPlan;
  setMyPlan(CustomerTrainingPlan myPlan) => this.myPlan = myPlan;

  @override
  Stream<TrainingPlanState> mapEventToState(TrainingPlanEvent event) async* {
    try {
      if (event is TrainingPlanActivate) {
        yield TrainingPlanLoading();
        myPlan = await trainingPlanRepository.activateTrainingPlan(event.trainingPlanId);
        Cache().myTrainingPlan = myPlan;
        await Cache().saveMyTrainingPlan();
        yield TrainingPlanFinished();
      } else if (event is TrainingPlanWeightChange) {
        yield TrainingPlanLoading();
        event.detail.weight = event.weight;

        yield TrainingPlanReady();
      } else if (event is TrainingPlanRepeatsChange) {
        yield TrainingPlanLoading();

        event.detail.repeats = event.repeats;

        yield TrainingPlanReady();
      } else if (event is TrainingPlanSaveExercise) {
        yield TrainingPlanLoading();

        event.detail.state = ExercisePlanDetailState.inProgress;
        final Exercise exercise = Exercise();
        exercise.customerId = Cache().userLoggedIn!.customerId!;
        exercise.exerciseTypeId = event.detail.exerciseTypeId;
        exercise.quantity = event.detail.repeats!.toDouble();
        exercise.unit = event.detail.exerciseType!.unit;
        exercise.unitQuantity = event.detail.weight;
        exercise.dateAdd = DateTime.now();
        event.detail.exercises.add(exercise);
        if (event.detail.exercises.length >= event.detail.set!) {
          event.detail.state = ExercisePlanDetailState.finished;
        } else if (event.detail.exercises.length >= 0) {
          event.detail.state = ExercisePlanDetailState.inProgress;
        }

        exercise.trainingPlanDetailsId = myPlan!.trainingPlanId;

        // save Exercise
        await ExerciseApi().addExercise(exercise);
        Cache().addExercise(exercise);

        Cache().myTrainingPlan = myPlan;
        await Cache().saveMyTrainingPlan();
        yield TrainingPlanReady();
      }
    } on Exception catch (e) {
      yield TrainingPlanError(message: e.toString());
    }
  }

  CustomerTrainingPlanDetails? getTrainingPlanDetail(int trainingPlanDetailsId) {
    CustomerTrainingPlanDetails? detail;
    if (myPlan == null || myPlan!.details.isEmpty) {
      return null;
    }

    for (final det in this.myPlan!.details) {
      if (det.customerTrainingPlanDetailsId == trainingPlanDetailsId) {
        detail = det;
        break;
      }
    }

    return detail;
  }

  int? getActualWorkoutTreeId(int exerciseTypeId) {
    final WorkoutMenuTree? workoutTree = this.menuBloc.menuTreeRepository.getMenuItemByExerciseTypeId(exerciseTypeId);
    if (workoutTree == null) {
      return null;
    }
    return workoutTree.id;
  }

  String getActualImageName(int exerciseTypeId) {
    if (exerciseTypeId <= 0) {
      return "";
    }
    final WorkoutMenuTree? workoutTree = this.menuBloc.menuTreeRepository.getMenuItemByExerciseTypeId(exerciseTypeId);
    if (workoutTree == null) {
      return "";
    }

    return workoutTree.imageName;
  }

  CustomerTrainingPlanDetails? getNext() {
    if (myPlan == null || myPlan!.details.isEmpty) {
      return null;
    }

    CustomerTrainingPlanDetails? next;
    int minStep = 99;
    for (final detail in this.myPlan!.details) {
      if (!detail.state.equalsTo(ExercisePlanDetailState.finished)) {
        if (detail.exercises.isEmpty) {
          next = detail;
          minStep = 1;
          break;
        } else {
          final int step = detail.exercises.length;
          if (step < minStep) {
            next = detail;
            minStep = step;
            if (detail.parallel != true) {
              break;
            }
          }
        }
      }
    }

    return next;
  }

  bool isStarted() {
    if (myPlan == null || myPlan!.details.isEmpty) {
      return false;
    }

    if (myPlan!.details[0].state == ExercisePlanDetailState.start) {
      return false;
    } else {
      return true;
    }
  }
}