import 'dart:io';

import 'package:flutter_local_notifications/flutter_local_notifications.dart';
import 'package:intl/intl.dart';
import 'package:shared_preferences/shared_preferences.dart';

import 'Data.dart';
import 'DebugHelper.dart';
import 'Dialogs.dart';
import 'User.dart' as User;

class NotificationManager{

  static var fltrNotification;
  static void RescheduleNotifications() async{

    if(!User.cacheEnabled){print('Sorry no notifications for: ');return;}

    print("Rescheduling notifications");
    var androidInitilize = new AndroidInitializationSettings('@mipmap/ic_launcher');
    var iOSinitilize = new IOSInitializationSettings();

    var initilizationsSettings =
    new InitializationSettings(android: androidInitilize, iOS: iOSinitilize);
    fltrNotification = new FlutterLocalNotificationsPlugin();
    fltrNotification.initialize(initilizationsSettings, onSelectNotification: notificationSelected);

    await fltrNotification.cancel(0);
    await fltrNotification.cancel(2);

    int notification_interval = await Settings.getNotificationInterval();
    bool adaptive_notification = await Settings.getAdaptiveNotification();
    bool adaptive_notification_availabel = await Settings.adaptiveNotificationAvailable();

    var androidDetails = const AndroidNotificationDetails("Xperience", "TaskTracker", importance: Importance.max);
    var iSODetails = new IOSNotificationDetails();
    var generalNotificationDetails =
    new NotificationDetails(android: androidDetails, iOS: iSODetails);
    final prefs = await SharedPreferences.getInstance();
    if(prefs.containsKey('current_activity')) {
      String? ongoingActData = prefs.getString('current_activity');
      try {
        if (ongoingActData != null) {
          List<String> data = ongoingActData.split("<td>");
          const AndroidNotificationDetails androidNotificationDetails = AndroidNotificationDetails('0', 'Ongoing',
              enableVibration: false,
              playSound: false,
              ongoing: true,
              autoCancel: false);
          const NotificationDetails notificationDetails = NotificationDetails(android: androidNotificationDetails);
          final List<PendingNotificationRequest> pendingNotificationRequests =await fltrNotification.pendingNotificationRequests();
          bool containsNotification = false;
          for (var element in pendingNotificationRequests) {
            if(element.id==1){
              containsNotification=true;
              continue;
            }
          }
          if(!containsNotification) {
            await fltrNotification.show(
                1, 'Currently doing : ${data[0]}', 'Click on this notification to stop and add this activity', notificationDetails,
                payload: 'ongoingActivity');
          }
        }
      }catch(e){
        print("error ongoing activity");
        fltrNotification.cancel(1);
      }
    }else{
      fltrNotification.cancel(1);
    }

    User.todos.forEach((element) {
      if(element.notificationTime!=null){
        if(element.notificationTime!.isAfter(DateTime.now())){
          fltrNotification.schedule(2, "Time for ${element.task!.name}", "${element.metadata}", element.notificationTime, generalNotificationDetails);
        }


      }
    });

    if(adaptive_notification && adaptive_notification_availabel){
      print("Smart!, Using adaptive huh?");
      //Calculate you little thing! CALCULATE!'
      DateFormat timeFormat = DateFormat("HH:mm");
      DateTime baseline = DateTime(2000,2,2,0,0,0);
      Map<int,List<int>> timeMap = <int,List<int>>{};

      int totalDays = User.activities[0].startTime.difference(User.activities[User.activities.length-1].startTime).inDays;
      int groupingThreshold = 60;
      print("Iterating thru ${User.activities.length} activities of $totalDays");
      for (var element in User.activities) {
        if(element.startTime.difference(DateTime.now()).inDays <30){
          //Eligible for adaptation
          DateTime thisTime =baseline.add(Duration(hours: element.startTime.hour, minutes: element.startTime.minute));
          int thisMin = thisTime.difference(baseline).inMinutes;
          int? chosenOne = null;
          int bestChoiceDiffer = groupingThreshold;

          timeMap.forEach((key, value) {
            if(key > thisMin-bestChoiceDiffer && key < thisMin+bestChoiceDiffer){
              //Eligible to apply
              chosenOne=key;
              bestChoiceDiffer = (key - thisMin).abs();
            }
          });

          if(chosenOne==null){
            //There were no candidates
            timeMap.putIfAbsent(thisMin, () => [thisMin]);
          }else{
            List<int> tempList = timeMap[chosenOne]!;
            tempList.add(thisMin);
            int newKey = 0;
            for (var element in tempList) {
              newKey+=element;
            }
            newKey = (newKey / tempList.length).toInt();
            timeMap.remove(chosenOne);
            timeMap.putIfAbsent(newKey, () => tempList);
          }
        }
      }
      Debug.LogResponse("${timeMap.length}",src:'Time Map');
      Debug.LogResponse(timeMap);
      timeMap.forEach((key, value) {
        DateTime now = DateTime.now();
        DateTime todayStart = DateTime(now.year,now.month,now.day,0,0,0);
        DateTime thisTime = todayStart.add(Duration(minutes: key));
        if(value.length < (totalDays.clamp(0, 30) / 3).ceil()){
          Debug.Log("${timeFormat.format(thisTime)} this happened only ${value.length} times, Ignoring...");
        }else {
          Debug.Log(timeFormat.format(thisTime));
          if(thisTime.isBefore(DateTime.now())) {
            thisTime = thisTime.add(Duration(days: 1));
          }
          Debug.LogResponse("Scheduling at $thisTime");
          fltrNotification.schedule(0, "Don't forget to add new activity", "Adaptive notifications suggests that you may have done by now to track.", thisTime, generalNotificationDetails);

        }
      });
    }else if(notification_interval>0) {

      var scheduledTime = DateTime.now().add(Duration(hours: notification_interval));
      fltrNotification.schedule(0, "What did you do in last $notification_interval hours?", "Click here to track your last activities...",
        scheduledTime, generalNotificationDetails,);
      print("Sent notification schedule");
    }

    await Future.delayed(Duration(seconds: 2));
   try{ final List<PendingNotificationRequest> pendingNotificationRequests =await fltrNotification.pendingNotificationRequests();
    Debug.LogResponse("Notifications");
    pendingNotificationRequests.forEach((element) {
      Debug.LogResponse("${element.id} : ${element.title} -> ${element.body} \n payload:${element.payload}");
    });}catch(e){
     Debug.LogError("Error printing notifications \n $e");
   }
  }

  static void notificationSelected(val){
    print("Selected notifications : $val");
    if(val=="ongoingActivity"){
      Dialogs.ongoing();
    }
    RescheduleNotifications();
  }
}