import 'dart:async';
import 'dart:convert';
import 'dart:developer';
import 'dart:io';

import 'package:device_calendar/device_calendar.dart';
import 'package:firebase_messaging/firebase_messaging.dart';
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:flutter_timezone/flutter_timezone.dart';
import 'package:google_api_availability/google_api_availability.dart';
import 'package:huawei_push/huawei_push.dart' as h_push;
import 'package:provider/provider.dart';
import 'package:test_sa/controllers/notification/notification_manger.dart';
import 'package:test_sa/extensions/context_extension.dart';
import 'package:test_sa/extensions/string_extensions.dart';
import 'package:test_sa/extensions/text_extensions.dart';
import 'package:test_sa/extensions/widget_extensions.dart';
import 'package:test_sa/new_views/common_widgets/app_lazy_loading.dart';

import 'cm_detail_provider.dart';

class CMRequestUtils {
  static double calculateAndAssignWorkingHours({
    required DateTime? startTime,
    required DateTime? endTime,
    required TextEditingController workingHoursController,
    required Function(double) updateModel, // A callback to update the model
  }) {
    if (startTime != null && endTime != null) {
      Duration difference = endTime.difference(startTime);
      double hours = difference.inMinutes / 60.0; // Calculate hours as a decimal
      workingHoursController.text = hours.toStringAsFixed(1); // Format to 1 decimal places
      updateModel(hours); // Call the function to update the model
      return hours;
    } else {
      return -1; // Indicating invalid input
    }
  }

  static bool isLocalUrl(String url) {
    if (url.isEmpty != false) return false;
    return url.startsWith("/") || url.startsWith("file://") || url.substring(1).startsWith(':\\');
  }

  static String calculateTimeDifference(DateTime startDate, DateTime endDate) {
    try {
      Duration diff = startDate.difference(endDate);
      int days = diff.inDays;
      int hours = diff.inHours.remainder(24);
      int minutes = diff.inMinutes.remainder(60);
      int seconds = diff.inSeconds.remainder(60);
      List<String> parts = [];
      if (days > 0) parts.add('$days ${days == 1 ? 'day' : 'days'}');
      if (hours > 0) parts.add('$hours ${hours == 1 ? 'hour' : 'hours'}');
      if (minutes > 0) parts.add('$minutes ${minutes == 1 ? 'minute' : 'minutes'}');
      if (seconds > 0) parts.add('$seconds ${seconds == 1 ? 'second' : 'seconds'}');
      String timeDifference = parts.isEmpty ? '' : parts.join(', ');
      return 'Action duration: $timeDifference';
    } catch (e) {
      return '';
    }
  }

  static String formatTimerDuration(int seconds) {
    int hours = seconds ~/ 3600;
    int minutes = (seconds % 3600) ~/ 60;
    int remainingSeconds = seconds % 60;

    String formattedDuration = '';
    if (hours > 0) {
      formattedDuration += '$hours hour${hours > 1 ? 's' : ''} ';
    }
    if (minutes > 0) {
      formattedDuration += '$minutes minute${minutes > 1 ? 's' : ''} ';
    }

    if (remainingSeconds > 0) {
      formattedDuration += '$remainingSeconds second${remainingSeconds > 1 ? 's' : ''} ';
    }

    if (formattedDuration.isEmpty) {
      formattedDuration = 'Less than a second';
    }

    return formattedDuration.trim();
  }

  static String formatTimerDurationCM(int seconds) {
    int hours = seconds ~/ 3600;
    int minutes = (seconds % 3600) ~/ 60;
    int remainingSeconds = seconds % 60;

    String formattedDuration = '';
    if (hours > 0) {
      formattedDuration += '$hours hour${hours > 1 ? 's' : ''} ';
    }
    if (minutes > 0) {
      formattedDuration += '$minutes minute${minutes > 1 ? 's' : ''} ';
    }
    if (remainingSeconds > 0) {
      formattedDuration += '$remainingSeconds second${remainingSeconds > 1 ? 's' : ''} ';
    }
    if (formattedDuration.isEmpty) {
      formattedDuration = 'Less than a minute';
    }

    return formattedDuration.trim();
  }

  static String formatTotalWorkingHours(double timeInHours) {
    // Convert hours → seconds
    int totalSeconds = (timeInHours * 3600).round();

    int hours = totalSeconds ~/ 3600;
    int minutes = (totalSeconds % 3600) ~/ 60;
    int remainingSeconds = totalSeconds % 60;

    String formattedDuration = '';
    if (hours > 0) {
      formattedDuration += '$hours hour${hours > 1 ? 's' : ''} ';
    }
    if (minutes > 0) {
      formattedDuration += '$minutes minute${minutes > 1 ? 's' : ''} ';
    }
    if (remainingSeconds > 0) {
      formattedDuration += '$remainingSeconds second${remainingSeconds > 1 ? 's' : ''} ';
    }
    if (formattedDuration.isEmpty) {
      formattedDuration = 'Less than a minute';
    }

    return formattedDuration.trim();
  }

  static void getQrCode({required BuildContext context}) async {
    showDialog(context: context, barrierDismissible: false, builder: (context) => const AppLazyLoading());
    CMDetailProvider requestDetailProvider = Provider.of<CMDetailProvider>(context, listen: false);
    String? base64String = await requestDetailProvider.getQrCode(workOrderId: requestDetailProvider.currentWorkOrder!.data!.requestId ?? 0);
    Navigator.pop(context);
    if (base64String != null) {
      // You have the base64 string, now you can display it
      Uint8List bytes = base64Decode(base64String);

      showDialog(
        context: context,
        builder: (BuildContext context) {
          return AlertDialog(
            backgroundColor: Colors.white,
            title: context.translation.scanQr.heading6(context).center,
            content: Image.memory(
              bytes, // Displaying the QR code from base64
              fit: BoxFit.contain, // Ensure the image fits well in the dialog
              errorBuilder: (context, error, stackTrace) {
                return const Icon(Icons.error, color: Colors.red);
              },
            ),
          );
        },
      );
    } else {
      log('Failed to get the QR code');
    }
  }

  static void scheduleOrUpdateNotification({required BuildContext context, required DateTime scheduleDateTime, required String workOrderId}) async {
    DateTime scheduleTime = scheduleDateTime;
    await NotificationManger.cancelNotificationById(workOrderId.hashCode);
    NotificationManger.scheduleNotification(id: workOrderId.hashCode, title: 'Scheduled Notification', body: '$scheduleTime', scheduledNotificationDateTime: scheduleTime);
  }

  //steps:
  //add permission for andriod..
  //add string in info.plist for ios...
  //tz.TZDateTime.from(movieScreening.dateTime, tz.local) some time you need to add this while making build..
  //create event..
  static void addOrUpdateEventToCalendar({
    required BuildContext context,
    required DateTime start,
    required DateTime end,
    required String title,
    String? workOrderNumber,
  }) async {
    final deviceCalendarPlugin = DeviceCalendarPlugin();
    final currentLocation = getLocation(await FlutterTimezone.getLocalTimezone());
    TZDateTime startDate = TZDateTime.from(start, currentLocation);
    TZDateTime endDate = TZDateTime.from(end, currentLocation);

    setLocalLocation(currentLocation);
    final calendarsResult = await deviceCalendarPlugin.retrieveCalendars();
    if (calendarsResult.data?.isEmpty ?? true) {
      'No calendars available on the device.'.showToast;
      return;
    }

    // Select a write able  calendar
    final writableCalendar = calendarsResult.data?.firstWhere(
      (calendar) => calendar.isReadOnly == false,
      orElse: () => Calendar(id: '', name: 'Default', isReadOnly: true),
    );

    if (writableCalendar == null || writableCalendar.isReadOnly == true) {
      log('No writable calendar found.');
      'No writable calendar found.'.showToast;
      return; // Handle the case where no writable calendar exists
    }

    final eventsResult = await deviceCalendarPlugin.retrieveEvents(
      writableCalendar.id!,
      RetrieveEventsParams(startDate: start.subtract(Duration(days: 7)), endDate: end.add(Duration(days: 30))),
    );
    if (!(eventsResult.isSuccess && eventsResult.data != null)) {
      "Failed to retrieve reminders.".showToast;
      return;
    }

    // Find an event with the matching workOrderNumber in the description
    final matchingEvent = eventsResult.data!.firstWhere(
      (event) => event.description?.contains('$workOrderNumber') ?? false,
      orElse: () => Event('0', eventId: null),
    );

    if (matchingEvent.eventId != null) {
      // Update the existing event
      matchingEvent.title = title;
      matchingEvent.start = startDate;
      matchingEvent.end = endDate;

      // Save the updated event
      final updateResult = await deviceCalendarPlugin.createOrUpdateEvent(matchingEvent);

      if (updateResult?.isSuccess == true) {
        log('Reminder updated successfully: ${updateResult?.data}');
        "Reminder updated successfully on device calendar".showToast;
      } else {
        log('Failed to update reminder: ${updateResult?.errors}');
        "Failed to update reminder on device calendar".showToast;
      }
    } else {
      // add event to calendar..
      final eventToCreate = Event(
        writableCalendar.id,
        title: title,
        description: 'You have a reminder for a visit for work order $workOrderNumber',
        start: startDate,
        end: endDate,
      );

      final createResult = await deviceCalendarPlugin.createOrUpdateEvent(eventToCreate);

      if (createResult?.isSuccess == true) {
        log('Reminder added successfully: ${createResult?.data}');
        //TODO need to confirm to show the message to user...
        'Reminder added to device calendar'.showToast;
      } else {
        log('Failed to add reminder: ${createResult?.errors}');
        'Failed to add reminder to device calendar'.showToast;
      }
    }
  }

  // static void addEventToCalendar({
  //   required BuildContext context,
  //   required DateTime start,
  //   required DateTime end,
  //   required String title,
  //   String? workOrderNumber,
  // }) async {
  //   final deviceCalendarPlugin = DeviceCalendarPlugin();
  //
  //   // Retrieve current timezone
  //   final currentLocation = getLocation(await FlutterTimezone.getLocalTimezone());
  //   setLocalLocation(currentLocation);
  //
  //   // Retrieve calendars
  //   final calendarsResult = await deviceCalendarPlugin.retrieveCalendars();
  //
  //   if (calendarsResult.data?.isEmpty ?? true) {
  //     ScaffoldMessenger.of(context).showSnackBar(
  //       SnackBar(content: Text('No calendars available on the device.')),
  //     );
  //     return;
  //   }
  //
  //   // Select a writable calendar
  //   final writableCalendar = calendarsResult.data?.firstWhere(
  //         (calendar) => calendar.isReadOnly == false,
  //     orElse: () => Calendar(id: '', name: 'Default', isReadOnly: true),
  //   );
  //
  //   if (writableCalendar == null || writableCalendar.isReadOnly==true) {
  //     log('No writable calendar found.');
  //     return; // Handle the case where no writable calendar exists
  //   }
  //   // Convert start and end times
  //   TZDateTime startDate = TZDateTime.from(start, currentLocation);
  //   TZDateTime endDate = TZDateTime.from(end, currentLocation);
  //
  //   // Create event
  //   final eventToCreate = Event(
  //     writableCalendar.id,
  //     title: title,
  //     description: 'You have a reminder for a visit for work order $workOrderNumber ',
  //     start: startDate,
  //     end: endDate,
  //   );
  //
  //   // Create or update the event
  //   final response = await deviceCalendarPlugin.createOrUpdateEvent(eventToCreate);
  //
  //   if (response?.isSuccess == true) {
  //     log('Event added successfully: ${response?.data}');
  //   } else {
  //     log('Failed to add event: ${response?.errors}');
  //     ScaffoldMessenger.of(context).showSnackBar(
  //       SnackBar(content: Text('Failed to add event to calendar.')),
  //     );
  //   }
  // }

  // static Future<void> updateEventOnCalendar({
  //   required BuildContext context,
  //   required String calendarId,
  //   required int requestId,
  //   required String updatedTitle,
  //   required DateTime updatedStart,
  //   required DateTime updatedEnd,
  // }) async {
  //   final deviceCalendarPlugin = DeviceCalendarPlugin();
  //
  //   // Retrieve all events in the calendar
  //   final eventsResult = await deviceCalendarPlugin.retrieveEvents(
  //     calendarId,
  //     RetrieveEventsParams(),
  //   );
  //
  //   if (!(eventsResult.isSuccess && eventsResult.data != null)) {
  //     ScaffoldMessenger.of(context).showSnackBar(
  //       SnackBar(content: Text('Failed to retrieve events.')),
  //     );
  //     return;
  //   }
  //
  //   // Find the event with the matching requestId
  //   final matchingEvent = eventsResult.data!.firstWhere(
  //         (event) => event.eventId == requestId.toString(),
  //     orElse: () => null,
  //   );
  //
  //   if (matchingEvent == null) {
  //     ScaffoldMessenger.of(context).showSnackBar(
  //       SnackBar(content: Text('Event not found for requestId: $requestId')),
  //     );
  //     return;
  //   }
  //
  //   // Update the event's details
  //   matchingEvent.title = updatedTitle;
  //   matchingEvent.start = updatedStart;
  //   matchingEvent.end = updatedEnd;
  //
  //   // Save the updated event
  //   final updateResult = await deviceCalendarPlugin.createOrUpdateEvent(matchingEvent);
  //
  //   if (updateResult?.isSuccess == true) {
  //     log('Event updated successfully: ${updateResult?.data}');
  //     ScaffoldMessenger.of(context).showSnackBar(
  //       SnackBar(content: Text('Event updated successfully.')),
  //     );
  //   } else {
  //     log('Failed to update event: ${updateResult?.errors}');
  //     ScaffoldMessenger.of(context).showSnackBar(
  //       SnackBar(content: Text('Failed to update event.')),
  //     );
  //   }
  // }

  // static void addEventToCalendar({required BuildContext context, required DateTime start, required DateTime end,required String title,required int ? requestId}) async {
  //
  //
  //   var currentLocation = getLocation(await FlutterTimezone.getLocalTimezone());
  //   final calendarsResult = await DeviceCalendarPlugin().retrieveCalendars();
  //
  //   if (calendarsResult.data?.isNotEmpty ?? false) {
  //     setLocalLocation(currentLocation);
  //     await Future.delayed(const Duration(seconds: 2));
  //     TZDateTime startDate = TZDateTime.from(start, currentLocation);
  //     TZDateTime endDate = TZDateTime.from(end, currentLocation);
  //     final calendarId = calendarsResult.data!.first.id; // Use the first calendar
  //
  //     var eventToCreate = Event(
  //       calendarId,
  //       eventId: requestId.toString(),
  //       title: title,
  //       description: "You have a reminder for a visit",
  //       start: startDate,
  //       end: endDate,
  //     );
  //     final response = await DeviceCalendarPlugin().createOrUpdateEvent(eventToCreate);
  //     log("Response of adding calendar is ${response?.data}");
  //   } else {
  //     // "No calendars available on the device.".showToast();
  //
  //   }
  // //   setLocalLocation(currentLocation);
  // //   await Future.delayed(const Duration(seconds: 2));
  // //   TZDateTime startDate = TZDateTime.from(start, currentLocation);
  // //   TZDateTime endDate = TZDateTime.from(end, currentLocation);
  // //   var eventToCreate = Event(
  // //     '0',
  // //     // eventId:requestId.toString(),
  // //     title: title,
  // //     description: "You have reminder for Visit",
  // //     start: startDate,
  // //     end: endDate,
  // //   );
  // //   log('event to add i  got is ${eventToCreate.toJson()}');
  // // final response =    await  DeviceCalendarPlugin().createOrUpdateEvent(eventToCreate);
  // // log("response of adding calander is ${response?.data}");
  // //
  // }

  // Map<String, dynamic> messageData = message.data;
  // if (messageData["notificationType"] != null && messageData["accept"] != null) {
  //   if (messageData["notificationType"] == "arrivalConfirmation") {
  //     if ((messageData["accept"].toString()) == "False") {
  //       if(messageData["accept"])
  //       Navigator.pop(context, true);
  //     } else {
  //       Navigator.pop(context, false);
  //     }
  //   }
  // }

  static Future<bool?> listenForApproval() async {
    log('listen for approval called..');
    bool isVerified = false;
    Completer<bool> completer = Completer<bool>();

    if (Platform.isAndroid && !(await isGoogleServicesAvailable())) {
      // If not using Firebase (i.e., if Google Services is unavailable)
      h_push.Push.onMessageReceivedStream.listen((h_push.RemoteMessage remoteMessage) {
        ConfirmArrivalNotificationModel notificationModel = ConfirmArrivalNotificationModel.fromJson(remoteMessage.toMap());
        if (notificationModel.requestId != null && notificationModel.accept != null) {
          if (notificationModel.accept == 'True') {
            isVerified = true;
            completer.complete(isVerified);
          } else if (notificationModel.accept == 'False') {
            isVerified = false;
            completer.complete(isVerified);
          }
        }
      }, onError: (Object error) {
        log("onMessageReceivedStream:${error.toString()}");
        completer.complete(false); // Handle any error
      });
    } else {
      // Using Firebase
      FirebaseMessaging.onMessage.listen((RemoteMessage message) {
        log('message data received: ${message.data}');
        ConfirmArrivalNotificationModel notificationModel = ConfirmArrivalNotificationModel.fromJson(message.data);
        if (notificationModel.requestId != null && notificationModel.accept != null) {
          if (notificationModel.accept == 'True') {
            isVerified = true;
            if (!completer.isCompleted) {
              completer.complete(isVerified);
            }
          } else if (notificationModel.accept == 'False') {
            isVerified = false;
            if (!completer.isCompleted) {
              completer.complete(isVerified);
            }
          }
        }
      });
    }

    // Wait for the future to complete with the notification response
    return completer.future;
  }

  static Future<bool> isGoogleServicesAvailable() async {
    GooglePlayServicesAvailability availability = await GoogleApiAvailability.instance.checkGooglePlayServicesAvailability();
    String status = availability.toString().split('.').last;
    if (status == "success") {
      return true;
    }
    return false;
  }
}

class ConfirmArrivalNotificationModel {
  final String? transactionType;
  final String? requestId;
  final String? notificationType;
  final String? userId;
  final String? accept;

  ConfirmArrivalNotificationModel({
    this.transactionType,
    this.requestId,
    this.notificationType,
    this.userId,
    this.accept,
  });

  factory ConfirmArrivalNotificationModel.fromJson(Map<String, dynamic> json) {
    return ConfirmArrivalNotificationModel(
      transactionType: json['transactionType'],
      requestId: json['requestId'],
      notificationType: json['notificationType'],
      userId: json['userId'],
      accept: json['accept'],
    );
  }

  // Convert an instance to a Map (e.g., for serialization)
  Map<String, dynamic> toJson() {
    return {
      'transactionType': transactionType,
      'requestId': requestId,
      'notificationType': notificationType,
      'userId': userId,
      'accept': accept,
    };
  }
}
