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) {
      this.createNewPlan();
    }
    if (exercisePlan != null && actualPlanDetail != null) {
      if (exercisePlan!.exercisePlanId != 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) {
    if (exercisePlanDetails[exerciseTypeId] == null) return;
    exercisePlanDetails[exerciseTypeId]!.change = ModelChange.delete;
    Cache().deleteMyExercisePlanDetailByExerciseTypeId(exerciseTypeId);
  }

  Future<void> saveExercisePlan() async {
    if (exercisePlan == null) {
      this.createNewPlan();
    }
    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;
        }
      });
    }
  }

  void createNewPlan() {
    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);
    newPlan = true;
  }

  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);
    if (exercisePlan == null) {
      this.createNewPlan();
    }
    ;
    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 = [];
    LinkedHashMap<int, ExercisePlanDetail> listCache = Cache().getMyExercisePlanDetails();
    if (listCache.length > 0) {
      exercisePlanDetails = listCache;
      return;
    } else {
      if (exercisePlan!.exercisePlanId != null) {
        list = await ExercisePlanApi().getExercisePlanDetail(exercisePlan!.exercisePlanId!);
      }
    }

    exercisePlanDetails = LinkedHashMap<int, ExercisePlanDetail>();
    if (list.isNotEmpty) {
      list.forEach((element) {
        newPlan = false;
        ExercisePlanDetail detail = element;
        exercisePlanDetails[detail.exerciseTypeId] = detail;
      });
    }
    Cache().setMyExercisePlanDetails(exercisePlanDetails);

    return;
  }
}