import 'dart:collection';
import 'package:aitrainer_app/model/customer.dart';
import 'package:aitrainer_app/model/exercise_plan.dart';
import 'package:aitrainer_app/model/exercise_plan_detail.dart';
import 'package:aitrainer_app/model/exercise_tree.dart';
import 'package:aitrainer_app/model/exercise.dart';
import 'package:aitrainer_app/model/workout_menu_tree.dart';
import 'package:aitrainer_app/repository/exercise_repository.dart';
import 'package:aitrainer_app/service/exercise_tree_service.dart';
import 'package:aitrainer_app/service/exercisetype_service.dart';
import 'package:aitrainer_app/util/env.dart';
import 'package:shared_preferences/shared_preferences.dart';
import 'package:aitrainer_app/model/exercise_type.dart';

enum SharePrefsChange {
  login,
  registration,
  logout,
}
/*
  Auth flow of the app
  1. During the login screen the authentication will be executed
    - if not successful: message: Network error, try again later
    - if successful
      - get the stored shared preferences and customer id
        - if customer_id not present -> registration page
        - if present, check if the expiration_date > 10 days -> login page
        - else get the API customer by the stored customer_id
      - After registration / login store the preferences:
        - AuthToken
        - customer_id
        - last_store_date
        - is_registered
        - is_logged_in
 */

class Cache {
  static final Cache _singleton = Cache._internal();

  // Keys to store and fetch data from SharedPreferences
  static final String authTokenKey = 'auth_token';
  static final String customerIdKey = 'customer_id';
  static final String lastStoreDateKey = 'last_date';
  static final String isRegisteredKey = 'is_registered';
  static final String isLoggedInKey = 'is_logged_in';
  static final String langKey = 'lang';

  static String baseUrl = 'http://aitrainer.info:8888/api/';
  static final String mediaUrl = 'https://aitrainer.info:4343/media/';
  static final String username = 'bosi';
  static final String password = 'andio2009';

  String authToken = "";
  Customer userLoggedIn;
  bool firstLoad = true;

  List<ExerciseType> _exerciseTypes;
  List<ExerciseTree> _exerciseTree;

  List<Exercise> _exercises;
  ExercisePlan _myExercisePlan;

  LinkedHashMap<int, ExercisePlanDetail> _myExercisesPlanDetails = LinkedHashMap<int, ExercisePlanDetail>();

  LinkedHashMap _tree = LinkedHashMap<String, WorkoutMenuTree>();
  double _percentExercises = -1;

  Customer _trainee;
  List<Exercise> _exercisesTrainee;
  ExercisePlan _traineeExercisePlan;
  List<ExercisePlanDetail> _traineeExercisesPlanDetail;

  List deviceLanguages;
  String startPage;

  factory Cache() {
    return _singleton;
  }

  Cache._internal() {
    String testEnv = EnvironmentConfig.test_env;
    if ( testEnv == "1") {
      baseUrl = 'http://aitrainer.app:8899/api/';
    }
  }

  void setTestBaseUrl() {
    baseUrl = 'http://aitrainer.app:8899/api/';
  }

  String getAuthToken() {
    return this.authToken;
  }

  static String getToken(SharedPreferences prefs) {
    return prefs.getString(authTokenKey);
  }

  static String getBaseUrl() {
    return baseUrl;
  }

  static String getMediaUrl() {
    return mediaUrl;
  }

  afterRegistration(Customer customer) {
    Future<SharedPreferences> prefs = SharedPreferences.getInstance();

    userLoggedIn = customer;
    setPreferences(prefs, SharePrefsChange.registration, customer.customerId);
  }

  afterLogin(Customer customer) async {
    Future<SharedPreferences> prefs = SharedPreferences.getInstance();

    userLoggedIn = customer;
    await setPreferences(prefs, SharePrefsChange.login, customer.customerId);
  }

  logout() async {
    userLoggedIn = null;
    authToken = "";
    _trainee = null;
    _percentExercises = -1;
    _exercisesTrainee = null;
    _traineeExercisePlan = null;
    _exercises = List();
    _myExercisesPlanDetails = LinkedHashMap();
    print("Trainees is null? " + (_trainee == null).toString() );
    Future<SharedPreferences> prefs = SharedPreferences.getInstance();
    await setPreferences(prefs, SharePrefsChange.logout, 0);
  }

  setPreferences(Future<SharedPreferences> prefs,
                SharePrefsChange type,
                int customerId) async {
    SharedPreferences sharedPreferences;
    sharedPreferences = await prefs;

    DateTime now = DateTime.now();
    sharedPreferences.setString(Cache.lastStoreDateKey, now.toString());
    ExerciseRepository exerciseRepository = ExerciseRepository();
    if ( type == SharePrefsChange.registration ) {
      Cache().startPage = "home";
      sharedPreferences.setInt(Cache.customerIdKey, customerId);
      sharedPreferences.setBool(Cache.isRegisteredKey, true);
      sharedPreferences.setBool(Cache.isLoggedInKey, true);
      await ExerciseTypeApi().getExerciseTypes();
      await ExerciseTreeApi().getExerciseTree();
      exerciseRepository.getExercisesByCustomer(customerId);
    } else if ( type == SharePrefsChange.login ) {
      Cache().startPage = "home";
      sharedPreferences.setInt(Cache.customerIdKey, customerId);
      sharedPreferences.setBool(Cache.isLoggedInKey, true);
      await ExerciseTypeApi().getExerciseTypes();
      await ExerciseTreeApi().getExerciseTree();
      exerciseRepository.getExercisesByCustomer(customerId);
    } else if ( type == SharePrefsChange.logout ) {
      sharedPreferences.setBool(Cache.isLoggedInKey, false);
      sharedPreferences.setInt(Cache.customerIdKey, 0);
      sharedPreferences.setString(authTokenKey, "");
    }
  }

  void setExerciseTypes( List<ExerciseType> exerciseTypes) {
    this._exerciseTypes = exerciseTypes;
  }

  void setExerciseTree( List<ExerciseTree> exerciseTree) {
    this._exerciseTree = exerciseTree;
  }

  void setExercises( List<Exercise> exercises ) {
    this._exercises = exercises;
  }

  void setExercisesTrainee( List<Exercise> exercises ) {
    this._exercisesTrainee = exercises;
  }

  void setWorkoutMenuTree( LinkedHashMap<String, WorkoutMenuTree> tree) {
    this._tree = tree;
  }

  List<ExerciseType> getExerciseTypes() => this._exerciseTypes;

  List<ExerciseTree> getExerciseTree() => this._exerciseTree;

  List<Exercise> getExercises() => this._exercises;

  List<Exercise> getExercisesTrainee() => this._exercisesTrainee;

  LinkedHashMap<String, WorkoutMenuTree> getWorkoutMenuTree() => this._tree;

  void setPercentExercises(double percent) => this._percentExercises = percent;

  double getPercentExercises() => this._percentExercises;

  void addExercise(Exercise exercise) => _exercises.add(exercise);

  void addExerciseTrainee(Exercise exercise) => _exercisesTrainee.add(exercise);

  Customer getTrainee() => this._trainee;

  void setTrainee(Customer trainee) => _trainee = trainee;

  void setTraineeExercisePlan(ExercisePlan exercisePlan) =>  this._traineeExercisePlan = exercisePlan;

  ExercisePlan getTraineesExercisePlan() => this._traineeExercisePlan;

  void setMyExercisePlan(ExercisePlan exercisePlan) => _myExercisePlan = exercisePlan;

  ExercisePlan getMyExercisePlan() => _myExercisePlan;

  void setMyExercisePlanDetails(LinkedHashMap<int, ExercisePlanDetail> listExercisePlanDetail)
    => _myExercisesPlanDetails = listExercisePlanDetail;

  void addToMyExercisePlanDetails(ExercisePlanDetail detail) => _myExercisesPlanDetails[detail.exerciseTypeId] = detail;

  LinkedHashMap<int, ExercisePlanDetail> getMyExercisePlanDetails() => _myExercisesPlanDetails;

  void resetMyExercisePlanDetails() => _myExercisesPlanDetails = LinkedHashMap<int, ExercisePlanDetail>();

  void updateMyExercisePlanDetail(ExercisePlanDetail detail) {
    this.addToMyExercisePlanDetails(detail);
  }

  void deleteMyExercisePlanDetail(ExercisePlanDetail detail)
    => this.deleteMyExercisePlanDetailByExerciseTypeId(detail.exerciseTypeId);

  void deletedMyExercisePlanDetail(ExercisePlanDetail detail)
    => this._myExercisesPlanDetails[detail.exerciseTypeId].change = ExercisePlanDetailChange.deleted;

  void deleteMyExercisePlanDetailByExerciseTypeId(int exerciseTypeId) {
    this._myExercisesPlanDetails[exerciseTypeId].change = ExercisePlanDetailChange.delete;
  }



}