import 'dart:collection';

import 'package:aitrainer_app/model/cache.dart';
import 'package:aitrainer_app/model/exercise_plan.dart';
import 'package:aitrainer_app/model/exercise_plan_detail.dart';
import 'package:aitrainer_app/model/exercise_type.dart';
import 'package:aitrainer_app/model/model_change.dart';
import 'package:aitrainer_app/service/exercise_plan_service.dart';

class ExercisePlanRepository {
  bool newPlan = true;
  ExercisePlan exercisePlan;
  LinkedHashMap<int, ExercisePlanDetail> exercisePlanDetails = LinkedHashMap<int, ExercisePlanDetail>();
  int customerId = 0;
  ExercisePlanDetail actualPlanDetail;

  void setCustomerId(int customerId) {
    this.customerId = customerId;
  }

  int getCustomerId() => customerId;

  void setExercisePlan(ExercisePlan plan) {
    this.exercisePlan = plan;
  }

  ExercisePlan getExercisePlan() => exercisePlan;

  void addDetailToPlan() {
    if (exercisePlan != null) {
      actualPlanDetail.exercisePlanId = exercisePlan.exercisePlanId;
    }
    exercisePlanDetails[actualPlanDetail.exerciseTypeId] = actualPlanDetail;
    Cache().addToMyExercisePlanDetails(actualPlanDetail);
  }

  ExercisePlanDetail getExercisePlanDetailByExerciseId(int exerciseTypeId) => exercisePlanDetails[exerciseTypeId];

  void setActualPlanDetailByExerciseType(ExerciseType exerciseType) {
    ExercisePlanDetail detail = exercisePlanDetails[exerciseType.exerciseTypeId];
    if (detail != null) {
      actualPlanDetail = detail;
    } else {
      actualPlanDetail = ExercisePlanDetail(exerciseType.exerciseTypeId);
    }
    actualPlanDetail.exerciseType = exerciseType;
  }

  ExercisePlanDetail getActualPlanDetail() => actualPlanDetail;

  void setActualPlanDetail(ExercisePlanDetail detail) {
    this.actualPlanDetail = detail;
  }

  int getPlanDetailId(int exerciseTypeId) => exercisePlanDetails[exerciseTypeId].exercisePlanDetailId;

  String getPlanDetail(int exerciseTypeId) {
    ExercisePlanDetail detail = exercisePlanDetails[exerciseTypeId];
    String detailString = "";
    if (detail != null) {
      detailString = detail.serie.toString() + "x" + detail.repeats.toString() + " " + detail.weightEquation + "kg";
    }
    return detailString;
  }

  int getExercisePlanDetailSize() {
    return exercisePlanDetails.length;
  }

  void updateExercisePlanDetail(ExerciseType exerciseType, int serie, int repeat, String weight) {
    if (exercisePlanDetails[exerciseType.exerciseTypeId] == null) {
      return;
    }
    ExercisePlanDetail exercisePlanDetail = exercisePlanDetails[exerciseType.exerciseTypeId];
    exercisePlanDetail.serie = serie;
    exercisePlanDetail.repeats = repeat;
    exercisePlanDetail.weightEquation = weight;
    exercisePlanDetail.change = ModelChange.update;

    exercisePlanDetails[exerciseType.exerciseTypeId] = exercisePlanDetail;
  }

  void removeExerciseTypeFromPlan(ExerciseType exerciseType) {
    removeExerciseTypeFromPlanByExerciseTypeId(exerciseType.exerciseTypeId);
  }

  void removeExerciseTypeFromPlanByExerciseTypeId(int exerciseTypeId) {
    exercisePlanDetails[exerciseTypeId].change = ModelChange.delete;
    Cache().deleteMyExercisePlanDetailByExerciseTypeId(exerciseTypeId);
  }

  Future<void> saveExercisePlan() async {
    if (exercisePlan == null) {
      if (Cache().userLoggedIn == null) {
        throw Exception("please log in");
      }

      String exercisePlanName;
      if (this.customerId == Cache().userLoggedIn.customerId) {
        exercisePlanName = Cache().userLoggedIn.name + " private";
      } else {
        exercisePlanName = Cache().getTrainee().name + " " + Cache().getTrainee().firstname + " private";
      }

      exercisePlan = ExercisePlan(exercisePlanName, this.customerId);
    }
    if (newPlan) {
      exercisePlan.dateAdd = DateTime.now();
      exercisePlan.private = true;
      ExercisePlan savedExercisePlan = await ExercisePlanApi().saveExercisePlan(exercisePlan);

      LinkedHashMap<int, ExercisePlanDetail> savedExercisePlanDetails = LinkedHashMap();
      exercisePlanDetails.forEach((exerciseTypeId, exercisePlanDetail) async {
        exercisePlanDetail.exercisePlanId = savedExercisePlan.exercisePlanId;
        ExercisePlanDetail savedDetail = await ExercisePlanApi().saveExercisePlanDetail(exercisePlanDetail);
        savedExercisePlanDetails[savedDetail.exerciseTypeId] = savedDetail;
      });

      exercisePlan = savedExercisePlan;
      exercisePlanDetails = savedExercisePlanDetails;
    } else {
      //await ExercisePlanApi().updateExercisePlan(exercisePlan, exercisePlan.exercisePlanId);

      exercisePlanDetails.forEach((exerciseTypeId, exercisePlanDetail) async {
        if (exercisePlanDetail.change == ModelChange.delete) {
          await ExercisePlanApi().deleteExercisePlanDetail(exercisePlanDetail.exercisePlanDetailId);
          exercisePlanDetail.change = ModelChange.deleted;
          Cache().deletedMyExercisePlanDetail(exercisePlanDetail);
        } else if (exercisePlanDetail.change == ModelChange.update) {
          await ExercisePlanApi().updateExercisePlanDetail(exercisePlanDetail, exercisePlanDetail.exercisePlanDetailId);
          Cache().updateMyExercisePlanDetail(exercisePlanDetail);
          exercisePlanDetail.change = ModelChange.saved;
        } else if (exercisePlanDetail.change == ModelChange.add) {
          await ExercisePlanApi().saveExercisePlanDetail(exercisePlanDetail);
          Cache().addToMyExercisePlanDetails(exercisePlanDetail);
          exercisePlanDetail.change = ModelChange.saved;
        }
      });
    }
  }

  Future<ExercisePlan> getLastExercisePlan() async {
    if (customerId == 0) {
      return null;
    }
    ExercisePlan myExercisePlan = Cache().getMyExercisePlan();
    if (myExercisePlan != null) {
      exercisePlan = myExercisePlan;
      return myExercisePlan;
    }

    exercisePlan = await ExercisePlanApi().getLastExercisePlan(customerId);
    newPlan = (exercisePlan == null);
    print("New plan: " + newPlan.toString());
    Cache().setMyExercisePlan(exercisePlan);
    return exercisePlan;
  }

  Future<void> getExercisePlanDetails() async {
    if (exercisePlan == null) {
      ExercisePlan exercisePlan = await this.getLastExercisePlan();
      if (exercisePlan == null) {
        exercisePlanDetails = LinkedHashMap<int, ExercisePlanDetail>();
        return;
      }
    }

    List<ExercisePlanDetail> list = List();
    LinkedHashMap<int, ExercisePlanDetail> listCache = Cache().getMyExercisePlanDetails();
    if (listCache.length > 0) {
      exercisePlanDetails = listCache;
      return;
    } else {
      list = await ExercisePlanApi().getExercisePlanDetail(exercisePlan.exercisePlanId);
    }

    exercisePlanDetails = LinkedHashMap<int, ExercisePlanDetail>();

    list.forEach((element) {
      newPlan = false;
      ExercisePlanDetail detail = element;
      exercisePlanDetails[detail.exerciseTypeId] = detail;
    });
    Cache().setMyExercisePlanDetails(exercisePlanDetails);

    return;
  }
}