import 'dart:async';
import 'dart:collection';
import 'dart:convert';
import 'dart:io';
import 'dart:ui';

import 'package:device_calendar/device_calendar.dart';
import 'package:flutter/widgets.dart';
import 'package:hmg_patient_app_new/core/dependencies.dart';
import 'package:hmg_patient_app_new/core/utils/date_util.dart';
import 'package:hmg_patient_app_new/extensions/string_extensions.dart';
import 'package:hmg_patient_app_new/presentation/prescriptions/prescription_reminder_view.dart';
import 'package:hmg_patient_app_new/services/dialog_service.dart';
import 'package:hmg_patient_app_new/services/permission_service.dart';
import 'package:hmg_patient_app_new/widgets/common_bottom_sheet.dart';
import 'package:jiffy/jiffy.dart';
import 'package:manage_calendar_events/manage_calendar_events.dart' as ios;
import 'package:permission_handler/permission_handler.dart';
import 'package:timezone/data/latest.dart' as tzl;

final DeviceCalendarPlugin deviceCalendarPlugin = DeviceCalendarPlugin();
final ios.CalendarPlugin _myPlugin = ios.CalendarPlugin();

class CalendarUtils {
  static Completer<CalendarUtils>? _completer;

  dynamic get writableCalendars => calendars.firstWhere((c) => !c.isReadOnly!);
  dynamic calendars;

  CalendarUtils._(this.calendars);

  // static Future<CalendarUtils> getInstance() async {
  //   if (_completer == null) {
  //     _completer = Completer<CalendarUtils>();
  //     print(_completer!.isCompleted);
  //     try {
  //       final dynamic calendarsResult;
  //       if (Platform.isIOS) {
  //         calendarsResult = await _myPlugin.getCalendars();
  //         if (!_completer!.isCompleted) {
  //           _completer?.complete(CalendarUtils._(await calendarsResult!));
  //         }
  //       } else {
  //         calendarsResult = await deviceCalendarPlugin.retrieveCalendars();
  //         if (!_completer!.isCompleted) {
  //           _completer?.complete(CalendarUtils._(await calendarsResult.data!));
  //         }
  //       }
  //     } on Exception catch (e) {
  //       if (!_completer!.isCompleted) {
  //         _completer!.completeError(e);
  //       }
  //     }
  //   }
  //   return _completer!.future;
  // }

  static Future<CalendarUtils> getInstance() async {
    tzl.initializeTimeZones();
    if (_completer != null) {
      return _completer!.future;
    }
    _completer = Completer<CalendarUtils>();
    try {
      final dynamic calendarsResult;
      if (Platform.isIOS) {
        calendarsResult = await _myPlugin.getCalendars();
        _completer!.complete(CalendarUtils._(calendarsResult));
      } else {
        calendarsResult = await deviceCalendarPlugin.retrieveCalendars();
        _completer!.complete(CalendarUtils._(calendarsResult.data));
      }
    } catch (e) {
      _completer!.completeError(e);
    }

    return _completer!.future;
  }

  Future createOrUpdateEvents({List<DateTime>? scheduleList, String? title, String? description, List<DateTime>? scheduleDateTime, List<DayOfWeek>? daysOfWeek}) async {
    tzl.initializeTimeZones();
    List<Event> events = [];
    Location _currentLocation;
    if (DateTime.now().timeZoneName == "+04")
      _currentLocation = getLocation('Asia/Dubai');
    else
      _currentLocation = getLocation('Asia/Riyadh');

    scheduleDateTime!.forEach((element) {
      RecurrenceRule recurrenceRule = RecurrenceRule(
        // RecurrenceFrequency.Daily,
        // daysOfWeek: daysOfWeek,
        // endDate: element,
        until: element, frequency: Frequency.daily,
      );
      //added byAamir Tz Time
      Event event = Event(writableCalendars!.id,
          recurrenceRule: recurrenceRule,
          start: TZDateTime.from(element, _currentLocation),
          end: TZDateTime.from(element.add(Duration(minutes: 30)), _currentLocation),
          title: title,
          description: description);
      events.add(event);
    });

    events.forEach((element) {
      deviceCalendarPlugin.createOrUpdateEvent(element);
    });
  }

  Future createOrUpdateEvent({required String title, required String description, required String location, DateTime? scheduleDateTime, String? eventId}) async {
    RecurrenceRule recurrenceRule = RecurrenceRule(
      // RecurrenceFrequency.Daily,
      // daysOfWeek: daysOfWeek,
      // endDate: scheduleDateTime,
      until: scheduleDateTime, frequency: Frequency.daily,
    );

    Location _currentLocation;
    // if (DateTime.now().timeZoneName == "+04")
    //   _currentLocation = getLocation('Asia/Dubai');
    // else
    _currentLocation = getLocation('Asia/Riyadh');

    TZDateTime scheduleDateTimeUTZ = TZDateTime.from(scheduleDateTime!, _currentLocation);

    print("writableCalendars-name:  " + writableCalendars.name);
    print("writableCalendars-Id:  " + writableCalendars.id);
    print("writableCalendarsToString:  " + writableCalendars.toString());
    print("writableCalendarsToString:  " + writableCalendars!.id!);
    Event event = Event(
      writableCalendars!.id,
      start: scheduleDateTimeUTZ,
      end: scheduleDateTimeUTZ.add(Duration(minutes: 30)),
      title: title,
      description: description,
    );

    ios.CalendarEvent iosCalEvent =
        ios.CalendarEvent(location: location, startDate: scheduleDateTimeUTZ, endDate: scheduleDateTimeUTZ.add(Duration(minutes: 30)), title: title, description: description, isAllDay: false);

    if (Platform.isAndroid) {
      Result<bool> result = await deviceCalendarPlugin.hasPermissions();
      print(result);
      await deviceCalendarPlugin.createOrUpdateEvent(event).catchError((e) {
        print("catchError " + e.toString());
      }).whenComplete(() {
        print("whenComplete Calender ID " + eventId!);
      });
    } else {
      await _myPlugin.createEvent(calendarId: writableCalendars.id!, event: iosCalEvent).catchError((e) {
        print("catchError " + e.toString());
      }).whenComplete(() {
        print("whenComplete Calender ID iOS " + eventId!);
      });
    }
  }

  deleteEvent(String _calendarId, String _eventId) async {
    if (Platform.isIOS) {
      await _myPlugin.deleteEvent(calendarId: _calendarId, eventId: _eventId);
    } else {
      await deviceCalendarPlugin.deleteEvent(_calendarId, _eventId);
    }
  }

  Future retrieveEvents(
    String calendarId,
    RetrieveEventsParams retrieveEventsParams,
  ) async {
    if (Platform.isIOS) {
      return await _myPlugin.getEvents(calendarId: calendarId);
    } else {
      return await deviceCalendarPlugin.retrieveEvents(calendarId, retrieveEventsParams);
    }
  }

  Future createCalendar(
    String calendarName, {
    Color? calendarColor,
    String? localAccountName,
  }) async {
    return await deviceCalendarPlugin.createCalendar(calendarName, calendarColor: calendarColor, localAccountName: localAccountName);
  }
}

Future<Map<Permission, PermissionStatus>> requestPermissions() async {
  var permissionResults = [Permission.calendarFullAccess].request();
  return permissionResults;
}

showReminderBottomSheet(BuildContext context, DateTime dateTime, String doctorName, String eventId, String appoDateFormatted, String appoTimeFormatted,
    {required Function() onSuccess, String? title, String? description, Function(int)? onMultiDateSuccess, bool isMultiAllowed = false}) async {
  if (Platform.isAndroid) {
    if (await PermissionService.isCalendarPermissionEnabled()) {
      _showReminderBottomSheet(context, dateTime, doctorName, eventId, appoDateFormatted, appoTimeFormatted,
          onSuccess: onSuccess, title: title, description: description, onMultiDateSuccess: onMultiDateSuccess, isMultiAllowed: isMultiAllowed);
    } else {
      // Utils.showPermissionConsentDialog(context, TranslationBase.of(context).calendarPermission, () async {
      //   if (await Permission.calendarFullAccess.request().isGranted) {
      //     _showReminderDialog(context, dateTime, doctorName, eventId, appoDateFormatted, appoTimeFormatted,
      //         onSuccess: onSuccess, title: title, description: description, onMultiDateSuccess: onMultiDateSuccess, isMultiAllowed: isMultiAllowed);
      //   }
      // });
    }
  } else {
    if (await Permission.calendarWriteOnly.request().isGranted) {
      if (await Permission.calendarFullAccess.request().isGranted) {
        _showReminderBottomSheet(context, dateTime, doctorName, eventId, appoDateFormatted, appoTimeFormatted,
            onSuccess: onSuccess, title: title, description: description, onMultiDateSuccess: onMultiDateSuccess, isMultiAllowed: isMultiAllowed);
      }
    }
  }
}

Future<void> _showReminderBottomSheet(BuildContext providedContext, DateTime dateTime, String doctorName, String eventId, String appoDateFormatted, String appoTimeFormatted,
    {required Function onSuccess, String? title, String? description, Function(int)? onMultiDateSuccess, bool? isMultiAllowed}) async {
  showCommonBottomSheetWithoutHeight(providedContext, title: "Set the timer of reminder".needTranslation, child: PrescriptionReminderView(
    setReminder: (int value) async {
      if (!isMultiAllowed!) {
        if (onMultiDateSuccess == null) {
          CalendarUtils calendarUtils = await CalendarUtils.getInstance();
          await calendarUtils.createOrUpdateEvent(
              title: title ?? "You have appointment with Dr. ".needTranslation + doctorName,
              description: description ?? "At " + appoDateFormatted + " " + appoTimeFormatted,
              scheduleDateTime: dateTime,
              eventId: eventId,
              location: '');
          onSuccess();
        }
      } else {
        onMultiDateSuccess!(value);
      }
    },
  ), callBackFunc: () {}, isFullScreen: false);
}

setCalender(BuildContext context,
    {required String eventId, required int selectedMinutes, int? frequencyNumber, required int days, required String orderDate, required String itemDescriptionN, required String route}) async {
  DateTime actualDate = DateTime(DateTime.now().year, DateTime.now().month, DateTime.now().day, 8, 0);
  frequencyNumber ??= 2; //Some time frequency number is null so by default will be 2

  int remainingDays = days - (Jiffy.parseFromDateTime(DateTime.now()).diff(Jiffy.parseFromDateTime(DateUtil.convertStringToDate(orderDate)), unit: Unit.day) as int);
  if (remainingDays.isNegative) {
    getIt.get<DialogService>().showErrorBottomSheet(message: "Prescription date has been already passed you can not add a reminder for this prescription.");
    return;
  }
  CalendarUtils calendarUtils = await CalendarUtils.getInstance();

  try {
    for (int i = 0; i < remainingDays; i++) {
      //event for number of days.
      for (int j = 0; j < frequencyNumber; j++) {
        // event for number of times per day.
        if (j != 0) {
          actualDate.add(new Duration(hours: 8)); // 8 hours addition for daily dose.
        }
        //Time subtraction from actual reminder time. like before 30, or 1 hour.

        actualDate = Jiffy.parseFromDateTime(actualDate).subtract(minutes: selectedMinutes).dateTime;

        calendarUtils.createOrUpdateEvent(
          title: "$itemDescriptionN} Prescription Reminder",
          description: "$itemDescriptionN $frequencyNumber $route ",
          scheduleDateTime: actualDate,
          eventId: eventId + (i.toString() + j.toString()),
          location: '', //event id with  varitions
        );

        actualDate = DateTime(actualDate.year, actualDate.month, actualDate.day, 8, 0);
      }
      actualDate = Jiffy.parseFromDateTime(actualDate).add(days: 1).dateTime;
    }
  } catch (ex) {
    getIt.get<DialogService>().showErrorBottomSheet(message: "catch:$ex");
  }
}

Future<void> checkAndRemove(hasReminder, {bool delete = false, String itemDescriptionN = ""}) async {
  final ios.CalendarPlugin _myPlugin = ios.CalendarPlugin();
  CalendarUtils calendarUtils = await CalendarUtils.getInstance();
  DateTime startEventsDate = Jiffy.parseFromDateTime(DateTime.now()).subtract(days: 30).dateTime;
  DateTime endEventsDate = Jiffy.parseFromDateTime(DateTime.now()).add(days: 120).dateTime;
  RetrieveEventsParams params = RetrieveEventsParams(startDate: startEventsDate, endDate: endEventsDate);

  if (calendarUtils.calendars != null) {
    if (Platform.isAndroid) {
      await processEvents(calendarUtils.calendars, calendarUtils, params, delete, itemDescriptionN, hasReminder);
    } else {
      List<ios.Calendar>? iosCalendars = await _myPlugin.getCalendars();
      if (iosCalendars != null) {
        await processEvents(iosCalendars.map((cal) => Calendar(id: cal.id, name: cal.name, accountName: cal.accountName)).toList(), calendarUtils, params, delete, itemDescriptionN, hasReminder);
      }
    }
  }
}

Future<void> processEvents(List<Calendar> calendars, calendarUtils, params, delete, String itemDescriptionN, hasReminder) async {
  for (var calendar in calendars) {
    Result<UnmodifiableListView<Event>> events = await calendarUtils.retrieveEvents(calendar.id!, params);
    for (var event in events.data!) {
      if (event.title!.contains(itemDescriptionN)) {
        if (delete) {
          await calendarUtils.deleteEvent(calendar, event);
          //  AppToast.showSuccessToast(message: TranslationBase.of(context).reminderCancelSuccess);
          hasReminder = false;
        } else {
          hasReminder = false;
          // setState(() {
          //   hasReminder = true;
          // });
        }
      }
    }
  }
}
