import 'dart:collection';

import 'package:aitrainer_app/model/cache.dart';
import 'package:aitrainer_app/model/customer.dart';
import 'package:aitrainer_app/model/exercise.dart';
import 'package:aitrainer_app/model/exercise_type.dart';
import 'package:aitrainer_app/model/workout_menu_tree.dart';
import 'package:aitrainer_app/service/exercise_service.dart';

class ExerciseRepository {
  Exercise exercise;
  Customer customer;
  ExerciseType exerciseType;
  List<Exercise> exerciseList;

  double rmWendler = 0;
  double rmMcglothlin = 0;
  double rmLombardi = 0;
  double rmMayhew = 0;
  double rmOconner = 0;
  double rmWathen = 0;

  createNew() {
    this.exercise = Exercise();
    exercise.dateAdd = DateTime.now();
  }

  setQuantity(double quantity) {
    if ( this.exercise == null ) {
      this.createNew();
    }
    this.exercise.quantity = quantity;
  }

  setUnitQuantity(double unitQuantity) {
    if ( this.exercise == null ) {
      this.createNew();
    }

    this.exercise.unitQuantity = unitQuantity;
  }

  setUnit( String unit) {
    if ( this.exercise == null ) {
      this.createNew();
    }

    this.exercise.unit = unit;
  }

  setDatetimeExercise(DateTime datetimeExercise) {
    if ( this.exercise == null ) {
      this.createNew();
    }

    this.exercise.dateAdd = datetimeExercise;
  }

  double get unitQuantity => this.exercise.unitQuantity;

  double get quantity => this.exercise.quantity;

  Exercise getExercise() => this.exercise;

  Future<void> addExercise() async {
    final Exercise modelExercise = this.exercise;
    modelExercise.customerId = this.customer.customerId;
    modelExercise.exerciseTypeId = this.exerciseType.exerciseTypeId;
    Exercise savedExercise = await ExerciseApi().addExercise(modelExercise);
    if ( customer.customerId == Cache().userLoggedIn.customerId) {
        Cache().addExercise(savedExercise);
    } else if ( Cache().getTrainee() != null && customer.customerId == Cache().getTrainee().customerId ) {
        Cache().addExerciseTrainee(savedExercise);
    }
  }

  Future<void> deleteExercise(Exercise exercise) async {
    await ExerciseApi().deleteExercise(exercise);
  }


  setCustomer(Customer customer) => this.customer = customer;

  setExerciseType( ExerciseType exerciseType) => this.exerciseType = exerciseType;


  Future<List<Exercise>> getExercisesByCustomer( int customerId ) async {
    final results =  await ExerciseApi().getExercisesByCustomer(customerId);
    this.exerciseList = results;
    if ( Cache().userLoggedIn != null ) {
      if (customerId == Cache().userLoggedIn.customerId) {
        Cache().setExercises(exerciseList);
      } else if (Cache().getTrainee() != null && customerId == Cache()
        .getTrainee()
        .customerId) {
        Cache().setExercisesTrainee(exerciseList);
      }
    }
    return this.exerciseList;
  }

  List<Exercise> getExerciseList() {
    this.exerciseList = Cache().getExercises();
    return this.exerciseList;
  }

  List<Exercise> getExerciseListTrainee() {
    this.exerciseList = Cache().getExercisesTrainee();
    return this.exerciseList;
  }

  String nextMissingBaseExercise(SplayTreeMap sortedTree) {
    if ( exerciseList == null ) {
      exerciseList = Cache().getExercises();
    }

    if ( exerciseList == null ) {
      return "";
    }
    String missingTreeName;
    String foundTreeName;
    bool isBreak = false;

    sortedTree.forEach((key, list) {
      List<WorkoutMenuTree> listByMuscle = list as List<WorkoutMenuTree>;
      String treeName = key as String;
      treeName = treeName.substring(3);
      foundTreeName = null;
      listByMuscle.forEach((exercise) {
        if ( missingTreeName == null ) {
          missingTreeName = treeName;
        }
        if ( exercise.base ) {
          exerciseList.forEach((element) { 
            if ( element.exerciseTypeId == exercise.exerciseTypeId ) {
              foundTreeName = treeName;
              //print("Found " + foundTreeName + " Missing actual: " + missingTreeName);
              isBreak = true;
            }
          });
        }
      });
      if ( foundTreeName == null &&! isBreak ) {
        missingTreeName = treeName;
        isBreak = true;
      }
    });

    return missingTreeName;
  }

  void getBaseExerciseFinishedPercent() {
    List<int> checkedExerciseTypeId = List();
    List<int> baseTreeItem = List();
    List<int> checkedBaseTreeItem = List();
    int count1RMExercises = 0;
    LinkedHashMap<String, WorkoutMenuTree> tree = Cache().getWorkoutMenuTree();

    if ( tree == null ) {
      return;
    }

    tree.forEach((key, value) {
      WorkoutMenuTree treeItem = value;
      if (treeItem.exerciseType != null &&
        treeItem.exerciseType.base == true &&
        !baseTreeItem.contains(treeItem.parent)) {
        baseTreeItem.add(treeItem.parent);
      }
    });

    if ( exerciseList == null ) {
      exerciseList = Cache().getExercises();
    }

    if ( exerciseList == null ) {
      return;
    }

    exerciseList.forEach((element) {
      Exercise exercise = element;
      if ( !checkedExerciseTypeId.contains(exercise.exerciseTypeId )) {
        checkedExerciseTypeId.add(exercise.exerciseTypeId);
        tree.forEach((key, value) {
          WorkoutMenuTree treeItem = value;
          if (treeItem.exerciseType != null
            && treeItem.exerciseType.base == true
            && exercise.exerciseTypeId == treeItem.exerciseType.exerciseTypeId
            && !checkedBaseTreeItem.contains(treeItem.parent)) {
              //print ("id: " + exercise.exerciseTypeId.toString());
              checkedBaseTreeItem.add(treeItem.parent);
              count1RMExercises++;
          }
        });
      }
    });

    //print ("checkedExerciseTypeid: " + checkedExerciseTypeId.toString());
    //print ("baseTreeItem: " + baseTreeItem.toString());
    //print ("count1RMExercises: " + count1RMExercises.toString());
    final double percent = count1RMExercises / baseTreeItem.length;
    Cache().setPercentExercises(percent);
  }

  void getLastExercise() {
    List<Exercise> exercises = this.getExerciseList();
    Exercise lastExercise = exercises[0];
    exercises.forEach((element) {
      Exercise actualExercise = element;
      if ( actualExercise.dateAdd.compareTo(lastExercise.dateAdd) > 0 ) {
        lastExercise = actualExercise;
      }
    });
    this.exercise = lastExercise;
    this.customer = Cache().userLoggedIn;
    this.exerciseType = getExerciseTypeById(exercise.exerciseTypeId);
    return;
  }

  ExerciseType getExerciseTypeById(int exerciseTypeId) {
    ExerciseType actualExerciseType;
    Cache().getExerciseTypes().forEach((element) {
      ExerciseType exerciseType = element;
      if ( exerciseType.exerciseTypeId == exerciseTypeId) {
        actualExerciseType = exerciseType;
      }
    });
    if ( actualExerciseType == null ) {
      throw Exception("Data error, no ExerciseType for exerciseTypeId $exerciseTypeId" );
    }
    return actualExerciseType;
  }

  void sortByDate() => exerciseList.sort( (a, b) => b.dateAdd.compareTo(a.dateAdd) );

}