import 'dart:async';
import 'dart:convert';
import 'dart:io';
import 'package:firebase_messaging/firebase_messaging.dart';
import 'package:flutter/widgets.dart';
import 'package:flutter_local_notifications/flutter_local_notifications.dart';
import 'package:get/get.dart';
import '../controllers/conversations_controller.dart';
import '../models/conversation_model.dart';
import '../screens/chat_screen.dart';
import 'whatsapp_service.dart';

@pragma('vm:entry-point')
Future<void> _firebaseMessagingBackgroundHandler(RemoteMessage message) async {
  // We can't access GetX services easily here since it's a separate isolate,
  // but Firebase automatically shows the notification.
  print("Handling a background message: ${message.messageId}");
}

class FirebaseService extends GetxService {
  final FirebaseMessaging _messaging = FirebaseMessaging.instance;
  final FlutterLocalNotificationsPlugin _localNotifications =
      FlutterLocalNotificationsPlugin();

  Future<FirebaseService> init() async {
    // 1. Request Permission
    await _messaging.requestPermission(
      alert: true,
      badge: true,
      sound: true,
    );

    // 2. Initialize Local Notifications (for foreground)
    const androidInit = AndroidInitializationSettings('@mipmap/ic_launcher');
    const iosInit = DarwinInitializationSettings();
    const initSettings =
        InitializationSettings(android: androidInit, iOS: iosInit);

    await _localNotifications.initialize(
      initSettings,
      onDidReceiveNotificationResponse: _onNotificationTap,
    );

    // 3. Background Handler
    FirebaseMessaging.onBackgroundMessage(_firebaseMessagingBackgroundHandler);

    // 4. Foreground Message Handler
    FirebaseMessaging.onMessage.listen((RemoteMessage message) {
      final chatId = message.data['chatId'];
      final activeChatId = Get.find<WhatsAppService>().activeChatId.value;

      // Smart Notification: Only show if we are NOT currently in this chat
      if (chatId != null && activeChatId == chatId) {
        print('[FCM] Silent notification, user is currently in chat $chatId');
        return; // Silent
      }

      _showLocalNotification(message);
    });

    // 5. Handle tapping on a background notification when app opens
    FirebaseMessaging.onMessageOpenedApp.listen((RemoteMessage message) {
      _handleNotificationClick(message.data);
    });

    // 6. Check if app was opened from a terminated state via a notification
    final initialMessage = await _messaging.getInitialMessage();
    if (initialMessage != null) {
      Future.delayed(const Duration(seconds: 1), () {
        _handleNotificationClick(initialMessage.data);
      });
    }

    // 7. Request and register FCM Token on the server
    _setupFcmTokenRegistration();

    return this;
  }

  void _setupFcmTokenRegistration() async {
    try {
      // For iOS, wait until the APNS token is successfully initialized by the OS before calling getToken()
      if (Platform.isIOS) {
        String? apnsToken = await _messaging.getAPNSToken();
        int retries = 0;
        while (apnsToken == null && retries < 15) {
          print('[FCM] APNS token not set yet. Waiting 1 second... (Attempt ${retries + 1}/15)');
          await Future.delayed(const Duration(seconds: 1));
          apnsToken = await _messaging.getAPNSToken();
          retries++;
        }
        if (apnsToken != null) {
          print('[FCM] APNS Token successfully obtained: $apnsToken');
        } else {
          print('[FCM WARNING] Failed to obtain APNS token after 15 attempts. FCM registration might fail.');
        }
      }

      final token = await _messaging.getToken();
      if (token != null) {
        final displayToken = token.length > 15 ? token.substring(0, 15) : token;
        print('[FCM] Token obtained: $displayToken...');
        _registerTokenOnServer(token);
      }
    } catch (e) {
      print('[FCM ERROR] Could not get token: $e');
    }

    _messaging.onTokenRefresh.listen((newToken) {
      print('[FCM] Token refreshed');
      _registerTokenOnServer(newToken);
    });
  }

  void _registerTokenOnServer(String token) {
    final wsSvc = Get.find<WhatsAppService>();
    if (wsSvc.status.value == WsStatus.waReady ||
        wsSvc.status.value == WsStatus.connected) {
      print('[FCM] Sending token to server...');
      wsSvc.sendFcmToken(token);
    } else {
      // Listen to status changes and send once connected
      late StreamSubscription sub;
      sub = wsSvc.status.listen((status) {
        if (status == WsStatus.waReady || status == WsStatus.connected) {
          print('[FCM] WebSocket connected, sending token to server...');
          wsSvc.sendFcmToken(token);
          sub.cancel();
        }
      });
    }
  }

  void _showLocalNotification(RemoteMessage message) {
    final notification = message.notification;
    if (notification == null) return;

    const androidDetails = AndroidNotificationDetails(
      'whatsapp_channel',
      'WhatsApp Messages',
      importance: Importance.max,
      priority: Priority.high,
      ticker: 'ticker',
    );
    const iosDetails = DarwinNotificationDetails();
    const details =
        NotificationDetails(android: androidDetails, iOS: iosDetails);

    _localNotifications.show(
      notification.hashCode,
      notification.title,
      notification.body,
      details,
      payload: jsonEncode(message.data),
    );
  }

  void showLocalNotificationFromData(Map<String, dynamic> data) {
    final chatId = data['chatId'];
    final name = data['name'] ?? 'WhatsApp';
    final body = data['body'] ?? 'New Message';

    // Only show local notifications when the app is actively in the foreground (resumed).
    // If the app is in the background or suspended, the native FCM notification will handle it natively.
    // This fully prevents duplicate notifications!
    if (WidgetsBinding.instance.lifecycleState != AppLifecycleState.resumed) {
      print('[FCM] Skipping WebSocket local notification: app is in background.');
      return;
    }

    // Smart Notification: Only show if we are NOT currently in this chat
    final activeChatId = Get.find<WhatsAppService>().activeChatId.value;
    if (chatId != null && activeChatId == chatId) {
      return; // Silent
    }

    // Do not show local notification if the chat is muted in user's conversations list
    if (chatId != null && Get.isRegistered<ConversationsController>()) {
      final controller = Get.find<ConversationsController>();
      final index = controller.conversations.indexWhere((c) => c.id == chatId);
      if (index != -1 && controller.conversations[index].isMuted) {
        print('[LOCAL NOTIF] Skipping: Chat $chatId is muted by user.');
        return; // Silent
      }
    }

    const androidDetails = AndroidNotificationDetails(
      'whatsapp_channel',
      'WhatsApp Messages',
      importance: Importance.max,
      priority: Priority.high,
      ticker: 'ticker',
    );
    const iosDetails = DarwinNotificationDetails();
    const details = NotificationDetails(android: androidDetails, iOS: iosDetails);

    _localNotifications.show(
      DateTime.now().microsecond,
      name,
      body,
      details,
      payload: jsonEncode({'chatId': chatId, 'name': name}),
    );
  }

  void _onNotificationTap(NotificationResponse response) {
    if (response.payload != null) {
      final data = jsonDecode(response.payload!);
      _handleNotificationClick(data);
    }
  }

  void _handleNotificationClick(Map<String, dynamic> data) {
    final chatId = data['chatId'];
    final name = data['name'] ?? 'Chat';

    if (chatId != null) {
      final dummyChat = ConversationModel(
        id: chatId,
        name: name,
        isGroup: false,
        unreadCount: 0,
        timestamp: 0,
        pinned: false,
        isMuted: false,
      );

      Get.to(() => ChatScreen(conversation: dummyChat), preventDuplicates: false);
    }
  }
}
