import 'package:firebase_messaging/firebase_messaging.dart';
import 'package:flutter/foundation.dart';
import 'dart:convert';
import 'package:http/http.dart' as http;
import 'package:googleapis_auth/auth_io.dart';
import 'package:flutter/services.dart' show rootBundle;

class NotificationService {
  static final NotificationService _instance = NotificationService._internal();
  factory NotificationService() => _instance;
  NotificationService._internal();

  FirebaseMessaging? _messaging;

  static const String vapidKey =
      'BKrFSFm2cb2DNtEpTNmEy3acpi2ziRA5DhzKSyjshqAWANaoydztUTa0Cn3jwh1v7KN6pHUQfsODFXUWrKG6aSU';

  // Firebase project configuration
  static const String _projectId = 'wesalapp-bc676';

  // Service account credentials loaded from file
  static String? _serviceAccountJson;

  static const List<String> topics = [
    'all',
    'newposts',
    'newinvites',
    'invitesfollowup',
    'appnews',
  ];

  Future<void> initialize() async {
    try {
      if (!kIsWeb) {
        print('Notifications are only supported on web platform');
        return;
      }

      if (!_isNotificationSupported()) {
        print('Notifications are not supported in this browser');
        return;
      }

      _messaging = FirebaseMessaging.instance;
      await _setupMessageHandlers();
    } catch (e) {
      print('Error initializing notifications: $e');
    }
  }

  Future<void> requestPermissionAndSetup() async {
    try {
      if (!kIsWeb) {
        print('Notifications are only supported on web platform');
        return;
      }

      if (!_isNotificationSupported()) {
        print('Notifications are not supported in this browser');
        return;
      }

      if (_messaging == null) {
        _messaging = FirebaseMessaging.instance;
        await _setupMessageHandlers();
      }

      await _requestPermission();
      await _subscribeToTopics();
    } catch (e) {
      print('Error requesting notification permission: $e');
    }
  }

  bool _isNotificationSupported() {
    if (!kIsWeb) return false;

    // Check if the browser supports notifications
    try {
      // This will throw an error if notifications are not supported
      return true; // Firebase already handles browser support checks
    } catch (e) {
      return false;
    }
  }

  Future<void> _requestPermission() async {
    if (_messaging == null) return;

    try {
      NotificationSettings settings = await _messaging!.requestPermission(
        alert: true,
        announcement: false,
        badge: true,
        carPlay: false,
        criticalAlert: false,
        provisional: false,
        sound: true,
      );

      print('User granted permission: ${settings.authorizationStatus}');

      if (settings.authorizationStatus == AuthorizationStatus.authorized) {
        print('User granted permission for notifications');
      } else if (settings.authorizationStatus ==
          AuthorizationStatus.provisional) {
        print('User granted provisional permission for notifications');
      } else {
        print('User declined or has not accepted permission for notifications');
      }
    } catch (e) {
      print('Error requesting notification permission: $e');
    }
  }

  Future<void> _subscribeToTopics() async {
    if (_messaging == null) return;

    for (String topic in topics) {
      try {
        await _messaging!.subscribeToTopic(topic);
        print('Subscribed to topic: $topic');
      } catch (e) {
        print('Error subscribing to topic $topic: $e');
      }
    }
  }

  Future<void> _setupMessageHandlers() async {
    if (_messaging == null) return;

    // Handle foreground messages
    FirebaseMessaging.onMessage.listen((RemoteMessage message) {
      print('Got a message whilst in the foreground!');
      print('Message data: ${message.data}');

      if (message.notification != null) {
        print('Message also contained a notification: ${message.notification}');
        _showNotification(message.notification!);
      }
    });

    // Handle background messages
    FirebaseMessaging.onBackgroundMessage(_firebaseMessagingBackgroundHandler);

    // Handle notification taps
    FirebaseMessaging.onMessageOpenedApp.listen((RemoteMessage message) {
      print('A new onMessageOpenedApp event was published!');
      print('Message data: ${message.data}');
      _handleNotificationTap(message);
    });

    // Get the initial message if the app was opened from a notification
    RemoteMessage? initialMessage = await _messaging!.getInitialMessage();
    if (initialMessage != null) {
      print('App opened from notification: ${initialMessage.data}');
      _handleNotificationTap(initialMessage);
    }

    // Get the FCM token for this device
    String? token = await _messaging!.getToken(vapidKey: vapidKey);
    print('FCM Token: $token');
  }

  void _showNotification(RemoteNotification notification) {
    // For web, we rely on the service worker to show notifications
    // This is mainly for logging and debugging
    print('Notification Title: ${notification.title}');
    print('Notification Body: ${notification.body}');
  }

  void _handleNotificationTap(RemoteMessage message) {
    // Handle notification tap actions here
    print('Notification tapped: ${message.data}');

    // You can navigate to specific screens based on the notification data
    // For example:
    // if (message.data['type'] == 'newpost') {
    //   // Navigate to posts screen
    // } else if (message.data['type'] == 'newinvite') {
    //   // Navigate to invitations screen
    // }
  }

  Future<void> unsubscribeFromTopic(String topic) async {
    if (_messaging == null) return;

    try {
      await _messaging!.unsubscribeFromTopic(topic);
      print('Unsubscribed from topic: $topic');
    } catch (e) {
      print('Error unsubscribing from topic $topic: $e');
    }
  }

  Future<void> subscribeToTopic(String topic) async {
    if (_messaging == null) return;

    try {
      await _messaging!.subscribeToTopic(topic);
      print('Subscribed to topic: $topic');
    } catch (e) {
      print('Error subscribing to topic $topic: $e');
    }
  }

  Future<String?> getToken() async {
    if (_messaging == null) return null;
    return await _messaging!.getToken(vapidKey: vapidKey);
  }

  Future<NotificationStatus> getNotificationStatus() async {
    if (!kIsWeb) {
      return NotificationStatus.notSupported;
    }

    if (!_isNotificationSupported()) {
      return NotificationStatus.notSupported;
    }

    if (_messaging == null) {
      return NotificationStatus.notInitialized;
    }

    try {
      NotificationSettings settings = await _messaging!
          .getNotificationSettings();

      switch (settings.authorizationStatus) {
        case AuthorizationStatus.authorized:
          return NotificationStatus.enabled;
        case AuthorizationStatus.provisional:
          return NotificationStatus.provisional;
        case AuthorizationStatus.denied:
          return NotificationStatus.denied;
        case AuthorizationStatus.notDetermined:
          return NotificationStatus.notDetermined;
        default:
          return NotificationStatus.denied;
      }
    } catch (e) {
      print('Error getting notification status: $e');
      return NotificationStatus.error;
    }
  }

  Future<void> _loadServiceAccountCredentials() async {
    if (_serviceAccountJson != null) return;

    try {
      _serviceAccountJson = await rootBundle.loadString(
        'firebase-service-account.json',
      );
    } catch (e) {
      print('Error loading service account credentials: $e');
      _serviceAccountJson = null;
    }
  }

  Future<String?> _getAccessToken() async {
    try {
      await _loadServiceAccountCredentials();

      if (_serviceAccountJson == null) {
        print('Service account credentials not loaded');
        return null;
      }

      final credentials = ServiceAccountCredentials.fromJson(
        _serviceAccountJson!,
      );
      final client = await clientViaServiceAccount(credentials, [
        'https://www.googleapis.com/auth/firebase.messaging',
      ]);

      final token = client.credentials.accessToken.data;
      client.close();

      return token;
    } catch (e) {
      print('Error getting access token: $e');
      return null;
    }
  }

  Future<bool> sendNotificationToToken(
    String token,
    String title,
    String body, {
    Map<String, String>? data,
  }) async {
    try {
      final accessToken = await _getAccessToken();
      if (accessToken == null) {
        print('Failed to get access token. Cannot send notifications.');
        return false;
      }

      final url = Uri.parse(
        'https://fcm.googleapis.com/v1/projects/$_projectId/messages:send',
      );
      final headers = {
        'Content-Type': 'application/json',
        'Authorization': 'Bearer $accessToken',
      };

      final payload = {
        'message': {
          'token': token,
          'notification': {'title': title, 'body': body},
          'data': data ?? {},
          'webpush': {
            'notification': {
              'icon': 'icons/ios/192.png',
              'badge': 'icons/ios/192.png',
            },
          },
        },
      };

      print('Sending notification to token: ${token.substring(0, 20)}...');
      print('Payload: ${json.encode(payload)}');

      final response = await http.post(
        url,
        headers: headers,
        body: json.encode(payload),
      );

      if (response.statusCode == 200) {
        print('Notification sent successfully to token!');
        print('Response: ${response.body}');
        return true;
      } else {
        print('Failed to send notification. Status: ${response.statusCode}');
        print('Response: ${response.body}');
        return false;
      }
    } catch (e) {
      print('Error sending notification: $e');
      return false;
    }
  }

  Future<bool> sendNotificationToTopic(
    String topic,
    String title,
    String body, {
    Map<String, String>? data,
  }) async {
    try {
      final accessToken = await _getAccessToken();
      if (accessToken == null) {
        print('Failed to get access token. Cannot send notifications.');
        return false;
      }

      final url = Uri.parse(
        'https://fcm.googleapis.com/v1/projects/$_projectId/messages:send',
      );
      final headers = {
        'Content-Type': 'application/json',
        'Authorization': 'Bearer $accessToken',
      };

      final payload = {
        'message': {
          'topic': topic,
          'notification': {'title': title, 'body': body},
          'data': data ?? {},
          'webpush': {
            'notification': {
              'icon': 'icons/ios/192.png',
              'badge': 'icons/ios/192.png',
            },
          },
        },
      };

      final response = await http.post(
        url,
        headers: headers,
        body: json.encode(payload),
      );

      if (response.statusCode == 200) {
        print('Notification sent successfully to topic: $topic');
        print('Response: ${response.body}');
        return true;
      } else {
        print('Failed to send notification. Status: ${response.statusCode}');
        print('Response: ${response.body}');
        return false;
      }
    } catch (e) {
      print('Error sending notification: $e');
      return false;
    }
  }

  Future<bool> sendCoffeeInviteAcceptedNotification() async {
    // Send to specific token for testing
    const testToken =
        'evEF6UT53IkV98ku-MR1bH:APA91bGE52wWTUBm_cOoQ0GeGy6gUgpHhaZquB0Y0L_eyoosFZvE8lMuiQrhhVZ81tw-lB_baC7en0Bk1JIVGAuIj6KyFHKeuoPJVbntHh7HtEZDBEeJRkc';

    return await sendNotificationToToken(
      testToken,
      'Coffee Time! ☕',
      'You\'re set for coffee! Your invitation has been accepted.',
      data: {
        'type': 'coffee_invite_accepted',
        'timestamp': DateTime.now().toIso8601String(),
      },
    );
  }
}

enum NotificationStatus {
  enabled,
  provisional,
  denied,
  notDetermined,
  notSupported,
  notInitialized,
  error,
}

// Background message handler must be a top-level function
Future<void> _firebaseMessagingBackgroundHandler(RemoteMessage message) async {
  print('Handling a background message: ${message.messageId}');
  print('Message data: ${message.data}');

  if (message.notification != null) {
    print(
      'Background message contained a notification: ${message.notification}',
    );
  }
}
