import 'package:intl/intl.dart';
import 'package:aitrainer_app/bloc/training_plan/training_plan_bloc.dart';
import 'package:aitrainer_app/model/cache.dart';
import 'package:aitrainer_app/model/customer_training_plan_details.dart';
import 'package:aitrainer_app/model/exercise_plan_detail.dart';
import 'package:aitrainer_app/model/training_evaluation_exercise.dart';
import 'package:aitrainer_app/util/common.dart';
import 'package:bloc/bloc.dart';
import 'package:equatable/equatable.dart';
import 'package:flutter/material.dart';

part 'training_evaluation_event.dart';
part 'training_evaluation_state.dart';

class TrainingEvaluationBloc extends Bloc<TrainingEvaluationEvent, TrainingEvaluationState> with Common {
  final TrainingPlanBloc trainingPlanBloc;
  final String day;
  TrainingEvaluationBloc({required this.trainingPlanBloc, required this.day}) : super(TrainingEvaluationInitial()) {
    _load();
    on<TrainingEvaluationLoad>(_onLoad);
  }

  String duration = "-";
  String totalLift = "0";
  String maxTotalLift = "0";
  String maxRepeats = "0";
  String totalRepeats = "0";
  DateTime? end;

  List<TrainingEvaluationExercise> evaluationList = [];

  void _onLoad(TrainingEvaluationLoad event, Emitter<TrainingEvaluationState> emit) async {
    getDuration();
    getTotalLift();
    getMaxRepeats();
    getTotalRepeats();
    createEvaluationData();
    getMaxLift();
    if (end == null || DateTime.now().difference(end!).inMinutes > 5) {
      emit(TrainingEvaluationReady());
    } else {
      emit(TrainingEvaluationVictoryReady());
    }
  }

  void _load() {
    getDuration();
    getTotalLift();
    getMaxRepeats();
    getTotalRepeats();
    createEvaluationData();
    getMaxLift();
    /* if (end == null || DateTime.now().difference(end!).inMinutes > 5) {
      emit(TrainingEvaluationReady());
    } else {
      emit(TrainingEvaluationVictoryReady());
    } */
  }

  void createEvaluationData() {
    if (trainingPlanBloc.getMyPlan() == null || trainingPlanBloc.getMyPlan()!.days[day] == null) {
      return;
    }

    trainingPlanBloc.getMyPlan()!.days[day]!.forEach((element) {
      if (element.exerciseTypeId != null) {
        if (!findExerciseInEvaluationList(element.exerciseTypeId!)) {
          addEvaluationExercise(element);
        }
      }
    });
  }

  bool findExerciseInEvaluationList(int exerciseTypeId) {
    bool found = false;
    for (var exercise in evaluationList) {
      if (exercise.exerciseTypeId == exerciseTypeId) {
        found = true;
        break;
      }
    }
    return found;
  }

  void addEvaluationExercise(CustomerTrainingPlanDetails detail) {
    TrainingEvaluationExercise exercise = TrainingEvaluationExercise();
    exercise.exerciseTypeId = detail.exerciseTypeId!;
    exercise.name = detail.exerciseType!.nameTranslation;
    exercise.state = detail.state;

    if (detail.state.equalsTo(ExercisePlanDetailState.skipped)) {
      TrainingEvaluationExercise exercise = TrainingEvaluationExercise();
      exercise.exerciseTypeId = detail.exerciseTypeId!;
      exercise.name = detail.exerciseType!.nameTranslation;
      exercise.state = ExercisePlanDetailState.skipped;
      exercise.type = TrainingEvaluationExerciseType.weightBased;
      this.evaluationList.add(exercise);
    } else {
      if (detail.exerciseType!.unitQuantityUnit == null || detail.weight == null) {
        exercise.type = TrainingEvaluationExerciseType.repeatBased;
        exercise.repeats = detail.repeats;
        exercise.maxRepeats = getMaxRepeatsByExerciseType(detail.exerciseTypeId!);
        exercise.trend = getTrendEvaluationRepeats(exercise);
      } else {
        exercise.type = TrainingEvaluationExerciseType.weightBased;
        exercise.oneRepMax = calculate1RM(detail.weight!, detail.repeats!.toDouble());
        exercise.max1RM = getMax1RMByExerciseType(detail.exerciseTypeId!);
        exercise.totalLift = getTotalLiftBySameExercise(detail.exerciseTypeId!);
        exercise.maxTotalLift = getMaxTotalLiftByExerciseType(detail.exerciseTypeId!);
        exercise.trend = this.getTrendWeight(exercise.oneRepMax!, exercise.max1RM, exercise.totalLift, exercise.maxTotalLift);
      }
      exercise.trendText = getTrendText(exercise.trend!);
      exercise.trendColor = getTrendColor(exercise.trend!);
      this.evaluationList.add(exercise);
    }
  }

  double getTrendEvaluationRepeats(TrainingEvaluationExercise exercise) {
    double rate = exercise.repeats! / exercise.maxRepeats!;
    return rate;
  }

  String getTrendText(double rate) {
    if (rate > 1.20) {
      return "Strongly Growing";
    } else if (rate > 1.05) {
      return "Growing";
    } else if (rate < 0.80) {
      return "Strongly Sinking";
    } else if (rate < 0.95) {
      return "Sinking";
    } else {
      return "Stagnant";
    }
  }

  Color getTrendColor(double rate) {
    if (rate > 1.20) {
      return Colors.green[900]!;
    } else if (rate > 1.05) {
      return Colors.green[300]!;
    } else if (rate < 0.80) {
      return Colors.red[900]!;
    } else if (rate < 0.95) {
      return Colors.red[400]!;
    } else {
      return Colors.white;
    }
  }

  void getDuration() {
    if (trainingPlanBloc.getMyPlan() == null || trainingPlanBloc.getMyPlan()!.days[day] == null) {
      return;
    }
    int index = 0;
    DateTime? start;

    trainingPlanBloc.getMyPlan()!.days[day]!.forEach((element) {
      if (element.state.equalsTo(ExercisePlanDetailState.finished)) {
        if (index++ == 0) {
          start = element.exercises[0].dateAdd!;
        } else {
          if (element.exercises.length > 0) {
            this.end = element.exercises[element.exercises.length - 1].dateAdd!;
          }
        }
        //print("Exercise Date ${element.exercises[0].dateAdd!}");
      }
    });
    if (start == null) {
      this.duration = "00:00:00";
    } else if (this.end == null) {
      this.duration = "00:01:00";
      this.end = start;
    } else {
      this.duration = end!.difference(start!).inMinutes.toString();
    }
  }

  void getTotalLift() {
    if (trainingPlanBloc.getMyPlan() == null || trainingPlanBloc.getMyPlan()!.days[day] == null) {
      return;
    }
    double total = 0;
    trainingPlanBloc.getMyPlan()!.days[day]!.forEach((element) {
      if (element.state.equalsTo(ExercisePlanDetailState.finished) && element.exerciseType!.unitQuantityUnit != null) {
        total += element.weight! * element.repeats!;
      }
    });
    totalLift = total.toStringAsFixed(0);
  }

  double getTotalLiftBySameExercise(int exerciseTypeId) {
    if (trainingPlanBloc.getMyPlan() == null || trainingPlanBloc.getMyPlan()!.days[day] == null) {
      return 0;
    }
    double total = 0;
    trainingPlanBloc.getMyPlan()!.days[day]!.forEach((element) {
      if (element.exerciseTypeId == exerciseTypeId) {
        if (element.state.equalsTo(ExercisePlanDetailState.finished) && element.exerciseType!.unitQuantityUnit != null) {
          total += element.weight! * element.repeats!;
        }
      }
    });
    return total;
  }

  void getMaxLift() {
    if (trainingPlanBloc.getMyPlan() == null || trainingPlanBloc.getMyPlan()!.days[day] == null) {
      return;
    }
    double max = 0;
    trainingPlanBloc.getMyPlan()!.days[day]!.forEach((element) {
      if (element.state.equalsTo(ExercisePlanDetailState.finished) && element.exerciseType!.unitQuantityUnit != null) {
        if (max < element.weight!) {
          max = element.weight!;
        }
      }
    });
    maxTotalLift = max.toStringAsFixed(0);
  }

  void getMaxRepeats() {
    if (trainingPlanBloc.getMyPlan() == null || trainingPlanBloc.getMyPlan()!.days[day] == null) {
      return;
    }
    int max = 0;
    trainingPlanBloc.getMyPlan()!.days[day]!.forEach((element) {
      if (element.state.equalsTo(ExercisePlanDetailState.finished) && element.exerciseType!.unit != "second") {
        print("Repeats ${element.repeats}");
        if (max < element.repeats!) {
          max = element.repeats!;
        }
      }
    });
    maxRepeats = max.toStringAsFixed(0);
  }

  void getTotalRepeats() {
    if (trainingPlanBloc.getMyPlan() == null || trainingPlanBloc.getMyPlan()!.days[day] == null) {
      return;
    }
    int total = 0;
    trainingPlanBloc.getMyPlan()!.days[day]!.forEach((element) {
      if (element.state.equalsTo(ExercisePlanDetailState.finished) && element.exerciseType!.unit != "second") {
        print("Repeats ${element.repeats}");

        total += element.repeats!;
      }
    });
    totalRepeats = total.toStringAsFixed(0);
  }

  double getMaxTotalLiftByExerciseType(int exerciseTypeId) {
    if (Cache().getExercises() == null || Cache().getExercises()!.length == 0) {
      return 0;
    }

    var now = new DateTime.now();
    var formatter = new DateFormat('yyyy-MM-dd');
    final String formattedToday = formatter.format(now);

    double maxTotal = 0;
    Cache().getExercises()!.forEach((element) {
      if (element.dateAdd != null) {
        final String formattedExerciseDate = formatter.format(element.dateAdd!);
        if (element.exerciseTypeId == exerciseTypeId && formattedToday != formattedExerciseDate) {
          final double total = element.quantity! * element.unitQuantity!;
          if (maxTotal < total) {
            maxTotal = total;
          }
        }
      }
    });

    return maxTotal;
  }

  double getMax1RMByExerciseType(int exerciseTypeId) {
    if (Cache().getExercises() == null || Cache().getExercises()!.length == 0) {
      return 0;
    }
    var now = new DateTime.now();
    var formatter = new DateFormat('yyyy-MM-dd');
    final String formattedToday = formatter.format(now);

    double max1RM = 0;
    Cache().getExercises()!.forEach((element) {
      if (element.dateAdd != null) {
        final String formattedExerciseDate = formatter.format(element.dateAdd!);
        if (element.exerciseTypeId == exerciseTypeId && formattedToday != formattedExerciseDate) {
          final double oneRepMax = calculate1RM(element.unitQuantity!, element.quantity!);
          if (max1RM < oneRepMax) {
            max1RM = oneRepMax;
          }
        }
      }
    });
    return max1RM;
  }

  int getMaxRepeatsByExerciseType(int exerciseTypeId) {
    if (Cache().getExercises() == null || Cache().getExercises()!.length == 0) {
      return 0;
    }
    int maxRepeats = 0;
    Cache().getExercises()!.forEach((element) {
      if (element.exerciseTypeId == exerciseTypeId) {
        final int repeats = element.quantity!.toInt();
        if (maxRepeats < repeats) {
          maxRepeats = repeats;
        }
      }
    });
    return maxRepeats;
  }

  double getOneRepMax(CustomerTrainingPlanDetails detail) {
    if (detail.weight == null) {
      return 0;
    }
    return calculate1RM(detail.weight!, detail.repeats!.toDouble());
  }

  double getTotalLiftExercise(CustomerTrainingPlanDetails detail) {
    if (detail.weight == null) {
      return 0;
    }
    return detail.weight! * detail.repeats!;
  }

  double getTrendWeight(double oneRepMax, max1RM, totalLift, maxTotalLift) {
    final double oneRepMaxRate = oneRepMax / max1RM;
    //double totalLiftRate = totalLift / maxTotalLift;
    return oneRepMaxRate;
  }
}
