import 'dart:typed_data';

import 'package:flutter_local_notifications/flutter_local_notifications.dart';
import 'package:hmg_patient_app_new/services/logger_service.dart';
import 'package:timezone/data/latest_all.dart' as tz;
import 'package:timezone/timezone.dart' as tz show TZDateTime, local, setLocalLocation, getLocation;

/// Abstract class defining the notification service interface
abstract class NotificationService {
  /// Initialize the notification service
  Future<void> initialize({Function(String payload)? onNotificationClick});

  /// Request notification permissions (mainly for iOS)
  Future<bool> requestPermissions();

  /// Show an immediate notification
  Future<void> showNotification({
    required String title,
    required String body,
    String? payload,
  });

  /// Schedule a notification at a specific date and time
  Future<void> scheduleNotification({
    required int id,
    required String title,
    required String body,
    required DateTime scheduledDate,
    String? payload,
  });

  /// Schedule daily notifications at specific times
  Future<void> scheduleDailyNotifications({
    required List<DateTime> times,
    required String title,
    required String body,
    String? payload,
  });

  /// Schedule water reminder notifications
  Future<void> scheduleWaterReminders({
    required List<DateTime> reminderTimes,
    required String title,
    required String body,
  });

  /// Cancel a specific notification by id
  Future<void> cancelNotification(int id);

  /// Cancel all scheduled notifications
  Future<void> cancelAllNotifications();

  /// Get list of pending notifications
  Future<List<PendingNotificationRequest>> getPendingNotifications();
}

/// Implementation of NotificationService following the project architecture
class NotificationServiceImp implements NotificationService {
  final FlutterLocalNotificationsPlugin flutterLocalNotificationsPlugin;
  final LoggerService loggerService;

  NotificationServiceImp({required this.flutterLocalNotificationsPlugin, required this.loggerService});

  // Channel IDs for different notification types
  static const String _waterReminderChannelId = 'water_reminder_channel';
  static const String _waterReminderChannelName = 'Water Reminders';
  static const String _waterReminderChannelDescription = 'Daily water intake reminders';

  static const String _generalChannelId = 'hmg_general_channel';
  static const String _generalChannelName = 'HMG Notifications';
  static const String _generalChannelDescription = 'General notifications from HMG';

  Function(String payload)? _onNotificationClick;

  @override
  Future<void> initialize({Function(String payload)? onNotificationClick}) async {
    try {
      // Initialize timezone database
      tz.initializeTimeZones();

      // Set local timezone (you can also use a specific timezone if needed)
      // For example: tz.setLocalLocation(tz.getLocation('Asia/Riyadh'));
      final locationName = DateTime.now().timeZoneName;
      try {
        tz.setLocalLocation(tz.getLocation(locationName));
      } catch (e) {
        // Fallback to UTC if specific timezone not found
        loggerService.logInfo('Could not set timezone $locationName, using UTC');
        tz.setLocalLocation(tz.getLocation('UTC'));
      }

      _onNotificationClick = onNotificationClick;

      const androidSettings = AndroidInitializationSettings('app_icon');
      const iosSettings = DarwinInitializationSettings(
        requestAlertPermission: true,
        requestBadgePermission: true,
        requestSoundPermission: true,
      );

      const initializationSettings = InitializationSettings(
        android: androidSettings,
        iOS: iosSettings,
      );

      await flutterLocalNotificationsPlugin.initialize(
        initializationSettings,
        onDidReceiveNotificationResponse: _handleNotificationResponse,
      );

      loggerService.logInfo('NotificationService initialized successfully');
    } catch (ex) {
      loggerService.logError('Failed to initialize NotificationService: $ex');
    }
  }

  /// Handle notification tap
  void _handleNotificationResponse(NotificationResponse response) {
    try {
      if (response.payload != null && _onNotificationClick != null) {
        _onNotificationClick!(response.payload!);
      }
      loggerService.logInfo('Notification tapped: ${response.payload}');
    } catch (ex) {
      loggerService.logError('Error handling notification response: $ex');
    }
  }

  @override
  Future<bool> requestPermissions() async {
    try {
      // Request permissions for iOS
      final result =
          await flutterLocalNotificationsPlugin.resolvePlatformSpecificImplementation<IOSFlutterLocalNotificationsPlugin>()?.requestPermissions(
                alert: true,
                badge: true,
                sound: true,
              );

      // For Android 13+, permissions are requested at runtime
      final androidResult = await flutterLocalNotificationsPlugin
          .resolvePlatformSpecificImplementation<AndroidFlutterLocalNotificationsPlugin>()
          ?.requestNotificationsPermission();

      loggerService.logInfo('Notification permissions: iOS=${result ?? true}, Android=${androidResult ?? true}');
      return result ?? androidResult ?? true;
    } catch (ex) {
      loggerService.logError('Error requesting notification permissions: $ex');
      return false;
    }
  }

  @override
  Future<void> showNotification({
    required String title,
    required String body,
    String? payload,
  }) async {
    try {
      final androidDetails = AndroidNotificationDetails(
        _generalChannelId,
        _generalChannelName,
        channelDescription: _generalChannelDescription,
        importance: Importance.high,
        priority: Priority.high,
        vibrationPattern: _getVibrationPattern(),
      );

      const iosDetails = DarwinNotificationDetails();

      final notificationDetails = NotificationDetails(
        android: androidDetails,
        iOS: iosDetails,
      );

      await flutterLocalNotificationsPlugin.show(
        DateTime.now().millisecondsSinceEpoch ~/ 1000,
        title,
        body,
        notificationDetails,
        payload: payload,
      );

      loggerService.logInfo('Notification shown: $title');
    } catch (ex) {
      loggerService.logError('Error showing notification: $ex');
    }
  }

  @override
  Future<void> scheduleNotification({
    required int id,
    required String title,
    required String body,
    required DateTime scheduledDate,
    String? payload,
  }) async {
    try {
      final androidDetails = AndroidNotificationDetails(
        _generalChannelId,
        _generalChannelName,
        channelDescription: _generalChannelDescription,
        importance: Importance.high,
        priority: Priority.high,
        vibrationPattern: _getVibrationPattern(),
      );

      const iosDetails = DarwinNotificationDetails();

      final notificationDetails = NotificationDetails(
        android: androidDetails,
        iOS: iosDetails,
      );

      await flutterLocalNotificationsPlugin.zonedSchedule(
        id,
        title,
        body,
        tz.TZDateTime.from(scheduledDate, tz.local),
        notificationDetails,
        androidScheduleMode: AndroidScheduleMode.exactAllowWhileIdle,
        payload: payload,
      );

      loggerService.logInfo('Notification scheduled for: $scheduledDate');
    } catch (ex) {
      loggerService.logError('Error scheduling notification: $ex');
    }
  }

  @override
  Future<void> scheduleDailyNotifications({
    required List<DateTime> times,
    required String title,
    required String body,
    String? payload,
  }) async {
    try {
      for (int i = 0; i < times.length; i++) {
        final time = times[i];
        await scheduleNotification(
          id: i + 1000,
          // Offset ID to avoid conflicts
          title: title,
          body: body,
          scheduledDate: time,
          payload: payload,
        );
      }

      loggerService.logInfo('Scheduled ${times.length} daily notifications');
    } catch (ex) {
      loggerService.logError('Error scheduling daily notifications: $ex');
    }
  }

  @override
  Future<void> scheduleWaterReminders({
    required List<DateTime> reminderTimes,
    required String title,
    required String body,
  }) async {
    try {
      // Cancel existing water reminders first
      await _cancelWaterReminders();

      final androidDetails = AndroidNotificationDetails(
        _waterReminderChannelId,
        _waterReminderChannelName,
        channelDescription: _waterReminderChannelDescription,
        importance: Importance.high,
        priority: Priority.high,
        vibrationPattern: _getVibrationPattern(),
        icon: 'app_icon',
        styleInformation: const BigTextStyleInformation(''),
      );

      const iosDetails = DarwinNotificationDetails(
        presentAlert: true,
        presentBadge: true,
        presentSound: true,
      );

      final notificationDetails = NotificationDetails(
        android: androidDetails,
        iOS: iosDetails,
      );

      for (int i = 0; i < reminderTimes.length; i++) {
        final reminderTime = reminderTimes[i];
        final notificationId = 5000 + i; // Use 5000+ range for water reminders

        // Schedule for today if time hasn't passed, otherwise schedule for tomorrow
        DateTime scheduledDate = reminderTime;
        if (scheduledDate.isBefore(DateTime.now())) {
          scheduledDate = scheduledDate.add(const Duration(days: 1));
        }

        await flutterLocalNotificationsPlugin.zonedSchedule(
          notificationId,
          title,
          body,
          tz.TZDateTime.from(scheduledDate, tz.local),
          notificationDetails,
          androidScheduleMode: AndroidScheduleMode.exactAllowWhileIdle,
          matchDateTimeComponents: DateTimeComponents.time, // Repeat daily at the same time
          payload: 'water_reminder_$i',
        );
      }

      loggerService.logInfo('Scheduled ${reminderTimes.length} water reminders');
    } catch (ex) {
      loggerService.logError('Error scheduling water reminders: $ex');
    }
  }

  /// Cancel all water reminders (IDs 5000-5999)
  Future<void> _cancelWaterReminders() async {
    try {
      final pendingNotifications = await getPendingNotifications();
      for (final notification in pendingNotifications) {
        if (notification.id >= 5000 && notification.id < 6000) {
          await cancelNotification(notification.id);
        }
      }
      loggerService.logInfo('Cancelled all water reminders');
    } catch (ex) {
      loggerService.logError('Error cancelling water reminders: $ex');
    }
  }

  @override
  Future<void> cancelNotification(int id) async {
    try {
      await flutterLocalNotificationsPlugin.cancel(id);
      loggerService.logInfo('Cancelled notification with ID: $id');
    } catch (ex) {
      loggerService.logError('Error cancelling notification: $ex');
    }
  }

  @override
  Future<void> cancelAllNotifications() async {
    try {
      await flutterLocalNotificationsPlugin.cancelAll();
      loggerService.logInfo('Cancelled all notifications');
    } catch (ex) {
      loggerService.logError('Error cancelling all notifications: $ex');
    }
  }

  @override
  Future<List<PendingNotificationRequest>> getPendingNotifications() async {
    try {
      final pending = await flutterLocalNotificationsPlugin.pendingNotificationRequests();
      loggerService.logInfo('Found ${pending.length} pending notifications');
      return pending;
    } catch (ex) {
      loggerService.logError('Error getting pending notifications: $ex');
      return [];
    }
  }

  /// Get vibration pattern for notifications
  Int64List _getVibrationPattern() {
    final vibrationPattern = Int64List(4);
    vibrationPattern[0] = 0;
    vibrationPattern[1] = 500;
    vibrationPattern[2] = 500;
    vibrationPattern[3] = 500;
    return vibrationPattern;
  }
}
