import 'dart:collection';
import 'dart:convert';
import 'package:flutter/foundation.dart';
import 'package:package_info_plus/package_info_plus.dart';
import 'package:workouttest_util/model/customer.dart';
import 'package:workouttest_util/model/customer_activity.dart';
import 'package:workouttest_util/model/customer_property.dart';
import 'package:workouttest_util/model/customer_training_plan.dart';
import 'package:workouttest_util/model/description.dart';
import 'package:workouttest_util/model/evaluation.dart';
import 'package:workouttest_util/model/exercise_plan.dart';
import 'package:workouttest_util/model/exercise_plan_detail.dart';
import 'package:workouttest_util/model/exercise_plan_template.dart';
import 'package:workouttest_util/model/exercise_tree.dart';
import 'package:workouttest_util/model/exercise.dart';
import 'package:workouttest_util/model/faq.dart';
import 'package:workouttest_util/model/model_change.dart';
import 'package:workouttest_util/model/product.dart' as wt_product;
import 'package:workouttest_util/model/product.dart';
import 'package:workouttest_util/model/property.dart';
import 'package:workouttest_util/model/purchase.dart';
import 'package:workouttest_util/model/split_test.dart';
import 'package:workouttest_util/model/sport.dart';
import 'package:workouttest_util/model/training_plan.dart';
import 'package:workouttest_util/model/training_plan_day.dart';
import 'package:workouttest_util/model/tutorial.dart';
import 'package:workouttest_util/model/workout_menu_tree.dart';
import 'package:workouttest_util/repository/customer_repository.dart';
import 'package:workouttest_util/service/firebase_api.dart';
import 'package:workouttest_util/service/package_service.dart';
import 'package:workouttest_util/util/enums.dart';
import 'package:workouttest_util/util/env.dart';
import 'package:workouttest_util/util/track.dart';
import 'package:firebase_remote_config/firebase_remote_config.dart';
import 'package:flutter_facebook_auth/flutter_facebook_auth.dart';
import 'package:matomo_tracker/matomo_tracker.dart';
import 'package:posthog_session/posthog_session.dart';
// ignore: depend_on_referenced_packages
import 'package:shared_preferences/shared_preferences.dart';
import 'package:workouttest_util/model/exercise_type.dart';
// ignore: depend_on_referenced_packages
import 'package:intl/intl.dart';

import '../util/logging.dart';
import 'customer_exercise_device.dart';
import 'exercise_device.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
 */

enum ActivityDone {
  tutorialExecuteFirstTest,
  tutorialBasic,
  tutorialBasicChestPress,
  tutorialBasicLegPress,
  tutorialDevelopment,
  isExerciseLogSeen,
  isMuscleDevelopmentSeen,
  isBodyTypeSeen,
  exerciseSaveTestTip,
  exerciseSaveTrainingTip,
  exerciseSaveTestsetTip
}

extension ActivityDoneExt on ActivityDone {
  String toStr() => toString().split(".").last;
  bool equalsTo(ActivityDone value) => toString() == value.toString();
  bool equalsStringTo(String value) => toStr() == value;

  ActivityDone? searchByString(String activityString) {
    ActivityDone? activity;
    for (var element in ActivityDone.values) {
      if (element.equalsStringTo(activityString)) {
        activity = element;
      }
    }
    return activity;
  }
}

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

  // Keys to store and fetch data from SharedPreferences
  static const String authTokenKey = "auth_token";
  static const String customerIdKey = "customer_id";
  static const String firebaseUidKey = "firebase_uid";
  static const String lastStoreDateKey = "last_date";
  static const String isRegisteredKey = "is_registered";
  static const String isLoggedInKey = "is_logged_in";
  static const String langKey = "lang";
  static const String serverKey = "live";
  static const String hardwareKey = "hardware";
  static const String loginTypeKey = "login_type";
  static const String timerDisplayKey = "timer_display";
  static const String activeExercisePlanKey = "active_exercise_plan";
  static const String activeExercisePlanDateKey = "active_exercise_plan_date";
  static const String activeExercisePlanDetailsKey = "active_exercise_details_plan";
  static const String myTrainingPlanKey = "myTrainingPlan";

  static String baseUrlLive = 'https://api.workouttest.org/api/';
  static String baseUrlTest = 'https://apitest.workouttest.org/api/';
  static String baseUrlDiet = 'https://api.diet4you.eu/api/';
  static String baseUrlDietTest = 'https://apitest.diet4you.eu/api/';
  static String baseUrlLocal = 'http://localhost:8443/api/';
  late String baseUrl;
  static const String mediaUrl = 'https://admin.workouttest.org/media/';
  static const String username = 'bosi';
  static const String password = 'andio2009';

  String authToken = "";
  AccessToken? accessTokenFacebook;
  Customer? userLoggedIn;
  String? firebaseUid;
  String? firebaseMessageToken;
  LoginType? loginType;
  PackageInfo? packageInfo;

  bool hasPurchased = false;

  bool firstLoad = true;

  List<ExerciseType>? _exerciseTypes;
  List<ExerciseTree>? _exerciseTree;
  List<Evaluation>? evaluations;

  List<Exercise>? _exercises;
  ExercisePlan? _myExercisePlan;
  List<Property>? _properties;
  List<Sport>? _sports;
  List<wt_product.Product>? _products;
  List<Purchase> _purchases = [];
  List<SplitTest> _splitTests = [];
  List<TrainingPlanDay> _trainingPlanDays = [];

  List<ExercisePlanTemplate> _exercisePlanTemplates = [];

  ExercisePlan? activeExercisePlan;
  CustomerTrainingPlan? myTrainingPlan;
  List<ExercisePlanDetail>? activeExercisePlanDetails;

  List<ExerciseDevice>? _devices;

  List<CustomerExerciseDevice>? _customerDevices;
  List<CustomerActivity>? _customerActivities;
  List<CustomerTrainingPlan>? _customerTrainingPlans;
  List<CustomerProperty>? _customerPropertyAll;

  List<Tutorial>? _tutorials;
  List<Description>? _descriptions;
  List<Faq>? _faqs;
  List<TrainingPlan>? _trainingPlans;

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

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

  Customer? _trainee;
  List<Exercise>? _exercisesTrainee;
  ExercisePlan? _traineeExercisePlan;

  FirebaseRemoteConfig? remoteConfig;

  LinkedHashMap<String, int> _badges = LinkedHashMap();

  List? deviceLanguages;
  String startPage = "home";
  late String testEnvironment;
  bool liveServer = true;
  bool? hasHardware = false;

  HashMap<String, bool> activitiesDone = HashMap();

  factory Cache() {
    return _singleton;
  }

  Cache._internal() {
    String testEnv = EnvironmentConfig.test_env;
    testEnvironment = testEnv;
    log("testEnv $testEnv");
    if (testEnv == "1") {
      baseUrl = baseUrlTest;
      liveServer = false;
    } else if (testEnv == "2") {
      baseUrl = baseUrlLocal;
      liveServer = false;
    }

    for (var element in ActivityDone.values) {
      activitiesDone[element.toStr()] = false;
    }
  }

  void setTestBaseUrl() {
    baseUrl = baseUrlTest;
  }

  void setDietTestBaseUrl() {
    baseUrl = baseUrlDietTest;
  }

  void setDietBaseUrl() {
    baseUrl = baseUrlDiet;
  }

  void setLocalBaseUrl() {
    baseUrl = baseUrlLocal;
  }

  String getAuthToken() {
    return authToken;
  }

  Future<void> deleteCustomerId(int customerId) async {
    Future<SharedPreferences> prefs = SharedPreferences.getInstance();
    SharedPreferences sharedPreferences = await prefs;
    sharedPreferences.remove(Cache.customerIdKey);
  }

  Future<void> saveActiveExercisePlan(ExercisePlan exercisePlan, List<ExercisePlanDetail> exercisePlanDetails) async {
    activeExercisePlan = exercisePlan;
    activeExercisePlanDetails = exercisePlanDetails;
    String exercisePlanJson = const JsonEncoder().convert(exercisePlan.toJson());
    String detailsJson = jsonEncode(exercisePlanDetails.map((i) => i.toJsonWithExerciseList()).toList()).toString();

    Future<SharedPreferences> prefs = SharedPreferences.getInstance();
    SharedPreferences sharedPreferences;
    sharedPreferences = await prefs;

    final DateTime now = DateTime.now();
    sharedPreferences.setString(Cache.activeExercisePlanKey, exercisePlanJson);
    sharedPreferences.setString(Cache.activeExercisePlanDetailsKey, detailsJson);
    String savingDay = DateFormat("yyyy-MM-dd HH:mm:ss").format(now);
    sharedPreferences.setString(Cache.activeExercisePlanDateKey, savingDay);
  }

  Future<void> saveMyTrainingPlan() async {
    if (myTrainingPlan == null) {
      return;
    }
    String myTrainingPlanJson = const JsonEncoder().convert(myTrainingPlan!.toJsonWithDetails());

    Future<SharedPreferences> prefs = SharedPreferences.getInstance();
    SharedPreferences sharedPreferences;
    sharedPreferences = await prefs;
    sharedPreferences.setString(Cache.myTrainingPlanKey, myTrainingPlanJson);
  }

  Future<void> deleteMyTrainingPlan() async {
    if (myTrainingPlan == null) {
      return;
    }

    Future<SharedPreferences> prefs = SharedPreferences.getInstance();
    SharedPreferences sharedPreferences;
    sharedPreferences = await prefs;
    sharedPreferences.remove(Cache.myTrainingPlanKey);
  }

  Future<void> getMyTrainingPlan() async {
    Future<SharedPreferences> prefs = SharedPreferences.getInstance();
    SharedPreferences sharedPreferences;
    sharedPreferences = await prefs;

    final String? savedTrainingPlanJson = sharedPreferences.getString(Cache.myTrainingPlanKey);
    if (savedTrainingPlanJson == null) {
      return;
    }
    //String jsonPlan = savedTrainingPlanJson.replaceAllMapped(RegExp(r'[a-zA-Z]+\:'), (Match m) => "\"${m[0]}\"");
    Map<String, dynamic> map;
    try {
      map = const JsonDecoder().convert(savedTrainingPlanJson);
      //log("Training plan: $savedTrainingPlanJson");
      myTrainingPlan = CustomerTrainingPlan.fromJsonWithDetails(map);
    } on Exception catch (e) {
      log(e.toString());
    }
  }

  Future<void> deleteActiveExercisePlan() async {
    Future<SharedPreferences> prefs = SharedPreferences.getInstance();
    SharedPreferences sharedPreferences;
    sharedPreferences = await prefs;

    sharedPreferences.remove(Cache.activeExercisePlanDateKey);
    activeExercisePlan = null;
    activeExercisePlanDetails = null;
  }

  Future<void> getActiveExercisePlan() async {
    Future<SharedPreferences> prefs = SharedPreferences.getInstance();
    SharedPreferences sharedPreferences;
    sharedPreferences = await prefs;

    final savedPlanDateString = sharedPreferences.getString(Cache.activeExercisePlanDateKey);
    if (savedPlanDateString == null) {
      return;
    }

    DateFormat format = DateFormat("yyyy-MM-dd HH:mm:ss");
    DateTime savedPlanDate;

    savedPlanDate = format.parse(savedPlanDateString);
    log("Saved plan: $savedPlanDate");

    final DateTime now = DateTime.now();
    final DateTime added = savedPlanDate.add(const Duration(days: 1));
    if (added.isBefore(now)) {
      return;
    }

    String? exercisePlanJson = sharedPreferences.getString(Cache.activeExercisePlanKey);
    if (exercisePlanJson != null) {
      final Map<String, dynamic> map = const JsonDecoder().convert(exercisePlanJson);
      activeExercisePlan = ExercisePlan.fromJson(map);
    }

    String? detailsJson = sharedPreferences.getString(Cache.activeExercisePlanDetailsKey);
    if (detailsJson != null) {
      Iterable json = jsonDecode(detailsJson);
      activeExercisePlanDetails = json.map((details) => ExercisePlanDetail.fromJsonWithExerciseList(details)).toList();
    }
  }

  Future<void> setServer(bool live) async {
    if (testEnvironment == "1") {
      liveServer = false;
      live = false;
    }
    Future<SharedPreferences> prefs = SharedPreferences.getInstance();
    SharedPreferences sharedPreferences;
    sharedPreferences = await prefs;
    liveServer = live;
    sharedPreferences.setBool(Cache.serverKey, live);
  }

  void getHardware(SharedPreferences prefs) {
    final bool? hasHardware = prefs.getBool(Cache.hardwareKey);
    this.hasHardware = hasHardware;
    if (hasHardware == null) {
      this.hasHardware = false;
    }
  }

  Future<bool> selectedHardwareBefore() async {
    Future<SharedPreferences> prefs = SharedPreferences.getInstance();
    SharedPreferences sharedPreferences = await prefs;

    final bool? selectedHardware = sharedPreferences.getBool(Cache.hardwareKey);
    return selectedHardware == null;
  }

  Future<void> setHardware(bool hasHardware) async {
    Future<SharedPreferences> prefs = SharedPreferences.getInstance();
    SharedPreferences sharedPreferences;
    sharedPreferences = await prefs;
    sharedPreferences.setBool(Cache.hardwareKey, hasHardware);
    hasHardware = hasHardware;
  }

  void setServerAddress(SharedPreferences prefs) {
    if (testEnvironment == "1") {
      baseUrl = baseUrlTest;
      log("TestEnv $baseUrl");
      return;
    } else if (testEnvironment == "2") {
      baseUrl = baseUrlLocal;
      log("TestEnv $baseUrl");
      return;
    }
    final bool? live = prefs.getBool(Cache.serverKey);
    if (live == null) {
      baseUrl = baseUrlLive;
      log("Live Env $baseUrl");
      liveServer = true;
      return;
    }
    liveServer = live;
    if (live) {
      baseUrl = baseUrlLive;
    } else {
      baseUrl = baseUrlTest;
    }

    log("Env $baseUrl");
  }

  Future<void> setLoginTypeFromPrefs() async {
    Future<SharedPreferences> prefs = SharedPreferences.getInstance();
    SharedPreferences sharedPreferences = await prefs;
    final String? loginType = sharedPreferences.getString(Cache.loginTypeKey);
    LoginType type = LoginType.email;
    if (loginType == LoginType.apple.toString()) {
      type = LoginType.apple;
    } else if (loginType == LoginType.google.toString()) {
      type = LoginType.google;
    } else if (loginType == LoginType.fb.toString()) {
      type = LoginType.fb;
    } else if (loginType == LoginType.email.toString()) {
      type = LoginType.email;
    }
    //log("LoginType: " + loginType == null ? "NULL" : loginType);
    Cache().setLoginType(type);
  }

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

  String getBaseUrl() {
    return baseUrl;
  }

  static String getMediaUrl() {
    return mediaUrl;
  }

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

    userLoggedIn = customer;
    final String uid = Cache().firebaseUid!;
    SharedPreferences sharedPreferences = await prefs;
    sharedPreferences.setString(Cache.loginTypeKey, Cache().getLoginType().toString());
    await setPreferences(prefs, SharePrefsChange.registration, customer.customerId!, uid);
  }

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

    userLoggedIn = customer;
    SharedPreferences sharedPreferences = await prefs;
    sharedPreferences.setString(Cache.loginTypeKey, Cache().getLoginType().toString());
    await setPreferences(prefs, SharePrefsChange.login, customer.customerId!, Cache().firebaseUid!);
  }

  afterFirebaseLogin() async {
    Future<SharedPreferences> prefs = SharedPreferences.getInstance();
    SharedPreferences sharedPreferences = await prefs;
    sharedPreferences.setString(Cache.loginTypeKey, Cache().getLoginType().toString());
    await setPreferences(prefs, SharePrefsChange.login, userLoggedIn!.customerId!, Cache().firebaseUid!);
  }

  afterFacebookLogin() async {
    Future<SharedPreferences> prefs = SharedPreferences.getInstance();
    SharedPreferences sharedPreferences = await prefs;
    sharedPreferences.setString(Cache.loginTypeKey, Cache().getLoginType().toString());
    await setPreferences(prefs, SharePrefsChange.login, userLoggedIn!.customerId!, Cache().firebaseUid!);
  }

  logout() async {
    if (accessTokenFacebook != null) {
      await FirebaseApi().logOutFacebook();
    }
    userLoggedIn = null;
    firebaseUid = null;
    authToken = "";
    _trainee = null;
    _percentExercises = -1;
    _exercisesTrainee = null;
    _traineeExercisePlan = null;
    _exercises = [];
    _myExercisesPlanDetails = LinkedHashMap();
    log("Trainees is null? ${_trainee == null}");
    Future<SharedPreferences> prefs = SharedPreferences.getInstance();
    await setPreferences(prefs, SharePrefsChange.logout, 0, "");
  }

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

    DateTime now = DateTime.now();
    sharedPreferences.setString(Cache.lastStoreDateKey, now.toString());
    if (type == SharePrefsChange.registration) {
      sharedPreferences.setInt(Cache.customerIdKey, customerId);
      sharedPreferences.setBool(Cache.isRegisteredKey, true);
      sharedPreferences.setBool(Cache.isLoggedInKey, true);
      sharedPreferences.setString(Cache.firebaseUidKey, firebaseUid);
      await initCustomer(customerId);
    } else if (type == SharePrefsChange.login) {
      sharedPreferences.setInt(Cache.customerIdKey, customerId);
      sharedPreferences.setString(Cache.firebaseUidKey, firebaseUid);
      sharedPreferences.setBool(Cache.isLoggedInKey, true);
      await initCustomer(customerId);
    } else if (type == SharePrefsChange.logout) {
      sharedPreferences.setBool(Cache.isLoggedInKey, false);
      sharedPreferences.setInt(Cache.customerIdKey, 0);
      sharedPreferences.setString(Cache.firebaseUidKey, "");
      sharedPreferences.setString(authTokenKey, "");
    }
    initBadges();
  }

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

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

  void setExercises(List<Exercise> exercises) => _exercises = exercises;

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

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

  List<ExerciseType>? getExerciseTypes() => _exerciseTypes;

  ExerciseType? getExerciseTypeById(int exerciseTypeId) {
    ExerciseType? exerciseType;
    if (_exerciseTypes != null) {
      for (var element in _exerciseTypes!) {
        if (element.exerciseTypeId == exerciseTypeId) {
          exerciseType = element;
        }
      }
    }
    return exerciseType;
  }

  List<ExerciseTree>? getExerciseTree() => _exerciseTree;

  List<Exercise>? getExercises() => _exercises;

  List<Exercise>? getExercisesTrainee() => _exercisesTrainee;

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

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

  double getPercentExercises() => _percentExercises;

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

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

  Customer? getTrainee() => _trainee;

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

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

  ExercisePlan? getTraineesExercisePlan() => _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) {
    addToMyExercisePlanDetails(detail);
  }

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

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

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

  void setProperties(List<Property> properties) => _properties = properties;
  List<Property>? getProperties() => _properties;

  List<Sport>? getSports() => _sports;
  void setSports(List<Sport> sports) => _sports = sports;

  void setDevices(List<ExerciseDevice> devices) => _devices = devices;

  List<ExerciseDevice>? getDevices() => _devices;

  void setCustomerDevices(List<CustomerExerciseDevice> devices) => _customerDevices = devices;

  List<CustomerExerciseDevice>? getCustomerDevices() => _customerDevices;

  LinkedHashMap getBadges() => _badges;

  void setBadge(String key, bool inc) {
    if (inc) {
      if (_badges[key] != null) {
        _badges[key] = _badges[key]! + 1;
      } else {
        _badges[key] = 1;
      }
    } else {
      if (_badges[key] != null) {
        if (_badges[key] == 1) {
          _badges.remove(key);
        } else {
          _badges[key] = _badges[key]! - 1;
        }
      }
    }
  }

  void setBadgeNr(String key, int counter) {
    if (_badges[key] != null) {
      _badges[key] = _badges[key]! + counter;
    } else {
      _badges[key] = counter;
    }
  }

  void initBadges() {
    CustomerRepository customerRepository = CustomerRepository();
    _badges = LinkedHashMap();
    if (userLoggedIn == null) {
      return;
    }
    customerRepository.setCustomer(userLoggedIn!);
    int ecto = customerRepository.getCustomerPropertyValue(PropertyEnum.Ectomorph.toStr()).toInt();
    int mezo = customerRepository.getCustomerPropertyValue(PropertyEnum.Mesomorph.toStr()).toInt();
    int endo = customerRepository.getCustomerPropertyValue(PropertyEnum.Endomorph.toStr()).toInt();

    //log("endo " + _endo.toString() + " mezo " + _mezo.toString());
    if (userLoggedIn != null) {
      if (userLoggedIn!.birthYear == null || userLoggedIn!.birthYear == 0) {
        setBadge("personalData", true);
        setBadge("account", true);
      }
      if (_customerDevices == null || _customerDevices!.isEmpty) {
        setBadge("customerDevice", true);
        setBadge("account", true);
      }
      if (userLoggedIn!.properties.isEmpty) {
        setBadge("personalData", true);
        setBadge("bodyType", true);
        setBadge("Sizes", true);
        setBadge("BMI", true);
        setBadge("BMR", true);
        setBadgeNr("My Body", 3);
        setBadgeNr("home", 3);
      } else if (customerRepository.getWeight() == 0) {
        setBadge("BMI", true);
        setBadge("BMR", true);
        setBadge("My Body", true);
        setBadgeNr("home", 1);
      }
      if (ecto == 0 && mezo == 0 && endo == 0) {
        setBadge("account", true);
        setBadge("bodyType", true);
      }
      if (_exercises == null || _exercises!.isEmpty) {
        setBadge("home", true);
        setBadge("Custom Tests", true);
        setBadge("Start Training", true);
      }
      if (customerRepository.getHeight() == 0) {
        setBadge("BMI", true);
        setBadge("BMR", true);
        setBadge("My Body", true);
        setBadgeNr("home", 1);
      }
      if (userLoggedIn!.goal == null) {
        setBadge("Goal", true);
        setBadge("account", true);
      }
      if (userLoggedIn!.fitnessLevel == null) {
        setBadge("FitnessLevel", true);
        setBadge("account", true);
      }
      if (_exercises != null && _exercises!.isNotEmpty) {
        if (!activitiesDone[ActivityDone.isExerciseLogSeen.toStr()]!) {
          setBadge("exerciseLog", true);
          setBadge("development", true);
        }
        if (!activitiesDone[ActivityDone.isMuscleDevelopmentSeen.toStr()]!) {
          setBadge("muscleDevelopment", true);
          setBadge("development", true);
        }
      }
    }
    log("Badges: $_badges");
  }

  List<Product>? get products => _products;
  void setProducts(List<wt_product.Product> value) => _products = value;

  List<Purchase> get purchases => _purchases;
  setPurchases(List<Purchase> value) => _purchases = value;

  Future<void> initCustomer(int customerId) async {
    log(" *** initCustomer");
    try {
      await PackageApi().getCustomerPackage(customerId);
    } on Exception catch (_) {
      return;
    }

    if (kReleaseMode) {
      //FlurryData.setUserId(customerId.toString());
      //FlutterUxcam.setUserProperty("username", customerId.toString());
      //FlutterUxcam.setUserIdentity(customerId.toString());
      //Smartlook.setUserIdentifier(customerId.toString());
      //Smartlook.instance.
      Track().track(TrackingEvent.enter);
      MatomoTracker.instance.setVisitorUserId(customerId.toString());
      MatomoTracker.instance.trackEvent(eventCategory: "wt", action: TrackingEvent.enter.enumToString());
      Posthog().identify(userId: customerId.toString());
      Posthog().capture(eventName: TrackingEvent.enter.enumToString());
    }

    await Future.forEach(ActivityDone.values, (element) async {
      ActivityDone activity = element;
      await isActivityDonePrefs(activity);
    });

    log("Firebase token save: $firebaseMessageToken");
    if (firebaseMessageToken != null) {
      userLoggedIn!.firebaseRegToken = firebaseMessageToken;
      CustomerRepository customerRepository = CustomerRepository();
      customerRepository.customer = userLoggedIn;
      customerRepository.saveCustomer();
    }

    await getMyTrainingPlan();

    Cache().startPage = "home";
  }

  AccessToken? get getAccessTokenFacebook => accessTokenFacebook;
  set setAccessTokenFacebook(AccessToken accessTokenFacebook) => accessTokenFacebook = accessTokenFacebook;

  LoginType? getLoginType() => loginType;
  void setLoginType(LoginType type) => loginType = type;

  List get exercisePlanTemplates => _exercisePlanTemplates;
  setExercisePlanTemplates(value) => _exercisePlanTemplates = value;

  isActivityDonePrefs(ActivityDone activity) async {
    Future<SharedPreferences> prefs = SharedPreferences.getInstance();
    SharedPreferences sharedPreferences = await prefs;
    if (sharedPreferences.getBool(activity.toStr()) != null) {
      activitiesDone[activity.toStr()] = sharedPreferences.getBool(activity.toStr())!;
    }

    return activitiesDone[activity.toStr()]!;
  }

  setActivityDonePrefs(ActivityDone activity) async {
    Future<SharedPreferences> prefs = SharedPreferences.getInstance();
    SharedPreferences sharedPreferences = await prefs;
    activitiesDone[activity.toStr()] = true;
    sharedPreferences.setBool(activity.toStr(), true);
  }

  bool isActivityDone(ActivityDone activity) => activitiesDone[activity.toStr()] == true;

  List<CustomerActivity>? get customerActivities => _customerActivities;
  setCustomerActivities(List<CustomerActivity>? value) => _customerActivities = value;

  List<Tutorial>? get tutorials => _tutorials;
  setTutorials(List<Tutorial>? value) => _tutorials = value;

  FirebaseRemoteConfig? getRemoteConfig() => remoteConfig;
  setRemoteConfig(FirebaseRemoteConfig? remoteConfig) => remoteConfig = remoteConfig;

  List<Description>? getDescriptions() => _descriptions;
  setDescriptions(List<Description>? value) => _descriptions = value;

  List<Faq>? getFaqs() => _faqs;
  setFaqs(List<Faq>? value) => _faqs = value;

  List<TrainingPlan>? getTrainingPlans() => _trainingPlans;
  setTrainingPlans(List<TrainingPlan>? value) => _trainingPlans = value;

  List<CustomerTrainingPlan>? getCustomerTrainingPlans() => _customerTrainingPlans;
  setCustomerTrainingPlans(value) => _customerTrainingPlans = value;

  List<SplitTest> getSplitTests() => _splitTests;
  setSplitTests(value) => _splitTests = value;

  List<TrainingPlanDay> getTrainingPlanDays() => _trainingPlanDays;
  setTrainingPlanDays(value) => _trainingPlanDays = value;

  List<CustomerProperty>? getCustomerPropertyAll() => _customerPropertyAll;
  setCustomerPropertyAll(value) => _customerPropertyAll = value;
  addCustomerProperty(CustomerProperty property) {
    _customerPropertyAll ??= [];
    _customerPropertyAll!.add(property);
  }
}