import 'dart:async';
import 'dart:io';

import 'package:app_usage/app_usage.dart';
import 'package:flutter/cupertino.dart';
import 'package:flutter/foundation.dart' as K;
import 'package:intl/intl.dart';
import 'package:shared_preferences/shared_preferences.dart';
import 'package:tasktracker/NewProject.dart';
import 'package:tasktracker/NotificationsManager.dart';
import 'DebugHelper.dart';
import 'main.dart';
import 'package:http/http.dart' as http;
import 'dart:convert';
import 'Data.dart';
import 'package:sqflite/sqflite.dart';
import 'package:sqflite_common_ffi/sqflite_ffi.dart' as SqlFF;
import 'package:path_provider/path_provider.dart';
import 'package:device_info_plus/device_info_plus.dart';
import 'package:sqflite_common/sqlite_api.dart';
import 'Tasks.dart';
import 'Dialogs.dart';

bool cacheEnabled = !K.kIsWeb;

late http.Response loginResponse;

late var cacheDb;
late String username;
List<Category> categories = [];
List<TaskType> taskTypes = [];
List<Activity> activities = [];
List<Project> projects = [];
List<Journal> journal = [];
List<Todo> todos = [];
const API_ENDPOINT = 'http://vps.playpoolstudios.com';
bool offline = true;
bool registered = false;
StreamController<bool> refreshStream = StreamController.broadcast();
Future<http.Response> login(String _username, String password) async {
  final prefs = await SharedPreferences.getInstance();
  username = _username;
  var device_id = await Settings.UUID();
  try {
    loginResponse = (await http.post(
        Uri.parse('http://vps.playpoolstudios.com/task_tracker/login.php'),
        body: <String, String>{
          "username": _username,
          "password": password,
          "device_id": device_id
        }));

    if (loginResponse.body.toLowerCase().contains("success")) {
      offline = false;
      username = _username;
      registered = loginResponse.body.toLowerCase().contains("register");

      Debug.Log("registered : $registered");
      if (registered) {
        prefs.setBool("registered", true);
      }
    }
  } catch (e) {
    Debug.LogError("Error while login $e");
  }
  return loginResponse;
}

Future<void> initUserData() async {
  if (cacheEnabled) {
    await initCacheDatabase();
    int catCount = Sqflite.firstIntValue(
            await cacheDb.rawQuery('SELECT COUNT(*) FROM Categories')) ??
        0;
    int taskCount = Sqflite.firstIntValue(
            await cacheDb.rawQuery('SELECT COUNT(*) FROM TaskTypes')) ??
        0;
    if (catCount > 0 && taskCount > 0) {
      await refreshUserData(forceOffline: true);
      refreshUserData();
    } else {
      await refreshUserData();
    }
  }

  BuildBridgeToServer();
  InitUsageListener();
  Debug.Log('Initializing UserData...');

  if (cacheEnabled) {
    // if (Platform.isAndroid || Platform.isIOS) {
    //   Connectivity().onConnectivityChanged.listen((result) {
    //     offline = (result == ConnectivityResult.none);
    //     if (!offline) {
    //       UserOperations.executeQueries();
    //       refreshUserData();
    //     }
    //   });
    // }
  }
}

Future<void> BuildBridgeToServer() async {
  final prefs = await SharedPreferences.getInstance();

  while (true) {
    await UserOperations.executeQueries();
    try {
      http.Response response = (await http.post(
          Uri.parse(API_ENDPOINT + '/task_tracker/bridge.php'),
          body: <String, String>{"username": username}));

      Debug.LogResponse("${response.body}", src: 'bridge');

      List<String> data = response.body.split(",");
      Debug.LogResponse(
          'Update :\nactivities_rev=${data[0]} tasks_rev=${data[1]} cats_rev=${data[2]} projects_rev=${data[3]}');
      bool changedOffline = offline == true;
      offline = false;
      if (changedOffline) {
        refreshStream.add(false);
      }
      if (data[4].contains('<td>')) {
        List<String> ongoingData = data[4].split("<td>");
        if (!prefs.containsKey('current_activity')) {
          StartActivityTimer(
              ongoingData[0], ongoingData[1], DateTime.parse(ongoingData[2]));
        }
      } else {
        if (prefs.containsKey('current_activity')) CancelOngoingActivity();
      }

      if (prefs.containsKey('rev')) {
        if (prefs.getString('rev') == response.body) {
          Debug.Log('We are on the same page');
        } else {
          Debug.Log('Gotta update');
          await refreshUserData();
          prefs.setString('rev', response.body);
        }
      } else {
        prefs.setString('rev', response.body);
        await refreshUserData();
      }
    } catch (e) {
      Debug.LogError("Error with bridge : $e");
      bool changedOffline = offline == false;
      offline = true;
      if (changedOffline) {
        refreshStream.add(false);
      }
    }
    await Future.delayed(Duration(seconds: 5));
  }
}
const APP_USAGE_KEY_NAME = "app_usage_data";
Future<void> InitUsageListener() async {
  final prefs = await SharedPreferences.getInstance();
  var delay = Duration(seconds: 10);
  if(!prefs.containsKey(APP_USAGE_KEY_NAME)){
    prefs.setString(APP_USAGE_KEY_NAME, "");
  }

  List<AppUsageInfo> app_usage = [];
  while (true) {
    List<AppUsageInfo> appUsage = await AppUsage().getAppUsage(DateTime.now().subtract(delay), DateTime.now());

    List<AppUsageInfo> prev_appUsage = jsonDecode(prefs.getString(APP_USAGE_KEY_NAME)!);


    Debug.Log("Listening to usage");
    await Future.delayed(delay);
  }
}

bool m_refreshing = false;
Future<void> refreshUserData({bool forceOffline = false}) async {
  Debug.Log('refreshing user data');
  if (m_refreshing) {
    Debug.LogError('Called while refreshing. Return');
    return;
  }
  m_refreshing = true;

  if (forceOffline) {
    refreshStream.add(true);
    categories = await GetCategories(true);
    projects = await GetProjects(true);
    taskTypes = await GetTaskTypes(true);
    activities = await GetActivities(true);
    journal = await GetJournals(true);
    todos = await GetTodos(true);

    refreshStream.add(false);
  } else {
    if (K.kIsWeb) {
      Debug.LogTest('updating cats ${DateTime.now()}');
      categories = await GetCategories(false);
      Debug.LogTest('updating projs ${DateTime.now()}');
      projects = await GetProjects(false);
      Debug.LogTest('updating tasks ${DateTime.now()}');
      taskTypes = await GetTaskTypes(false);
      Debug.LogTest('updating acts ${DateTime.now()}');
      activities = await GetActivities(false);
      Debug.LogTest('updating journals ${DateTime.now()}');
      journal = await GetJournals(false);
      Debug.LogTest('updating todos ${DateTime.now()}');
      todos = await GetTodos(false);
      Debug.LogTest('done refreshing ${DateTime.now()}');
    } else {
      Debug.LogTest('Doing super update ${DateTime.now()}');
      refreshStream.add(true);
      try {
        Debug.LogTest('Requesting all data @ ${DateTime.now()}');
        http.Response response = (await http.post(
            Uri.parse(API_ENDPOINT + '/task_tracker/grab_all_data.php'),
            body: <String, String>{
              "username": username,
              "device_id": await Settings.UUID()
            }));
        List<String> data = response.body.split('<tr>');
        Debug.LogTest(
            'Got response for all data [${response.contentLength}bytes] @ ${DateTime.now()}');
        Debug.LogTest(
            'super update items : ${data.length}\nfilling tables\nActivities : ${data[0].length}\nProjects: ${data[1].length}');
        Debug.LogResponse(response.body);
        Debug.LogResponse(data[0], src: 'Activity');
        Debug.LogResponse(data[1], src: 'Categories');
        Debug.LogResponse(data[2], src: 'Projects');
        Debug.LogResponse(data[3], src: 'Journals');
        Debug.LogResponse(data[4], src: 'TaskTypes');
        Debug.LogResponse(data[5], src: 'Todo');

        await fillActivityTable(data[0]);
        await fillCatsTable(data[1]);
        await fillJournalsTable(data[2]);
        await fillProjectsTable(data[3]);
        await fillTaskTypes(data[4]);
        await fillTodosTable(data[5]);

        Debug.LogTest('Done filling @ ${DateTime.now()}');

        categories = await GetCategories(true);
        projects = await GetProjects(true);
        taskTypes = await GetTaskTypes(true);
        activities = await GetActivities(true);
        journal = await GetJournals(true);
        todos = await GetTodos(true);
      } catch (e) {
        Debug.LogError("Error while Super Update $e");
      }
      refreshStream.add(false);
      Debug.LogTest('Done super update ${DateTime.now()}');
    }
    DateTime now = DateTime.now();
    List<AppUsageInfo> appUsage =
        await AppUsage().getAppUsage(now.subtract(Duration(days: 2)), now);

    Debug.Log("Adding auto logs");
    appUsage.forEach((task) {
      bool foundConflict = false;
      for (int i = 1; i < activities.length; i++) {
        Activity act = activities[activities.length - i];

        if (isConflicting(
            act.startTime, act.endTime, task.startDate, task.endDate)) {
          //Got something here
          continue;
        }

        // UserOperations.addActivity("At work", task.startDate, task.endDate);
        Debug.LogTest(task);

        if (act.startTime.isBefore(now.subtract(Duration(days: 2)))) {
          break;
        }
      }
    });
  }

  m_refreshing = false;
  if (cacheEnabled) {
    NotificationManager.RescheduleNotifications();
  }
}

bool isConflicting(
    DateTime start1, DateTime end1, DateTime start2, DateTime end2) {
  if (start1.isBefore(end2) && end1.isAfter(end2)) {
    // 1 starts before 2 and continues after 2 is done
    return true;
  }

  if (end1.isBefore(end2) && end1.isAfter(start2)) {
    // 1 ends within 2
    return true;
  }

  if (start1.isAfter(start2) && start1.isBefore(end2)) {
    //1 starts within 2
    return true;
  }

  if (start1 == start2 || end1 == end2) {
    return true;
  }

  return false;
}

Future<bool> cacheDbExist() async {
  if (!K.kIsWeb && Platform.isAndroid || Platform.isIOS) {
    Directory directory = await getApplicationDocumentsDirectory();
    return databaseFactory.databaseExists(directory.path + 'cache.db');
  } else {
    Directory directory = await getApplicationDocumentsDirectory();
    return SqlFF.databaseFactoryFfi.databaseExists(directory.path + 'cache.db');
  }
}

Future<void> updateCatsList() async {
  categories = await GetCategories(false);
}

Future<void> updateTasksList() async {
  taskTypes = await GetTaskTypes(false);
}

Future<void> updateActList() async {
  activities = await GetActivities(false);
}

Future<void> updateProjectsList() async {
  projects = await GetProjects(false);
}

Future<void> initCacheDatabase() async {
  Directory directory = await getApplicationDocumentsDirectory();
  Debug.LogResponse('database at ' + directory.path + '/cache.db');
  if (!K.kIsWeb && Platform.isAndroid || Platform.isIOS) {
    cacheDb = await openDatabase(directory.path + 'cache.db',
        version: 1,
        onCreate: onCacheDatabaseCreate,
        onUpgrade: onCacheDatabaseUpgrade);
  } else {
    cacheDb = await SqlFF.databaseFactoryFfi.openDatabase(
        directory.path + 'cache.db',
        options:
            OpenDatabaseOptions(version: 1, onCreate: onCacheDatabaseCreate));
  }
  await UserOperations.executeQueries();
}

void onCacheDatabaseCreate(Database db, int newVersion) async {
  String CategoriesTableSQL =
      'CREATE TABLE Categories(${Category.colCatId} VARCHAR(255) PRIMARY KEY,${Category.colName} TEXT, ${Category.colColor} TEXT, ${Category.colProductive} INTEGER)';
//  Debug.Log(CategoriesTableSQL);
  await db.execute(CategoriesTableSQL);
  Debug.Log("Initiated Categories Table");

  String TaskTableSQL =
      'CREATE TABLE TaskTypes(id TEXT PRIMARY KEY, ${TaskType.colName} TEXT, ${TaskType.colCategory} TEXT, ${TaskType.colRelatedProject} TEXT, '
      'FOREIGN KEY (${TaskType.colCategory}) REFERENCES Categories(${Category.colCatId}))';
  // Debug.Log(TaskTableSQL);
  await db.execute(TaskTableSQL);

  String ActivityTableSQL =
      'CREATE TABLE Activities(id INTEGER PRIMARY KEY AUTOINCREMENT, ${Activity.colType} INT, ${Activity.colStartTime} DATETIME, ${Activity.colEndTime} DATETIME, ${Activity.colMetadata} TEXT, '
      'FOREIGN KEY (${Activity.colType}) REFERENCES TaskTypes(id))';
  // Debug.Log(ActivityTableSQL);
  await db.execute(ActivityTableSQL);

  String ProjectsTableSQL =
      'CREATE TABLE Projects(id TEXT PRIMARY KEY, ${Project.colName} TEXT, ${Project.colCat} TEXT, ${Project.colSteps} TEXT, ${Project.colEta} INT, ${Project.colDeadline} DATETIME)';
  await db.execute(ProjectsTableSQL);

  String JournalTableSQL =
      'CREATE TABLE Journal(id TEXT PRIMARY KEY, ${Journal.colTitle} TEXT, ${Journal.colDescription})';
  await db.execute(JournalTableSQL);

  String TodoTableSQL =
      'CREATE TABLE Todos(id TEXT PRIMARY KEY, ${Todo.colCat} TEXT, ${Todo.colMetadata} TEXT, ${Todo.colDueDate} DATE, ${Todo.colNotificationTime} DATETIME)';
  await db.execute(TodoTableSQL);

  String QueriesTableSQL =
      'CREATE TABLE Queries(id INTEGER PRIMARY KEY AUTOINCREMENT, ${Queries.colLink} TEXT,${Queries.colData} TEXT)';
  await db.execute(QueriesTableSQL);

  final prefs = await SharedPreferences.getInstance();

  if (prefs.getBool("registered") ?? false) {
    addInitialDataToCache();
    prefs.setBool("registered", false);
  }
  // GetCategories();
}

Future<void> addInitialDataToCache() async {
  Dialogs.syncingMessage = "Adding initial data";
  Debug.Log("adding init data");
  await Future.delayed(const Duration(seconds: 1));

  //Insert Initial Entries
  for (Category element in InitialData.getCategories(username)) {
    await UserOperations.addCategory(
        element.name, element.color, element.productive,
        bulk: true);
  }
  Dialogs.syncingMessage = "Just a minute";
  for (TaskType element in InitialData.getTaskTypes(username)) {
    await UserOperations.addTaskType(element.name, element.category,
        bulk: true);
    // Map<String,Object> data = {
    //   TaskType.colName: element.name,
    //   TaskType.colCategory: element.category
    // };
    // await cacheDb.insert('TaskTypes', data);
  }
  Dialogs.syncingMessage = "Syncing";
  await UserOperations.executeQueries();
  // await refreshUserData();
}

void onCacheDatabaseUpgrade(Database db, int oldVersion, int newVersion) async {
  //ValidateCacheDB();
  Debug.LogResponse(
      'Upgrading CacheDB from ver.$oldVersion to ver.$newVersion');
}

Future<List<Category>> GetCategories(bool forceOffline) async {
  if (cacheEnabled) {
    List<Category> _categories = [];
    if (offline || forceOffline) {
      //Retreive from cacheDB

    } else {
      //Check if server got updated, If not go for cache
      var android_id = await Settings.UUID();

      //Validate device_id to check updates

      bool catsUpdated = false;
      // try {
      //   http.Response update_response = (await http.post(Uri.parse(API_ENDPOINT+'/task_tracker/check_update.php'), body: <String, String>{"username": username, "device_id": android_id}));
      //   final data = update_response.body.split(',');
      //   catsUpdated = data[0] == '1';
      // } catch (e) {
      //   Debug.Log(e);
      // }

      Debug.Log("Need to update : ${!catsUpdated}");

      //Update CacheDB
      if (!catsUpdated) {
        await UpdateCategoriesFromServer();
      }
    }

    List<Map> cats = await cacheDb.query('Categories');
    Debug.Log('categories :${cats.length}');
    for (Map element in cats) {
      String? catName = element[Category.colName].toString();
      String? catColor = element[Category.colColor].toString();
      String? catProductive = element[Category.colProductive].toString();
      if (catName == null || catColor == null || catProductive == null) {
        Debug.LogError("Something is null!");
        Debug.LogError(
            "name:{$catName}, color:{$catColor}, prod:{$Category.colProductive}");
        continue;
      }
      //  Debug.Log("name:{$catName}, color:{$catColor}, prod:{$catProductive}");
      _categories.add(Category(
          username + catName, catName, catColor, ParseBool(catProductive)));
    }
    categories = _categories;
  } else {
    Debug.Log("NC: Updating Categories as $username");
    try {
      http.Response response = (await http.post(
          Uri.parse(API_ENDPOINT + '/task_tracker/get_categories.php'),
          body: <String, String>{
            "username": username,
            "device_id": await Settings.UUID()
          }));

      Debug.LogResponse(response.body, src: 'get_categories');
      List<String> data = response.body.split("<td>");
      List<Category> _categories = [];
      for (var value in data) {
        Map<String, dynamic> cat = jsonDecode(value);
        _categories.add(Category(cat['category_id'], cat['name'], cat['color'],
            ParseBool(cat['productive'])));
      }
      categories = _categories;
    } catch (e) {
      Debug.LogError("Error while cats NC: $e");
    }
  }
  return categories;
}

Future<void> UpdateCategoriesFromServer() async {
  Debug.Log("Updating Categories as $username");
  try {
    http.Response response = (await http.post(
        Uri.parse(API_ENDPOINT + '/task_tracker/get_categories.php'),
        body: <String, String>{
          "username": username,
          "device_id": await Settings.UUID()
        }));

    Debug.LogResponse(response.body);
    await fillCatsTable(response.body);
  } catch (e) {
    Debug.LogError("Error while cats $e");
  }
}

Future<void> fillCatsTable(String response) async {
  List<String> data = response.split("<td>");
  await cacheDb.delete("Categories");
  for (var value in data) {
    Map<String, dynamic> cat = jsonDecode(value);
    //Debug.Log(catData);
    await cacheDb.rawInsert(
        "INSERT OR REPLACE INTO Categories (${Category.colCatId},${Category.colName},${Category.colProductive},${Category.colColor}) "
        "VALUES ('${cat['category_id']}','${cat['name']}',${cat['productive']},'${cat['color']}') ");
  }
}

Future<List<TaskType>> GetTaskTypes(bool forceOffline) async {
  if (cacheEnabled) {
    List<TaskType> _taskTypes = [];
    if (offline || forceOffline) {
      //Retreive from cacheDB

    } else {
      //Check if server got updated, If not go for cache
      var android_id = await Settings.UUID();

      bool updated = false;
      // try {
      //   //Validate device_id to check updates
      //   http.Response update_response = (await http.post(Uri.parse(API_ENDPOINT+'/task_tracker/check_update.php'), body: <String, String>{"username": username, "device_id": android_id}));
      //   final data = update_response.body.split(',');
      //   updated = data[1] == '1';
      // } catch (e) {
      //   Debug.Log(e);
      // }

      Debug.Log("Need to update : ${!updated}");

      //Update CacheDB
      if (!updated) {
        await UpdateTaskTypesFromServer();
      }
    }

    await Future.delayed(Duration(seconds: 1));

    List<Map> cats = await cacheDb.query('TaskTypes');
    Debug.Log(cats.length);
    for (Map element in cats) {
      String? id = element[TaskType.colId].toString();
      String? name = element[TaskType.colName].toString();
      String? category = element[TaskType.colCategory].toString();
      String? related_project = element[TaskType.colRelatedProject].toString();
      Category? cat = await getCatFromId(category);
      if (id == null || name == null || category == null) {
        Debug.LogError("Something is null!");
        Debug.LogError("name:{$name}, cat:{$category}, prod:{$id}");
        continue;
      }
      Project? relatedProject;
      if (related_project.isNotEmpty) {
        relatedProject = await getProjectFromId(related_project);
        Debug.Log('got a tasktype with project');
      }

      // Debug.Log("name:{$name}, cat:{$category}, prod:{$id}");
      _taskTypes.add(TaskType(id, name, category,
          cat: cat, relatedProject: relatedProject));
    }
    taskTypes = _taskTypes;
  } else {
    List<TaskType> _taskTypes = [];
    Debug.Log("NC: Updating TaskTypes as $username");
    try {
      http.Response response = (await http.post(
          Uri.parse(API_ENDPOINT + '/task_tracker/get_taskTypes.php'),
          body: <String, String>{
            "username": username,
            "device_id": await Settings.UUID()
          }));

      Debug.LogResponse("taskType retreive (try): ${response.body}");
      List<String> data = response.body.split("<td>");

      for (var value in data) {
        Map<String, dynamic> data = jsonDecode(value);
        Category? cat = await getCatFromId(data['category_id']);
        _taskTypes.add(TaskType(
            data['task_id'], data['name'], data['category_id'],
            cat: cat, relatedProject: data['related_project']));
        //Debug.Log(cat);
      }
    } catch (e) {
      Debug.LogError("Error while tasks NC $e");
    }

    taskTypes = _taskTypes;
  }
  return taskTypes;
}

Future<void> UpdateTaskTypesFromServer() async {
  // await GetCategories(true);
  Debug.Log("Updating TaskTypes as $username");
  try {
    http.Response response = (await http.post(
        Uri.parse(API_ENDPOINT + '/task_tracker/get_taskTypes.php'),
        body: <String, String>{
          "username": username,
          "device_id": await Settings.UUID()
        }));

    Debug.LogResponse(response.body);
    await fillTaskTypes(response.body);
  } catch (e) {
    Debug.LogError("Error while tasks $e");
  }
}

Future<void> fillTaskTypes(String response) async {
  List<String> data = response.split("<td>");
  await cacheDb.delete("TaskTypes");
  for (var value in data) {
    Map<String, dynamic> cat = jsonDecode(value);
    //Debug.Log(cat);
    await cacheDb.rawInsert(
        "INSERT OR REPLACE INTO TaskTypes (${TaskType.colId},${TaskType.colName},${TaskType.colCategory},${TaskType.colRelatedProject}) "
        "VALUES ('${cat['task_id']}','${cat['name']}','${cat['category_id']}', '${cat['related_project']}') ");

    Debug.LogResponse(await cacheDb.query("TaskTypes"));
  }
}

void StartActivityTimer(
    String taskType, String metadata, DateTime startTime) async {
  final prefs = await SharedPreferences.getInstance();

  prefs.setString('current_activity',
      "$taskType<td>$metadata<td>${UserOperations.dFormat.format(startTime)}");
  NotificationManager.RescheduleNotifications();

  UserOperations.startOngoing(prefs.getString('current_activity')!);
}

Future<List<String>?> getOngoingData() async {
  final prefs = await SharedPreferences.getInstance();
  if (prefs.containsKey('current_activity')) {
    List<String> data = [];
    try {
      data = prefs.getString('current_activity')!.split('<td>');
      return data;
    } catch (e) {}
  } else {}
}

void StopActivityTimer() async {
  final prefs = await SharedPreferences.getInstance();
  try {
    List<String> data = prefs.getString('current_activity')!.split("<td>");
    UserOperations.addActivity(data[0], DateTime.parse(data[2]), DateTime.now(),
        metadata: data[1]);
  } catch (e) {}
  prefs.remove('current_activity');
  UserOperations.stopOngoing();
}

void CancelOngoingActivity() async {
  final prefs = await SharedPreferences.getInstance();
  prefs.remove('current_activity');
  UserOperations.stopOngoing();
}

Future<List<Activity>> GetActivities(bool forceOffline) async {
  if (cacheEnabled) {
    List<Activity> _activities = [];
    if (offline || forceOffline) {
      //Retreive from cacheDB
      Debug.Log('offline, refreshing activities');
    } else {
      //Check if server got updated, If not go for cache
      var android_id = await Settings.UUID();

      bool updated = false;
      // try {
      //   //Validate device_id to check updates
      //   http.Response update_response = (await http.post(Uri.parse(API_ENDPOINT+'/task_tracker/check_update.php'), body: <String, String>{"username": username, "device_id": android_id}));
      //   final data = update_response.body.split(',');
      //   updated = data[2] == '1';
      // } catch (e) {
      //   Debug.Log(e);
      // }

      Debug.Log("Need to update activities : ${!updated}");

      //Update CacheDB
      if (!updated) {
        await UpdateActivitiesFromServer();
      }
    }

    List<Map> cats = await cacheDb.rawQuery(
        'SELECT * FROM Activities ORDER BY ${Activity.colStartTime} DESC');
    Debug.Log(cats.length);
    for (Map element in cats) {
      int? id = element['id'];
      String? type = element[Activity.colType].toString();
      String? startTime = element[Activity.colStartTime].toString();
      String? endTime = element[Activity.colEndTime].toString();
      String? metadata = element[Activity.colMetadata].toString();
      TaskType? taskType = await getTaskFromId(type);
      if (type == null ||
          startTime == null ||
          endTime == null ||
          taskType == null) {
        Debug.LogError(
            "Something is null!\ntype:${type == null}, startTime:${startTime == null}, eTime:${endTime == null}, taskType${taskType == null}");
        Debug.LogError(
            "TaskType:{$type}, Start Time:{$startTime}, endTime:{$endTime}, metadata:${metadata}");
        continue;
      }
      //Debug.Log("TaskType:{$type}, Start Time:{$startTime}, endTime:{$endTime}, metadata:${metadata}");
      DateTime sTime = DateTime.parse(startTime);
      DateTime eTime = DateTime.parse(endTime);

      if (eTime.day != sTime.day) {
        DateTime midnight =
            DateTime(eTime.year, eTime.month, eTime.day, 0, 0, 0);
        int firstHalf = eTime.difference(midnight).inMinutes;
        int secondHalf = midnight.difference(sTime).inMinutes;
        //  Debug.Log("${taskType.name} first half : $firstHalf -> second half: $secondHalf");
        if (firstHalf > 1) {
          _activities.add(Activity(taskType, midnight, eTime,
              metadata: metadata, tStartTime: sTime));
        }
        if (secondHalf > 1) {
          _activities.add(Activity(taskType, sTime, midnight,
              metadata: metadata, tEndTime: eTime));
        }
      } else {
        _activities.add(Activity(
            taskType, DateTime.parse(startTime), DateTime.parse(endTime),
            metadata: metadata));
      }
    }
    activities = _activities;
  } else {
    Debug.Log("NC :Updating Activities as $username");
    try {
      http.Response response = (await http.post(
          Uri.parse(API_ENDPOINT + '/task_tracker/get_activities.php'),
          body: <String, String>{
            "username": username,
            "device_id": await Settings.UUID()
          }));

      Debug.LogResponse("Activity response: ${response.body}");
      List<Activity> _activities = [];
      if (response.body.contains("{")) {
        List<String> data = response.body.split("<td>");

        for (var value in data) {
          Map<String, dynamic> cat = jsonDecode(value);
          int? id = cat['id'];
          String? type = cat['task_id'].toString();
          String? startTime = cat['sTime'].toString();
          String? endTime = cat['eTime'].toString();
          String? metadata = cat['metadata'];
          TaskType? taskType = await getTaskFromId(type);
          if (taskType == null) {
            Debug.LogError('null found');
            continue;
          }
          //Debug.Log("TaskType:{$type}, Start Time:{$startTime}, endTime:{$endTime}, metadata:${metadata}");
          DateTime sTime = DateTime.parse(startTime);
          DateTime eTime = DateTime.parse(endTime);

          if (eTime.day != sTime.day) {
            DateTime midnight =
                DateTime(eTime.year, eTime.month, eTime.day, 0, 0, 0);
            int firstHalf = eTime.difference(midnight).inMinutes;
            int secondHalf = midnight.difference(sTime).inMinutes;
            //  Debug.Log("${taskType.name} first half : $firstHalf -> second half: $secondHalf");
            if (firstHalf > 1) {
              _activities.add(Activity(taskType, midnight, eTime,
                  metadata: metadata, tStartTime: sTime));
            }
            if (secondHalf > 1) {
              _activities.add(Activity(taskType, sTime, midnight,
                  metadata: metadata, tEndTime: eTime));
            }
          } else {
            _activities.add(Activity(
                taskType, DateTime.parse(startTime), DateTime.parse(endTime),
                metadata: metadata));
          }
        }

        activities = _activities.reversed.toList();
      } else {
        Debug.LogError("No activities for now");
      }
    } catch (e) {
      Debug.LogError("Error while acts $e");
    }
  }
  return activities;
}

Future<void> UpdateActivitiesFromServer() async {
  Debug.Log("Updating Activities as $username");

  try {
    http.Response response = (await http.post(
        Uri.parse(API_ENDPOINT + '/task_tracker/get_activities.php'),
        body: <String, String>{
          "username": username,
          "device_id": await Settings.UUID()
        }));

    await fillActivityTable(response.body);

    // Debug.Log("Activity response: ${response.body}");

  } catch (e) {
    Debug.Log("Error while acts $e");
  }
}

Future<void> fillActivityTable(String response) async {
  if (response.contains("{")) {
    await cacheDb.rawDelete("DELETE FROM Activities");
    Debug.Log('Truncate Activity Table before');
    List<String> data = response.split("<td>");

    for (var value in data) {
      Map<String, dynamic> cat = jsonDecode(value);
      //Debug.Log(cat);
      await cacheDb.rawInsert(
          "INSERT OR REPLACE INTO Activities (${Activity.colType}, ${Activity.colStartTime}, ${Activity.colEndTime}, ${Activity.colMetadata}) "
          "VALUES ('${cat['task_id']}', '${cat['sTime']}','${cat['eTime']}', '${cat['metadata'].toString().replaceAll("'", "''")}') ");
    }
  } else {
    Debug.Log("No activities for now");
  }
}

Future<List<Project>> GetProjects(bool forceOffline) async {
  if (cacheEnabled) {
    List<Project> _projects = [];
    if (offline || forceOffline) {
      //Retreive from cacheDB
      Debug.Log('offline, refreshing projects');
    } else {
      //Check if server got updated, If not go for cache
      var android_id = await Settings.UUID();

      bool updated = false;

      Debug.Log("Need to update activities : ${!updated}");

      //Update CacheDB
      if (!updated) {
        await UpdateProjectsFromServer();
      }
    }

    List<Map> cats = await cacheDb.rawQuery('SELECT * FROM Projects');
    Debug.Log('projects : ${cats.length}');
    for (Map element in cats) {
      String? name = element[Project.colName];
      String? category = element[Project.colCat];
      String? stepsJson = element[Project.colSteps];
      String? deadline = element[Project.colDeadline];
      int? eta = element[Project.colEta];

      if (name == null ||
          category == null ||
          stepsJson == null ||
          deadline == null ||
          eta == null) {
        Debug.LogError(
            "Something is null!\nname:${name == null}, cat:${category == null}, steps:${stepsJson == null}, deadline${deadline == null}");
        Debug.LogError(
            "TaskType:{$name}, Start Time:{$category}, endTime:{$stepsJson}, metadata:${deadline}");
        continue;
      }
      Category? cat = await getCatFromId(category);
      Debug.Log('searching for $category');
      if (cat == null) {
        Debug.LogError('couldnt find cat');
        continue;
      }
      Debug.LogResponse('steps : $stepsJson');
      List<dynamic> _steps = jsonDecode(stepsJson);
      List<ProjectStep> steps = [];
      int m_eta = 0;
      _steps.forEach((element) {
        ProjectStep step = ProjectStep.fromJson(element);
        m_eta += step.eta;
        steps.add(step);
        Debug.LogResponse(element);
      });
      eta = (m_eta > 0) ? m_eta : eta;
      //  Debug.Log(steps);

      _projects.add(Project(name.replaceAll(username, ""), category, steps, eta,
          DateTime.parse(deadline),
          cat: cat));
    }
    projects = _projects;
  } else {
    Debug.Log("NC :Updating Projects as $username");
    try {
      http.Response response = (await http.post(
          Uri.parse(API_ENDPOINT + '/task_tracker/get_projects.php'),
          body: <String, String>{
            "username": username,
            "device_id": await Settings.UUID()
          }));

      //  Debug.Log("Activity response: ${response.body}");
      List<Project> _projects = [];
      if (response.body.contains("{")) {
        List<String> data = response.body.split("<td>");

        for (var value in data) {
          Map<String, dynamic> cat = jsonDecode(value);
          int? id = cat['id'];
          String? type = cat['task_id'].toString();
          String? startTime = cat['sTime'].toString();
          String? endTime = cat['eTime'].toString();
          String? metadata = cat['metadata'];
          TaskType? taskType = await getTaskFromId(type);
          if (taskType == null) {
            Debug.LogError('null task found');
            continue;
          }
        }

        projects = _projects;
      } else {
        Debug.Log("No activities for now");
      }
    } catch (e) {
      Debug.LogError("Error : $e @ updating activities");
      Debug.LogError("Error while acts $e");
    }
  }
  return projects;
}

Future<void> UpdateProjectsFromServer() async {
  Debug.Log("Updating Projects as $username");

  try {
    http.Response response = (await http.post(
        Uri.parse(API_ENDPOINT + '/task_tracker/get_projects.php'),
        body: <String, String>{
          "username": username,
          "device_id": await Settings.UUID()
        }));

    await fillProjectsTable(response.body);
  } catch (e) {
    Debug.LogError("Error while acts $e");
  }
}

Future<void> fillProjectsTable(String response) async {
  await cacheDb.rawDelete("DELETE FROM Projects");
  Debug.Log('Truncate Projects Table before');

  Debug.LogResponse("Projects response: ${response}");
  if (response.contains("{")) {
    List<String> data = response.split("<td>");

    for (var value in data) {
      Map<String, dynamic> cat = jsonDecode(value);
      Debug.LogResponse(cat, src: 'project data');
      await cacheDb.rawInsert(
          "INSERT OR REPLACE INTO Projects (${Project.colName}, ${Project.colCat}, ${Project.colSteps}, ${Project.colDeadline}, ${Project.colEta}) "
          "VALUES ('${cat['name']}', '${cat['category']}', '${cat['steps']}', '${cat['deadline']}', ${cat['eta']})");
    }
  } else {
    Debug.Log("No projects for now");
  }
}

Future<List<Journal>> GetJournals(bool forceOffline) async {
  if (cacheEnabled) {
    List<Journal> _journals = [];
    if (offline || forceOffline) {
      //Retreive from cacheDB

    } else {
      //Check if server got updated, If not go for cache

      //Validate device_id to check updates

      bool catsUpdated = false;
      // try {
      //   http.Response update_response = (await http.post(Uri.parse(API_ENDPOINT+'/task_tracker/check_update.php'), body: <String, String>{"username": username, "device_id": android_id}));
      //   final data = update_response.body.split(',');
      //   catsUpdated = data[0] == '1';
      // } catch (e) {
      //   Debug.Log(e);
      // }

      //Update CacheDB
      if (!catsUpdated) {
        await UpdateJournalsFromServer();
      }
    }

    List<Map> cats = await cacheDb.query('Journal');
    Debug.Log(cats.length);
    for (Map element in cats) {
      String? id = element['id'].toString();
      String? title = element[Journal.colTitle].toString();
      String? text = element[Journal.colDescription].toString();
      if (id == null || title == null || text == null) {
        Debug.LogError("Something is null!");
        Debug.LogError("id:{$id}, title:{$title}, text:${text}");
        continue;
      }
      DateTime day = DateTime.parse(id.replaceAll(username, ''));
      //  Debug.Log("name:{$catName}, color:{$catColor}, prod:{$catProductive}");
      _journals.add(Journal(id, day, title: title, description: text));
    }
    journal = _journals;
  } else {
    Debug.Log("NC: Updating Categories as $username");
    try {
      http.Response response = (await http.post(
          Uri.parse(API_ENDPOINT + '/task_tracker/get_journals.php'),
          body: <String, String>{
            "username": username,
            "device_id": await Settings.UUID()
          }));

      Debug.LogResponse(response.body);
      List<String> data = response.body.split("<td>");
      List<Journal> _categories = [];
      for (var value in data) {
        Map<String, dynamic> cat = jsonDecode(value);
        //Debug.Log(catData);
        _categories.add(Journal(cat['id'],
            DateTime.parse(cat['id'].toString().replaceAll(username, '')),
            title: cat['title'], description: cat['text']));
      }
      journal = _categories;
    } catch (e) {
      Debug.LogError("Error while cats NC: $e");
    }
  }
  journal.sort((a, b) => b.day.compareTo(a.day));
  return journal;
}

Future<void> UpdateJournalsFromServer() async {
  Debug.Log("Updating Journal as $username");
  try {
    http.Response response = (await http.post(
        Uri.parse(API_ENDPOINT + '/task_tracker/get_journals.php'),
        body: <String, String>{
          "username": username,
          "device_id": await Settings.UUID()
        }));

    await fillJournalsTable(response.body);
  } catch (e) {
    Debug.LogError("Error while cats $e");
  }
}

Future<void> fillJournalsTable(String response) async {
  Debug.LogResponse(response, src: 'Journal');
  if (response.isEmpty) {
    Debug.Log('Empty Journal');
  } else {
    List<String> data = response.split("<td>");
    await cacheDb.delete("Journal");
    for (var value in data) {
      Map<String, dynamic> cat = jsonDecode(value);
      //Debug.Log(catData);
      await cacheDb.rawInsert(
          "INSERT OR REPLACE INTO Journal (id, ${Journal.colTitle},${Journal.colDescription}) "
          "VALUES ('${cat['id']}','${cat['title'].toString().replaceAll("'", "''")}','${cat['description'].toString().replaceAll("'", "''")}') ");
    }
  }
}

Future<List<Todo>> GetTodos(bool forceOffline) async {
  if (cacheEnabled) {
    List<Todo> _todos = [];
    if (offline || forceOffline) {
      //Retreive from cacheDB

    } else {
      //Check if server got updated, If not go for cache

      //Validate device_id to check updates

      bool catsUpdated = false;
      // try {
      //   http.Response update_response = (await http.post(Uri.parse(API_ENDPOINT+'/task_tracker/check_update.php'), body: <String, String>{"username": username, "device_id": android_id}));
      //   final data = update_response.body.split(',');
      //   catsUpdated = data[0] == '1';
      // } catch (e) {
      //   Debug.Log(e);
      // }

      //Update CacheDB
      if (!catsUpdated) {
        await UpdateTodosFromServer();
      }
    }

    List<Map> cats = await cacheDb.query('Todos');
    Debug.Log(cats.length);
    for (Map element in cats) {
      String? id = element['id'].toString();
      String? task_id = element[Todo.colCat];
      String? metadata = element[Todo.colMetadata];
      String? due_date = element[Todo.colDueDate];
      String? notification_time = element[Todo.colNotificationTime];

      if (id == null ||
          task_id == null ||
          metadata == null ||
          due_date == null) {
        Debug.LogError("Something is null!");
        Debug.LogError(
            "id:{$id}, task:{$task_id}, metadata:${metadata}, due_date: ${due_date}");
        continue;
      }
      TaskType? taskType = await getTaskFromId(task_id);
      if (taskType == null) {
        Debug.LogError('got null taask for this todo!');
        Debug.LogResponse(
            "id:{$id}, task:{$task_id}, metadata:${metadata}, due_date: ${due_date}");
      }
      DateTime dueDate = DateTime.parse(due_date);
      DateTime? notificationTime = (notification_time == null)
          ? null
          : ((notification_time.isEmpty || notification_time == 'null')
              ? null
              : DateTime.parse(notification_time));
      //  Debug.Log("name:{$catName}, color:{$catColor}, prod:{$catProductive}");
      _todos.add(Todo(id, task_id, metadata, dueDate,
          notificationTime: notificationTime, task: taskType));
    }
    todos = _todos;
  } else {
    Debug.Log("NC: Updating todos as $username");
    try {
      http.Response response = (await http.post(
          Uri.parse(API_ENDPOINT + '/task_tracker/get_todos.php'),
          body: <String, String>{
            "username": username,
            "device_id": await Settings.UUID()
          }));

      Debug.LogResponse(response.body);
      List<String> data = response.body.split("<td>");
      List<Journal> _categories = [];
      for (var value in data) {
        Map<String, dynamic> cat = jsonDecode(value);
        //Debug.Log(catData);
        _categories.add(Journal(cat['id'],
            DateTime.parse(cat['id'].toString().replaceAll(username, '')),
            title: cat['title'], description: cat['text']));
      }
      journal = _categories;
    } catch (e) {
      Debug.LogError("Error while cats NC: $e");
    }
  }
  // journal.sort((a, b) => b.day.compareTo(a.day));
  return todos;
}

Future<void> UpdateTodosFromServer() async {
  Debug.Log("Updating Todos as $username");
  try {
    http.Response response = (await http.post(
        Uri.parse(API_ENDPOINT + '/task_tracker/get_todos.php'),
        body: <String, String>{
          "username": username,
          "device_id": await Settings.UUID()
        }));

    Debug.LogResponse(response.body);

    await fillTodosTable(response.body);
  } catch (e) {
    Debug.LogError("Error while cats $e");
  }
}

Future<void> fillTodosTable(String response) async {
  if (response.contains("{")) {
    List<String> data = response.split("<td>");
    await cacheDb.delete("Todos");
    for (var value in data) {
      Map<String, dynamic> cat = jsonDecode(value);
      //Debug.Log(catData);
      await cacheDb.rawInsert(
          "INSERT OR REPLACE INTO Todos (id, ${Todo.colCat},${Todo.colMetadata},${Todo.colDueDate},${Todo.colNotificationTime}) "
          "VALUES ('${cat['id'].toString().replaceAll("'", "''")}', '${cat['task_id']}', '${cat['metadata'].toString().replaceAll("'", "''")}', '${cat['due_date']}', '${cat['notification_time']}') ");
    }
  } else {
    Debug.Log('Empty Todos');
  }
}

Future<TaskType?> getTaskFromId(String taskId) async {
  // await GetTaskTypes(false);
  TaskType? cat = null;
  for (var element in taskTypes) {
    if (element.id == taskId) {
      cat = element;
      cat?.cat = await getCatFromId((cat?.category ?? ''));
    }
  }
  if (cat == null) {
    Debug.LogError(
        'Got null tasktype for ${taskId} after searching on ${taskTypes.length}');
  }

  return cat;
}

Future<Category?> getCatFromId(String catId) async {
  // await GetTaskTypes(false);
  Category? cat = null;
  for (var element in categories) {
    if (element.category_id == catId) {
      cat = element;
    }
  }

  return cat;
}

Future<Project?> getProjectFromId(String projectId) async {
  // await GetTaskTypes(false);
  Project? project = null;
  for (var element in projects) {
    if (element.getName() == projectId.replaceAll(username, "")) {
      project = element;
    }
  }
  if (project == null) {
    Debug.LogError(
        'Got null project for ${projectId} after searching on ${projects.length}');
  }

  return project;
}

bool journalExists(DateTime date) {
  int journalId = -1;
  for (int i = 0; i < journal.length; i++) {
    //   Debug.Log('${journal[i].day } : $date');
    if (DateFormat('yyyy-MM-dd').format(journal[i].day) ==
        DateFormat('yyyy-MM-dd').format(date)) {
      journalId = i;
      break;
    }
  }

  return (journalId > 0);
}

//Helpers
class Helpers {
  Future<String?> _getId() async {
    var deviceInfo = DeviceInfoPlugin();
    if (Platform.isIOS) {
      // import 'dart:io'
      var iosDeviceInfo = await deviceInfo.iosInfo;
      return iosDeviceInfo.identifierForVendor; // unique ID on iOS
    } else {
      var androidDeviceInfo = await deviceInfo.androidInfo;
      return androidDeviceInfo.androidId; // unique ID on Android
    }
  }
}

bool ParseBool(obj) {
  return obj.toString().toLowerCase() == "true" || obj.toString() == "1";
}

class UserOperations {
  static DateFormat dFormat = DateFormat("yyyy-MM-dd HH:mm:ss");

  static Future<void> addCategory(String name, String color, bool productive,
      {bool bulk = false}) async {
    Map<String, String> queryBody = <String, String>{
      'username': username,
      'device_id': await Settings.UUID(),
      'name': name,
      'color': color,
      'productive': productive ? '1' : '0'
    };
    if (cacheEnabled) {
      //Add Query
      Map<String, Object> query = {
        Queries.colLink: 'add_category',
        Queries.colData: jsonEncode(queryBody)
      };

      Debug.LogResponse(
          "adding new query ${query[Queries.colLink]} : ${jsonEncode(queryBody)}");

      await cacheDb.insert('Queries', query);

      //update Cache
      Map<String, Object> data = {
        Category.colCatId: username + name,
        Category.colName: name,
        Category.colColor: color,
        Category.colProductive: productive
      };
      await cacheDb.insert('Categories', data);
      await refreshUserData(forceOffline: true);
    } else {
      try {
        http.Response queryResponse = (await http.post(
            Uri.parse(API_ENDPOINT + '/task_tracker/add_category.php'),
            body: queryBody));
        Debug.LogResponse("Query executed : Results{${queryResponse.body}");
        if (queryResponse.body.toLowerCase().contains("success")) {
          //Success
        }
      } catch (e) {
        Debug.LogError('NC: Error editing acti $e}');
      }
      //executeQueries();
    }
    if (!bulk) {
      //Add to server and refresh Cache
      await executeQueries();
    }
  }

  static Future<void> addTaskType(String name, String category,
      {bool bulk = false, String? relatedProject = null}) async {
    Map<String, String> queryBody = <String, String>{
      'id': username + name,
      'username': username,
      'device_id': await Settings.UUID(),
      'name': name,
      'category': username + category,
      'related_project':
          (relatedProject == null) ? '' : (username + relatedProject)
    };

    if (cacheEnabled) {
      //Add Query
      Map<String, Object> query = {
        Queries.colLink: 'add_taskType',
        Queries.colData: jsonEncode(queryBody)
      };

      Debug.LogResponse(
          "adding new query ${query[Queries.colLink]} : ${jsonEncode(queryBody)}");

      await cacheDb.insert('Queries', query);

      //update Cache
      Map<String, Object> data = {
        TaskType.colId: username + name,
        Category.colName: name,
        Category.colCatId: username + category,
      };
      if (relatedProject != null || relatedProject == 'None') {
        data.putIfAbsent(
            TaskType.colRelatedProject, () => relatedProject.toString());
      }
      await cacheDb.insert('TaskTypes', data);
      await refreshUserData(forceOffline: true);
    } else {
      try {
        http.Response queryResponse = (await http.post(
            Uri.parse(API_ENDPOINT + '/task_tracker/add_taskType.php'),
            body: queryBody));
        Debug.LogResponse("Query executed : Results{${queryResponse.body}");
        if (queryResponse.body.toLowerCase().contains("success")) {
          //Success
        }
      } catch (e) {
        Debug.LogError('NC: Error editing acti $e}');
      }
    }
    if (!bulk) {
      //Add to server and refresh Cache
      await executeQueries();
    }
  }

  static Future<void> editTaskType(String oldName, String name, String category,
      {bool bulk = false, String? relatedProject = null}) async {
    Map<String, String> queryBody = <String, String>{
      'id': username + oldName,
      'username': username,
      'name': name,
      'category': username + category,
      'related_project':
          (relatedProject == null) ? '' : (username + relatedProject)
    };

    if (cacheEnabled) {
      //Add Query
      Map<String, Object> query = {
        Queries.colLink: 'edit_taskType',
        Queries.colData: jsonEncode(queryBody)
      };

      Debug.LogResponse(
          "adding new query ${query[Queries.colLink]} : ${jsonEncode(queryBody)}");

      await cacheDb.insert('Queries', query);

      //update Cache
      await cacheDb.rawUpdate(
          "UPDATE TaskTypes SET ${TaskType.colId}='${username + name}', ${TaskType.colName}='$name', ${TaskType.colCategory}='${username + category}', ${TaskType.colRelatedProject}='${(relatedProject == 'None') ? '' : relatedProject}' WHERE id='${username + oldName}'");
      await refreshUserData(forceOffline: true);
    } else {
      try {
        http.Response queryResponse = (await http.post(
            Uri.parse(API_ENDPOINT + '/task_tracker/add_taskType.php'),
            body: queryBody));
        Debug.LogResponse("Query executed : Results{${queryResponse.body}");
        if (queryResponse.body.toLowerCase().contains("success")) {
          //Success
        }
      } catch (e) {
        Debug.LogError('NC: Error editing task $e}');
      }
    }
    if (!bulk) {
      //Add to server and refresh Cache
      await executeQueries();
    }
  }

  static Future<void> addActivity(String type, DateTime sTime, DateTime eTime,
      {String metadata = 'null',
      bool bulk = false,
      Function(int)? onOverlap}) async {
    Map<String, String> queryBody = <String, String>{
      'username': username,
      'device_id': await Settings.UUID(),
      'type': username + type,
      'sTime': dFormat.format(sTime),
      'eTime': dFormat.format(eTime),
      'metadata': metadata
    };
    Map<String, Object> query = {
      Queries.colLink: 'add_activity',
      Queries.colData: jsonEncode(queryBody)
    };
    if (cacheEnabled) {
      //Check for timeoverlapse
      activities = await GetActivities(true);
      int? overlapCount = Sqflite.firstIntValue(await cacheDb.rawQuery(
          "SELECT COUNT(*) FROM Activities WHERE (((${Activity.colStartTime} < datetime('$sTime')) AND ((${Activity.colEndTime} > datetime('$eTime')) OR (${Activity.colEndTime} < datetime('$eTime') AND ${Activity.colEndTime} > datetime('$sTime')))) OR (${Activity.colStartTime} > datetime('$sTime') AND ${Activity.colStartTime} < datetime('$eTime')) OR (${Activity.colStartTime}=datetime('$sTime') AND ${Activity.colEndTime}=datetime('$eTime')))"));

      Debug.Log("ActivityOverlaps: $overlapCount");
      if (overlapCount! > 0) {
        onOverlap!(overlapCount);
        return;
      }

      if (metadata.length > 0) {}
      //Add Query

      Debug.LogResponse(
          "adding new query ${query[Queries.colLink]} : ${jsonEncode(queryBody)}");

      await cacheDb.insert('Queries', query);

      //update Cache
      Map<String, Object> data = {
        Activity.colType: username + type,
        Activity.colStartTime: dFormat.format(sTime),
        Activity.colEndTime: dFormat.format(eTime),
        Activity.colMetadata: metadata
      };
      await cacheDb.insert('Activities', data);
      await refreshUserData(forceOffline: true);
    } else {
      try {
        http.Response queryResponse = (await http.post(
            Uri.parse(API_ENDPOINT + '/task_tracker/add_activity.php'),
            body: queryBody));
        Debug.LogResponse("Query executed : Results{${queryResponse.body}");
        if (queryResponse.body.toLowerCase().contains("success")) {
          //Success
        }
      } catch (e) {
        Debug.LogError('NC: Error adding player $e}');
      }
    }
    if (!bulk) {
      //Add to server and refresh Cache
      await executeQueries();
    }
  }

  static Future<void> editActivity(DateTime init_sTime, DateTime init_eTime,
      String type, DateTime sTime, DateTime eTime,
      {String metadata = 'null',
      bool bulk = false,
      Function(int)? onOverlap}) async {
    Map<String, String> queryBody = <String, String>{
      'username': username,
      'device_id': await Settings.UUID(),
      'type': username + type,
      'init_sTime': dFormat.format(init_sTime),
      'init_eTime': dFormat.format(init_eTime),
      'sTime': dFormat.format(sTime),
      'eTime': dFormat.format(eTime),
      'metadata': metadata
    };
    Map<String, Object> query = {
      Queries.colLink: 'edit_activity',
      Queries.colData: jsonEncode(queryBody)
    };
    if (cacheEnabled) {
      //Check for timeoverlapse
      activities = await GetActivities(true);
      int? overlapCount = Sqflite.firstIntValue(await cacheDb.rawQuery(
          "SELECT COUNT(*) FROM Activities WHERE (((${Activity.colStartTime} < datetime('$sTime')) AND ((${Activity.colEndTime} > datetime('$eTime')) OR (${Activity.colEndTime} < datetime('$eTime') AND ${Activity.colEndTime} > datetime('$sTime')))) OR (${Activity.colStartTime} > datetime('$sTime') AND ${Activity.colStartTime} < datetime('$eTime')) OR (${Activity.colStartTime}=datetime('$sTime') AND ${Activity.colEndTime}=datetime('$eTime'))) AND ${Activity.colStartTime}!=datetime('${init_sTime}') AND ${Activity.colEndTime} != datetime('${init_eTime}')"));

      Debug.Log("ActivityOverlaps: $overlapCount");
      if (overlapCount! > 0) {
        onOverlap!(overlapCount);
        return;
      }

      if (metadata.length > 0) {}
      //Add Query

      Debug.LogResponse(
          "adding new query ${query[Queries.colLink]} : ${jsonEncode(queryBody)}");

      await cacheDb.insert('Queries', query);

      //TODO
      //update Cache
      // Map<String, Object> data = {Activity.colType: username + type, Activity.colStartTime: dFormat.format(sTime), Activity.colEndTime: dFormat.format(eTime), Activity.colMetadata: metadata};
      // String updateActQuery = "UPDATE Activities SET ${Activity.colType}=";
      // await cacheDb.insert('Activities', data);
      await cacheDb.rawUpdate(
          "UPDATE Activities SET ${Activity.colType}='${username + type}', ${Activity.colStartTime}=datetime('${dFormat.format(sTime)}'), ${Activity.colEndTime}=datetime('${dFormat.format(eTime)}'), ${Activity.colMetadata}='$metadata' WHERE ${Activity.colStartTime}=datetime('${dFormat.format(init_sTime)}')");
      await refreshUserData(forceOffline: true);
    } else {
      // queries.add(Queries('edit_activity', jsonEncode(queryBody)));
      try {
        http.Response queryResponse = (await http.post(
            Uri.parse(API_ENDPOINT + '/task_tracker/edit_activity.php'),
            body: queryBody));
        Debug.LogResponse("Query executed : Results{${queryResponse.body}");
        if (queryResponse.body.toLowerCase().contains("success")) {
          //Success
        }
      } catch (e) {
        Debug.LogError('NC: Error editing acti $e}');
      }
    }
    if (!bulk) {
      //Add to server and refresh Cache
      await executeQueries();
    }
  }

  static Future<void> startOngoing(String activityData) async {
    Map<String, String> queryBody = <String, String>{
      'username': username,
      'current_activity': activityData,
    };

    if (cacheEnabled) {
      //Add Query
      Map<String, Object> query = {
        Queries.colLink: 'start_ongoing',
        Queries.colData: jsonEncode(queryBody)
      };

      Debug.LogResponse(
          "adding new query ${query[Queries.colLink]} : ${jsonEncode(queryBody)}");

      await cacheDb.insert('Queries', query);
    } else {
      try {
        http.Response queryResponse = (await http.post(
            Uri.parse(API_ENDPOINT + '/task_tracker/start_ongoing.php'),
            body: queryBody));
        Debug.LogResponse("Query executed : Results{${queryResponse.body}");
        if (queryResponse.body.toLowerCase().contains("success")) {
          //Success
        }
      } catch (e) {
        Debug.LogError('NC: Error adding ongoing $e}');
      }
    }

    await executeQueries();
  }

  static Future<void> stopOngoing() async {
    Map<String, String> queryBody = <String, String>{
      'username': username,
    };

    if (cacheEnabled) {
      //Add Query
      Map<String, Object> query = {
        Queries.colLink: 'stop_ongoing',
        Queries.colData: jsonEncode(queryBody)
      };

      Debug.LogResponse(
          "adding new query ${query[Queries.colLink]} : ${jsonEncode(queryBody)}");

      await cacheDb.insert('Queries', query);
    } else {
      try {
        http.Response queryResponse = (await http.post(
            Uri.parse(API_ENDPOINT + '/task_tracker/stop_ongoing.php'),
            body: queryBody));
        Debug.LogResponse("Query executed : Results{${queryResponse.body}");
        if (queryResponse.body.toLowerCase().contains("success")) {
          //Success
        }
      } catch (e) {
        Debug.LogError('NC: Error adding ongoing $e}');
      }
    }

    await executeQueries();
  }

  static Future<void> addProject(String name, String category,
      List<ProjectStep> steps, int eta, DateTime deadline) async {
    Map<String, String> queryBody = <String, String>{
      'name': username + name,
      'username': username,
      'device_id': await Settings.UUID(),
      'category_id': username + category,
      'steps': jsonEncode(steps),
      'eta': eta.toString(),
      'deadline': DateFormat("yyyy-MM-dd").format(deadline)
    };

    if (cacheEnabled) {
      //Add Query
      Map<String, Object> query = {
        Queries.colLink: 'add_project',
        Queries.colData: jsonEncode(queryBody)
      };

      Debug.LogResponse(
          "adding new query ${query[Queries.colLink]} : ${jsonEncode(queryBody)}");

      await cacheDb.insert('Queries', query);

      //update Cache
      Map<String, Object> data = {
        Project.colName: username + name,
        Project.colCat: category,
        Project.colSteps: jsonEncode(steps),
        Project.colEta: eta,
        Project.colDeadline: deadline.toString()
      };
      await cacheDb.insert('Projects', data);
      await refreshUserData(forceOffline: true);
    } else {
      try {
        http.Response queryResponse = (await http.post(
            Uri.parse(API_ENDPOINT + '/task_tracker/add_project.php'),
            body: queryBody));
        Debug.LogResponse("Query executed : Results{${queryResponse.body}");
        if (queryResponse.body.toLowerCase().contains("success")) {
          //Success
        }
      } catch (e) {
        Debug.LogError('NC: Error adding prjct $e}');
      }
    }
    UserOperations.addTaskType(name, category, relatedProject: name);
    await executeQueries();
  }

  static Future<void> editProject(String oldName, String name, String category,
      List<ProjectStep> steps, int eta, DateTime deadline) async {
    Map<String, String> queryBody = <String, String>{
      'oldName': username + oldName,
      'name': username + name,
      'username': username,
      'category_id': username + category,
      'steps': jsonEncode(steps),
      'eta': eta.toString(),
      'deadline': DateFormat("yyyy-MM-dd").format(deadline)
    };

    if (cacheEnabled) {
      //Add Query
      Map<String, Object> query = {
        Queries.colLink: 'edit_project',
        Queries.colData: jsonEncode(queryBody)
      };

      Debug.LogResponse(
          "adding new query ${query[Queries.colLink]} : ${jsonEncode(queryBody)}");

      await cacheDb.insert('Queries', query);

      //update Cache
      Map<String, Object> data = {
        Project.colName: username + name,
        Project.colCat: category,
        Project.colSteps: jsonEncode(steps),
        Project.colEta: eta,
        Project.colDeadline: deadline.toString()
      };
      await cacheDb.rawUpdate(
          "UPDATE Projects SET ${Project.colName}='${username + name}', ${Project.colCat}='${username + category}', ${Project.colSteps}='${jsonEncode(steps)}', ${Project.colEta}='${eta}', ${Project.colDeadline}='${deadline.toString()}' WHERE ${Project.colName}='${username + oldName}'");
      await cacheDb.rawUpdate(
          "UPDATE TaskTypes SET ${TaskType.colRelatedProject}='${username + name}' WHERE ${TaskType.colRelatedProject}='${username + oldName}'");
      await refreshUserData(forceOffline: true);
    } else {
      try {
        http.Response queryResponse = (await http.post(
            Uri.parse(API_ENDPOINT + '/task_tracker/edit_project.php'),
            body: queryBody));
        Debug.LogResponse("Query executed : Results{${queryResponse.body}");
        if (queryResponse.body.toLowerCase().contains("success")) {
          //Success
        }
      } catch (e) {
        Debug.LogError('NC: Error adding prjct $e}');
      }
    }
    await executeQueries();
  }

  static Future<void> CompleteProjectStep(
      Project project, ProjectStep step, DateTime finishedDate) async {
    project.steps.forEach((element) {
      if (element.stepName == step.stepName) {
        element.finishedDate = finishedDate;
      }
    });

    Map<String, String> queryBody = <String, String>{
      'name': username + project.name,
      'username': username,
      'steps': jsonEncode(project.steps),
    };

    if (cacheEnabled) {
      //Add Query
      Map<String, Object> query = {
        Queries.colLink: 'update_projectSteps',
        Queries.colData: jsonEncode(queryBody)
      };

      Debug.LogResponse(
          "adding new query ${query[Queries.colLink]} : ${jsonEncode(queryBody)}");

      await cacheDb.insert('Queries', query);
      await cacheDb.rawUpdate(
          "UPDATE Projects SET steps='${jsonEncode(project.steps)}' WHERE ${Project.colName}='${project.name}'");
      //update Cache
      // Map<String, Object> data = {Project.colName: username+name, Project.colCat: category, Project.colSteps: jsonEncode(steps),Project.colEta: eta, Project.colDeadline: deadline.toString()};
      // await cacheDb.insert('Projects', data);
      await refreshUserData(forceOffline: true);
    } else {
      try {
        http.Response queryResponse = (await http.post(
            Uri.parse(API_ENDPOINT + '/task_tracker/update_projectSteps.php'),
            body: queryBody));
        Debug.LogResponse("Query executed : Results{${queryResponse.body}");
        if (queryResponse.body.toLowerCase().contains("success")) {
          //Success
        }
      } catch (e) {
        Debug.LogError('NC: Error completing prjctStep $e}');
      }
    }

    await executeQueries();
  }

  static Future<void> UndoProjectStep(Project project, ProjectStep step) async {
    project.steps.forEach((element) {
      if (element.stepName == step.stepName) {
        element.finishedDate = null;
      }
    });

    Map<String, String> queryBody = <String, String>{
      'name': username + project.name,
      'username': username,
      'steps': jsonEncode(project.steps),
    };

    if (cacheEnabled) {
      //Add Query
      Map<String, Object> query = {
        Queries.colLink: 'update_projectSteps',
        Queries.colData: jsonEncode(queryBody)
      };

      Debug.LogResponse(
          "adding new query ${query[Queries.colLink]} : ${jsonEncode(queryBody)}");

      await cacheDb.insert('Queries', query);
      await cacheDb.rawUpdate(
          "UPDATE Projects SET steps='${jsonEncode(project.steps)}' WHERE ${Project.colName}='${project.name}'");
      //update Cache
      // Map<String, Object> data = {Project.colName: username+name, Project.colCat: category, Project.colSteps: jsonEncode(steps),Project.colEta: eta, Project.colDeadline: deadline.toString()};
      // await cacheDb.insert('Projects', data);
      await refreshUserData(forceOffline: true);
    } else {
      try {
        http.Response queryResponse = (await http.post(
            Uri.parse(API_ENDPOINT + '/task_tracker/update_projectSteps.php'),
            body: queryBody));
        Debug.LogResponse("Query executed : Results{${queryResponse.body}");
        if (queryResponse.body.toLowerCase().contains("success")) {
          //Success
        }
      } catch (e) {
        Debug.LogError('NC: Error completing prjctStep $e}');
      }
    }

    await executeQueries();
  }

  static Future<void> addJournal(
      DateTime day, String title, String text) async {
    bool exist = false;
    for (var element in journal) {
      if (element.day == day) {
        //Wat!
        exist = true;
        break;
      }
    }
    if (exist) {
      return;
    }
    String id = username + DateFormat('yyyy-MM-dd').format(day);
    Map<String, String> queryBody = <String, String>{
      'username': username,
      'id': id,
      'title': title,
      'description': text
    };
    if (cacheEnabled) {
      //Add Query
      Map<String, Object> query = {
        Queries.colLink: 'add_journal',
        Queries.colData: jsonEncode(queryBody)
      };

      Debug.LogResponse(
          "adding new query ${query[Queries.colLink]} : ${jsonEncode(queryBody)}");

      await cacheDb.insert('Queries', query);

      //update Cache
      Map<String, Object> data = {
        'id': id,
        Journal.colTitle: title,
        Journal.colDescription: text
      };
      await cacheDb.insert('Journal', data);
      await refreshUserData(forceOffline: true);
    } else {
      try {
        http.Response queryResponse = (await http.post(
            Uri.parse(API_ENDPOINT + '/task_tracker/add_journal.php'),
            body: queryBody));
        Debug.LogResponse("Query executed : Results{${queryResponse.body}");
        if (queryResponse.body.toLowerCase().contains("success")) {
          //Success
        }
      } catch (e) {
        Debug.LogError('NC: Error adding journal entry $e}');
      }
      //executeQueries();
    }
    //Add to server and refresh Cache
    await executeQueries();
  }

  static Future<void> editJournal(
      DateTime oldDay, DateTime day, String title, String text) async {
    String oldId = username + DateFormat('yyyy-MM-dd').format(oldDay);
    String id = username + DateFormat('yyyy-MM-dd').format(day);
    Map<String, String> queryBody = <String, String>{
      'username': username,
      'old_id': oldId,
      'id': id,
      'title': title,
      'description': text
    };
    if (cacheEnabled) {
      //Add Query
      Map<String, Object> query = {
        Queries.colLink: 'edit_journal',
        Queries.colData: jsonEncode(queryBody)
      };

      Debug.LogResponse(
          "adding new query ${query[Queries.colLink]} : ${jsonEncode(queryBody)}");

      await cacheDb.insert('Queries', query);
      await cacheDb.rawUpdate(
          "UPDATE Journal SET id='$id', ${Journal.colTitle}='${title.toString().replaceAll("'", "''")}', ${Journal.colDescription}='${text.toString().replaceAll("'", "''")}' WHERE id='$oldId'");
      //update Cache
      Map<String, Object> data = {
        'id': id,
        Journal.colTitle: title,
        Journal.colDescription: text
      };
      // await cacheDb.insert('Journal', data);
      await refreshUserData(forceOffline: true);
    } else {
      try {
        http.Response queryResponse = (await http.post(
            Uri.parse(API_ENDPOINT + '/task_tracker/edit_journal.php'),
            body: queryBody));
        Debug.LogResponse("Query executed : Results{${queryResponse.body}");
        if (queryResponse.body.toLowerCase().contains("success")) {
          //Success
        }
      } catch (e) {
        Debug.LogError('NC: Error adding journal entry $e}');
      }
      //executeQueries();
    }
    //Add to server and refresh Cache
    await executeQueries();
  }

  static Future<void> addTodo(String taskType, String metadata,
      DateTime dueDate, DateTime? notificationTime) async {
    String taskId = username + taskType;
    if (taskId.contains('[') && taskId.contains(']')) {
      //has a project related
      taskId = taskId.substring(0, taskId.indexOf('[') - 1);
    }

    String id = taskId + metadata;

    Map<String, String> queryBody = <String, String>{
      'username': username,
      'task': taskId,
      'metadata': metadata,
      'due_date': DateFormat('yyyy-MM-dd').format(dueDate),
      if (notificationTime != null)
        'notification_time':
            DateFormat('yyyy-MM-dd HH:mm').format(notificationTime)
    };
    if (cacheEnabled) {
      //Add Query
      Map<String, Object> query = {
        Queries.colLink: 'add_todo',
        Queries.colData: jsonEncode(queryBody)
      };

      Debug.LogResponse(
          "adding new query ${query[Queries.colLink]} : ${jsonEncode(queryBody)}");

      await cacheDb.insert('Queries', query);

      //update Cache
      Map<String, Object> data = {
        'id': id,
        Todo.colCat: taskId,
        Todo.colMetadata: metadata,
        Todo.colDueDate: DateFormat('yyyy-MM-dd').format(dueDate),
        if (notificationTime != null)
          Todo.colNotificationTime:
              DateFormat('yyyy-MM-dd HH:mm').format(notificationTime)
      };
      await cacheDb.insert('Todos', data);
      await refreshUserData(forceOffline: true);
    } else {
      try {
        http.Response queryResponse = (await http.post(
            Uri.parse(API_ENDPOINT + '/task_tracker/add_todo.php'),
            body: queryBody));
        Debug.LogResponse("Query executed : Results{${queryResponse.body}");
        if (queryResponse.body.toLowerCase().contains("success")) {
          //Success
        }
      } catch (e) {
        Debug.LogError('NC: Error adding journal entry $e}');
      }
      //executeQueries();
    }
    //Add to server and refresh Cache
    await executeQueries();
  }

  static Future<void> editTodo(String oldId, String taskType, String metadata,
      DateTime dueDate, DateTime? notificationTime) async {
    String taskId = username + taskType;
    if (taskId.contains('[') && taskId.contains(']')) {
      //has a project related
      taskId = taskId.substring(0, taskId.indexOf('[') - 1);
    }

    String id = taskId + metadata;

    Map<String, String> queryBody = <String, String>{
      'old_id': oldId,
      'username': username,
      'task': taskId,
      'metadata': metadata,
      'due_date': DateFormat('yyyy-MM-dd').format(dueDate),
      if (notificationTime != null)
        'notification_time':
            DateFormat('yyyy-MM-dd HH:mm').format(notificationTime)
    };
    if (cacheEnabled) {
      //Add Query
      Map<String, Object> query = {
        Queries.colLink: 'edit_todo',
        Queries.colData: jsonEncode(queryBody)
      };

      Debug.LogResponse(
          "adding new query ${query[Queries.colLink]} : ${jsonEncode(queryBody)}");

      await cacheDb.insert('Queries', query);
      String dueDateString = DateFormat('yyyy-MM-dd').format(dueDate);
      //update Cache
      //  Map<String, Object> data = {'id': id, Todo.colCat: taskId, Todo.colMetadata: metadata, Todo.colDueDate: DateFormat('yyyy-MM-dd').format(dueDate), if(notificationTime!=null)Todo.colNotificationTime:DateFormat('yyyy-MM-dd HH:mm').format(notificationTime)};
      // await cacheDb.insert('Todos', data);
      await cacheDb.rawUpdate(
          "UPDATE Todos SET id='$id', ${Todo.colCat}='$taskId', ${Todo.colMetadata}='$metadata', ${Todo.colDueDate}='$dueDateString'${(notificationTime != null) ? ", ${Todo.colNotificationTime}='${DateFormat('yyyy-MM-dd HH:mm').format(notificationTime)}'" : ''} WHERE id='$oldId'");
      await refreshUserData(forceOffline: true);
    } else {
      try {
        http.Response queryResponse = (await http.post(
            Uri.parse(API_ENDPOINT + '/task_tracker/edit_todo.php'),
            body: queryBody));
        Debug.LogResponse("Query executed : Results{${queryResponse.body}");
        if (queryResponse.body.toLowerCase().contains("success")) {
          //Success
        }
      } catch (e) {
        Debug.LogError('NC: Error editing todo entry $e}');
      }
      //executeQueries();
    }
    //Add to server and refresh Cache
    await executeQueries();
  }

  static Future<void> deleteTask(String name, {bulk = false}) async {
    Map<String, String> queryBody = <String, String>{
      'id': username + name,
      'username': username,
      'device_id': await Settings.UUID(),
    };
    //Add Query
    Map<String, Object> query = {
      Queries.colLink: 'delete_taskType',
      Queries.colData: jsonEncode(queryBody)
    };

    Debug.LogResponse(
        "adding new query ${query[Queries.colLink]} : ${jsonEncode(queryBody)}");
    if (cacheEnabled) {
      await cacheDb.insert('Queries', query);

      //update Cache
      Map<String, Object> data = {
        TaskType.colId: username + name,
        Category.colName: name,
      };
      await cacheDb
          .rawDelete("DELETE FROM TaskTypes WHERE id='${username + name}'");

      await refreshUserData(forceOffline: true);
      //Add to server and refresh Cache
    } else {
      try {
        http.Response queryResponse = (await http.post(
            Uri.parse(API_ENDPOINT + '/task_tracker/delete_taskType.php'),
            body: queryBody));
        Debug.LogResponse("Query executed : Results{${queryResponse.body}");
        if (queryResponse.body.toLowerCase().contains("success")) {
          //Success
        }
      } catch (e) {
        Debug.LogError('NC: Error editing acti $e}');
      }
    }
    if (!bulk) {
      await executeQueries();
    }
  }

  static Future<void> deleteCategory(String name, {bulk = false}) async {
    Map<String, String> queryBody = <String, String>{
      'id': username + name,
      'username': username,
      'device_id': await Settings.UUID(),
    };
    //Add Query
    Map<String, Object> query = {
      Queries.colLink: 'delete_category',
      Queries.colData: jsonEncode(queryBody)
    };

    Debug.LogResponse(
        "adding new query ${query[Queries.colLink]} : ${jsonEncode(queryBody)}");
    if (cacheEnabled) {
      await cacheDb.insert('Queries', query);

      //update Cache
      Map<String, Object> data = {
        TaskType.colId: username + name,
        Category.colName: name,
      };
      await cacheDb.rawDelete(
          "DELETE FROM Categories WHERE ${Category.colCatId}='${username + name}'");
      await refreshUserData(forceOffline: true);
      //Add to server and refresh Cache
    } else {
      try {
        http.Response queryResponse = (await http.post(
            Uri.parse(API_ENDPOINT + '/task_tracker/delete_category.php'),
            body: queryBody));
        Debug.LogResponse("Query executed : Results{${queryResponse.body}");
        if (queryResponse.body.toLowerCase().contains("success")) {
          //Success
        }
      } catch (e) {
        Debug.LogError('NC: Error editing acti $e}');
      }
    }
    if (!bulk) {
      await executeQueries();
    }
  }

  static Future<void> deleteActivity(Activity activity, {bulk = false}) async {
    Map<String, String> queryBody = <String, String>{
      'username': username,
      'device_id': await Settings.UUID(),
      'sTime': activity.trueStartTime.toString(),
      'eTime': activity.trueEndTime.toString(),
    };
    //Add Query
    Map<String, Object> query = {
      Queries.colLink: 'delete_activity',
      Queries.colData: jsonEncode(queryBody)
    };

    Debug.LogResponse(
        "adding new query ${query[Queries.colLink]} : ${jsonEncode(queryBody)}");

    if (cacheEnabled) {
      await cacheDb.insert('Queries', query);

      //update Cache
      String deleteQuery =
          "DELETE FROM Activities WHERE ${Activity.colStartTime}=datetime('${dFormat.format(activity.trueStartTime)}') AND ${Activity.colEndTime}=datetime('${dFormat.format(activity.trueEndTime)}')";
      Debug.LogResponse("delteQuery : $deleteQuery");

      await cacheDb.rawDelete(deleteQuery);
      await refreshUserData(forceOffline: true);
      //Add to server and refresh Cache
    } else {
      try {
        http.Response queryResponse = (await http.post(
            Uri.parse(API_ENDPOINT + '/task_tracker/delete_activity.php'),
            body: queryBody));
        Debug.LogResponse("Query executed : Results{${queryResponse.body}");
        if (queryResponse.body.toLowerCase().contains("success")) {
          //Success
        }
      } catch (e) {
        Debug.LogError('NC: Error editing acti $e}');
      }
    }
    if (!bulk) {
      await executeQueries();
    }
  }

  static Future<void> deleteProject(String project, {bulk = false}) async {
    Map<String, String> queryBody = <String, String>{
      'username': username,
      'name': username + project,
    };
    //Add Query
    Map<String, Object> query = {
      Queries.colLink: 'delete_project',
      Queries.colData: jsonEncode(queryBody)
    };

    Debug.LogResponse(
        "adding new query ${query[Queries.colLink]} : ${jsonEncode(queryBody)}");

    if (cacheEnabled) {
      await cacheDb.insert('Queries', query);

      //update Cache
      String deleteQuery =
          "DELETE FROM Projects WHERE ${Project.colName}='${username + project}'";
      Debug.LogResponse("delteQuery : $deleteQuery");

      await cacheDb.rawDelete(deleteQuery);
      await refreshUserData(forceOffline: true);
      //Add to server and refresh Cache
    } else {
      try {
        http.Response queryResponse = (await http.post(
            Uri.parse(API_ENDPOINT + '/task_tracker/delete_project.php'),
            body: queryBody));
        Debug.LogResponse("Query executed : Results{${queryResponse.body}");
        if (queryResponse.body.toLowerCase().contains("success")) {
          //Success
        }
      } catch (e) {
        Debug.LogError('NC: Error deleting project $e}');
      }
    }
    if (!bulk) {
      await executeQueries();
    }
  }

  static Future<void> deleteJournal(String id, {bulk = false}) async {
    Map<String, String> queryBody = <String, String>{
      'username': username,
      'id': id,
    };
    //Add Query
    Map<String, Object> query = {
      Queries.colLink: 'delete_journal',
      Queries.colData: jsonEncode(queryBody)
    };

    Debug.LogResponse(
        "adding new query ${query[Queries.colLink]} : ${jsonEncode(queryBody)}");

    if (cacheEnabled) {
      await cacheDb.insert('Queries', query);

      //update Cache
      String deleteQuery = "DELETE FROM Journal WHERE id='$id'";
      Debug.LogResponse("delteQuery : $deleteQuery");

      await cacheDb.rawDelete(deleteQuery);
      await refreshUserData(forceOffline: true);
      //Add to server and refresh Cache
    } else {
      try {
        http.Response queryResponse = (await http.post(
            Uri.parse(API_ENDPOINT + '/task_tracker/delete_journal.php'),
            body: queryBody));
        Debug.LogResponse("Query executed : Results{${queryResponse.body}");
        if (queryResponse.body.toLowerCase().contains("success")) {
          //Success
        }
      } catch (e) {
        Debug.LogError('NC: Error deleting journal $e}');
      }
    }
    if (!bulk) {
      await executeQueries();
    }
  }

  static Future<void> deleteTodo(String id, {bulk = false}) async {
    Map<String, String> queryBody = <String, String>{
      'username': username,
      'id': id,
    };
    //Add Query
    Map<String, Object> query = {
      Queries.colLink: 'delete_todo',
      Queries.colData: jsonEncode(queryBody)
    };

    Debug.LogResponse(
        "adding new query ${query[Queries.colLink]} : ${jsonEncode(queryBody)}");

    if (cacheEnabled) {
      await cacheDb.insert('Queries', query);

      //update Cache
      String deleteQuery = "DELETE FROM Todos WHERE id='$id'";
      Debug.LogResponse("delteQuery : $deleteQuery");

      await cacheDb.rawDelete(deleteQuery);
      await refreshUserData(forceOffline: true);
      //Add to server and refresh Cache
    } else {
      try {
        http.Response queryResponse = (await http.post(
            Uri.parse(API_ENDPOINT + '/task_tracker/delete_todo.php'),
            body: queryBody));
        Debug.LogResponse("Query executed : Results{${queryResponse.body}");
        if (queryResponse.body.toLowerCase().contains("success")) {
          //Success
        }
      } catch (e) {
        Debug.LogError('NC: Error deleting journal $e}');
      }
    }
    if (!bulk) {
      await executeQueries();
    }
  }

  static Future<void> executeQueries() async {
    if (cacheEnabled) {
      if (offline) {
        Debug.Log("Cannot executre queries, Offline!");
        return;
      }
      List<Map<String, Object?>> queries = await cacheDb.query('Queries');

      for (Map<String, Object?> element in queries) {
        int id = int.parse(element['id'].toString());
        String? file = element[Queries.colLink].toString();
        String? data = element[Queries.colData].toString();
        if (file == null || data == null) {
          Debug.LogError("Null query, Ignoring...");
          continue;
        }
        Debug.LogResponse("Query[\n file:$file, \ndata:$data]");

        //Execute the http here
        Map<String, dynamic> body = jsonDecode(data);
        try {
          http.Response queryResponse = (await http.post(
              Uri.parse(API_ENDPOINT + '/task_tracker/$file.php'),
              body: body));
          Debug.LogResponse("Query executed : Results{${queryResponse.body}");
          if (queryResponse.body.toLowerCase().contains("+") ||
              queryResponse.body.toLowerCase().contains("success")) {
            await cacheDb.rawDelete('DELETE FROM Queries WHERE id=$id');
          }
          offline = false;
        } catch (e) {
          Debug.LogError("Error while query $e");
        }
      }
      //await refreshUserData();
    } else {
      await refreshUserData();
      Debug.LogError(
          'Trying to execute queries in no cahce mode, We dont do that here');
    }
  }
}
