import 'dart:math';
import 'package:ernaehrung/android/components/meal_page_text/days_component.dart';
import 'package:ernaehrung/android/config/cast_helper.dart';
import 'package:hive/hive.dart';
import '../models/food.dart';

class StatisticsService {
  final String reducedStatisticsBoxName = 'STATISTICS_REDUCED';
  final String mainStatisticsBoxName = 'STATISTICS_MAIN';

  StatisticsService()  {
    initBoxes();
  }

  initBoxes()async{
    Box reducedBox = Hive.box(reducedStatisticsBoxName);
    putIfKeyNotExists(reducedBox, 'FRÜHSTÜCK', []);
    putIfKeyNotExists(reducedBox, 'MITTAGESSEN', []);
    putIfKeyNotExists(reducedBox, 'ABENDESSEN', []);
    updateReducedBoxByTimespan(TimeSpan.day);
  }

  void putIfKeyNotExists(Box box, String key, dynamic value) {
    if (!box.containsKey(key)) {
      box.put(key, value);
    }
  }

  updateReducedBoxByTimespan(TimeSpan timeSpan){
    clearReducedBoxBeforeUpdate();
    DateTime now = DateTime.now();
    int timestamp = now.millisecondsSinceEpoch.toInt() ~/ 1000;
    switch(timeSpan){
       case TimeSpan.day:
        getNewFoodAndUpdateReducedBoxByTimestamp(timestamp);
        break;
       case TimeSpan.week:
         List<int> currentWeek = getTimestampsByTimestampAndTimespan(TimeSpan.week,timestamp);
         for(int i = 0;i < currentWeek.length;i++){
           getNewFoodAndUpdateReducedBoxByTimestamp(currentWeek[i]);
         }
         break;
      case TimeSpan.month:
        List<int> currentMonth = getTimestampsByTimestampAndTimespan(TimeSpan.month,timestamp);
        for(int i = 0;i < currentMonth.length;i++){
          getNewFoodAndUpdateReducedBoxByTimestamp(currentMonth[i]);
        }
        break;
     }
  }

  void getNewFoodAndUpdateReducedBoxByTimestamp(int timestamp){
    Map<String,List<Food>> newFood = getFoodMapForGivenTimestampFromMainBox(timestamp);
    if(newFood.keys.isNotEmpty){
      setElementsOfReducedBox(newFood);
    }
  }

  List<int> getTimestampsByTimestampAndTimespan(TimeSpan timespan, int timestamp) {
    int range = timespan == TimeSpan.week ? 7 : 31;
    int targetWeekday = DateTime.monday; // Example target weekday (Monday)
    DateTime currentDateTime = DateTime.fromMillisecondsSinceEpoch(timestamp * 1000);
    int currentWeekday = currentDateTime.weekday;
    int daysToAdd = targetWeekday - currentWeekday;
    DateTime targetDateTime = currentDateTime.add(Duration(days: daysToAdd));

    List<int> timestampsForWeekdays = [];
    for (int i = 0; i < range; i++) {
      timestampsForWeekdays.add(targetDateTime.millisecondsSinceEpoch ~/ 1000);
      targetDateTime = targetDateTime.add(const Duration(days: 1));
    }
    return timestampsForWeekdays;
  }

  clearReducedBoxBeforeUpdate(){
    Box box = Hive.box(reducedStatisticsBoxName);
    for(int i = 0; i < box.keys.length;i++){
      box.put(box.keys.elementAt(i), []);
    }
  }
  setElementsOfReducedBox(Map<String,List<Food>> newFood){
    Box box = Hive.box(reducedStatisticsBoxName);
    Iterable<String> keys = newFood.keys;
    for(int i = 0; i < keys.length;i++){
      box.put(keys.elementAt(i), newFood[keys.elementAt(i)] ?? []);
    }
  }

  getDayAsIntFromTimestamp(int timestamp){
    DateTime dateTime = DateTime.fromMillisecondsSinceEpoch(timestamp * 1000);
    return dateTime.day;
  }

  Map<String,List<Food>> getFoodMapForGivenTimestampFromMainBox(int timestamp){
    Box box = Hive.box(mainStatisticsBoxName);
    dynamic matchingTimestamp = getMatchingTimeStamp(box, timestamp);
    if(matchingTimestamp != null){
      return castDynamicMap(box.get(matchingTimestamp));
    }
    return <String,List<Food>>{};
  }

  getMatchingTimeStamp(Box box,int newTimestamp){
    if(box.keys.isNotEmpty){
      for(int i = 0; i < box.keys.length;i++){
        int timestamp = box.keys.elementAt(i);
        if(isDateEqual(newTimestamp, timestamp)){
          return timestamp;
        }
      }
      return null;
    }
  }

  getMonthAsIntFromTimestamp(int timestamp){
    DateTime dateTime = DateTime.fromMillisecondsSinceEpoch(timestamp * 1000);
    return dateTime.month;
  }

  getYearAsIntFromTimestamp(int timestamp){
    DateTime dateTime = DateTime.fromMillisecondsSinceEpoch(timestamp * 1000);
    return dateTime.year;
  }

  isDateEqual(int timestamp1, int timestamp2){
    return
      getDayAsIntFromTimestamp(timestamp1) == getDayAsIntFromTimestamp(timestamp2) &&
      getMonthAsIntFromTimestamp(timestamp1) == getMonthAsIntFromTimestamp(timestamp2) &&
      getYearAsIntFromTimestamp(timestamp1) == getYearAsIntFromTimestamp(timestamp2);
  }

  addItemToMainBox(Food value, String mealType){
    // Hive.deleteFromDisk();
    Box box = Hive.box(mainStatisticsBoxName);
    DateTime dateTime = DateTime.now();

    // DEBUG
    //DateTime dateTime = getRandomTimestampForTesting();

    int newTimestamp = dateTime.millisecondsSinceEpoch.toInt() ~/ 1000;

    dynamic matchingTimestamp = getMatchingTimeStamp(box, newTimestamp);
    if(matchingTimestamp != null){
      newTimestamp = matchingTimestamp;
    }
    Map<String, List<Food>> valueMap = castDynamicMap(box.get(newTimestamp));
    List<Food> values = [];
    if(valueMap.containsKey(mealType)){
      values = valueMap[mealType]!;
    }
    values.add(value);
    valueMap[mealType] = values;
    box.put(newTimestamp, valueMap);
  }

  getRandomTimestampForTesting(){
    DateTime now = DateTime.now();
    DateTime startOfWeek = now.subtract(Duration(days: now.weekday - 1));
    DateTime endOfWeek = startOfWeek.add(const Duration(days: 6));

    Random random = Random();
    int randomMilliseconds = random.nextInt(endOfWeek.millisecondsSinceEpoch - startOfWeek.millisecondsSinceEpoch);
    DateTime randomTimestamp = startOfWeek.add(Duration(milliseconds: randomMilliseconds));

    return randomTimestamp;
  }

  int getAllEatenCaloriesForTodayStatistics(){
    Box box = Hive.box(reducedStatisticsBoxName);
    num sum = 0;
    for(int i = 0; i < box.keys.length;i++){
      for(Food food in box.get(box.keys.elementAt(i))){
        sum += food.calories;
      }
    }
    return sum as int;
  }

  num getAllCaloriesByBoxAndTimestamp(Box box,int timestamp){
    Map<String, List<Food>> valueMap = castDynamicMap(box.get(timestamp));
    num sum = 0;
    for(var mealType in valueMap.keys){
      if(valueMap.containsKey(mealType)){
        List<Food> values = valueMap[mealType]!;
        for(var value in values){
          sum += value.calories;
        }
      }
    }
    return sum;
  }

  num getCaloriesByTimestampAndMealTypeAndBox(Box box,DateTime date, String mealType){
    int  timestamp = date.millisecondsSinceEpoch.toInt() ~/ 1000;
    Map<String, List<Food>> valueMap = castDynamicMap(box.get(timestamp));
    num sum = 0;
    if(valueMap.containsKey(mealType)){
      List<Food> values = valueMap[mealType]!;
      for(var value in values){
        sum += value.calories;
      }
    }
    return sum;
  }

  showItems(){
    print("Statistics.dart - showItems() - ITEMS");
    //Hive.box(boxName).clear();
    print(Hive.box(mainStatisticsBoxName).keys.length);
    for(int i = 0; i < Hive.box(mainStatisticsBoxName).keys.length; i++){
      print(Hive.box(mainStatisticsBoxName).keys.elementAt(i));
      print(Hive.box(mainStatisticsBoxName).values.elementAt(i));
      //print(Hive.box(boxName).keys.elementAt(i) + " " + Hive.box(boxName).values.elementAt(i));
    }
  }

}