import 'dart:convert';
import 'dart:io';

import 'package:firebase_core/firebase_core.dart';
import 'package:firebase_messaging/firebase_messaging.dart';
import 'package:flutter/foundation.dart';
import 'package:flutter_local_notifications/flutter_local_notifications.dart';
import 'package:injectable/injectable.dart';

/// Background message handler — must be a top-level function.
/// Firebase must be initialized here for background isolate.
@pragma('vm:entry-point')
Future<void> firebaseMessagingBackgroundHandler(RemoteMessage message) async {
  await Firebase.initializeApp();
  debugPrint('[FCM] Background message: ${message.messageId}');
  // Show local notification for data-only messages in background
  await _showBackgroundNotification(message);
}

/// Standalone local notifications plugin for background isolate use.
final _backgroundLocalNotifications = FlutterLocalNotificationsPlugin();

Future<void> _showBackgroundNotification(RemoteMessage message) async {
  const androidInit = AndroidInitializationSettings('@drawable/ic_notification');
  await _backgroundLocalNotifications.initialize(
    const InitializationSettings(android: androidInit),
  );

  final notification = message.notification;
  // Only show manually for data-only messages (FCM auto-shows notification messages)
  if (notification != null) return;

  final title = message.data['title'] as String?;
  final body = message.data['body'] as String?;
  if (title == null && body == null) return;

  await _backgroundLocalNotifications.show(
    message.hashCode,
    title,
    body,
    const NotificationDetails(
      android: AndroidNotificationDetails(
        'high_importance_channel',
        'High Importance Notifications',
        importance: Importance.high,
        priority: Priority.high,
        icon: '@drawable/ic_notification',
      ),
    ),
    payload: jsonEncode(message.data),
  );
}

@lazySingleton
class FcmService {
  final FirebaseMessaging _messaging = FirebaseMessaging.instance;

  final FlutterLocalNotificationsPlugin _localNotifications =
      FlutterLocalNotificationsPlugin();

  static const _androidChannel = AndroidNotificationChannel(
    'high_importance_channel',
    'High Importance Notifications',
    description: 'This channel is used for important notifications.',
    importance: Importance.max, // max agar banner (heads-up) muncul
    playSound: true,
    enableVibration: true,
    enableLights: true,
  );

  /// Call this once during app startup (after Firebase.initializeApp).
  Future<void> initialize({
    void Function(RemoteMessage message)? onMessageTap,
  }) async {
    // 1. Request permission (iOS + Android 13+)
    await _requestPermission();

    // 2. Setup local notifications (needed to show heads-up on Android)
    await _setupLocalNotifications();

    // 3. Register background handler
    FirebaseMessaging.onBackgroundMessage(firebaseMessagingBackgroundHandler);

    // 4. Foreground message handler
    FirebaseMessaging.onMessage.listen((message) {
      debugPrint('[FCM] Foreground message: ${message.messageId}');
      _showLocalNotification(message);
    });

    // 5. App opened from notification (background → foreground)
    FirebaseMessaging.onMessageOpenedApp.listen((message) {
      debugPrint('[FCM] Notification tapped (background): ${message.messageId}');
      onMessageTap?.call(message);
    });

    // 6. App launched from terminated state via notification
    final initialMessage = await _messaging.getInitialMessage();
    if (initialMessage != null) {
      debugPrint('[FCM] App launched from notification: ${initialMessage.messageId}');
      onMessageTap?.call(initialMessage);
    }

    // 7. Print FCM token for debugging
    try {
      final token = await getToken();
      debugPrint('[FCM] Token: $token');
    } catch (e) {
      // Simulator atau APNs belum dikonfigurasi — skip token fetch
      debugPrint('[FCM] Token unavailable: $e');
    }
  }

  Future<void> _requestPermission() async {
    try {
      final settings = await _messaging.requestPermission(
        alert: true,
        badge: true,
        sound: true,
      );
      debugPrint('[FCM] Permission status: ${settings.authorizationStatus}');
    } catch (e) {
      debugPrint('[FCM] Permission request failed: $e');
    }
  }

  Future<void> _setupLocalNotifications() async {
    // Android init
    const androidInit = AndroidInitializationSettings('@mipmap/launcher_icon');

    // iOS init
    const iosInit = DarwinInitializationSettings(
      requestAlertPermission: false,
      requestBadgePermission: false,
      requestSoundPermission: false,
    );

    const initSettings = InitializationSettings(
      android: androidInit,
      iOS: iosInit,
    );

    await _localNotifications.initialize(
      initSettings,
      onDidReceiveNotificationResponse: (details) {
        debugPrint('[FCM] Local notification tapped: ${details.payload}');
      },
    );

    // Create Android notification channel
    if (Platform.isAndroid) {
      await _localNotifications
          .resolvePlatformSpecificImplementation<
              AndroidFlutterLocalNotificationsPlugin>()
          ?.createNotificationChannel(_androidChannel);
    }

    // iOS: show notification even when app is in foreground
    await _messaging.setForegroundNotificationPresentationOptions(
      alert: true,
      badge: true,
      sound: true,
    );
  }

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

    _localNotifications.show(
      notification.hashCode,
      notification.title,
      notification.body,
      NotificationDetails(
        android: AndroidNotificationDetails(
          _androidChannel.id,
          _androidChannel.name,
          channelDescription: _androidChannel.description,
          icon: '@drawable/ic_notification',
          importance: Importance.max,
          priority: Priority.high,
          playSound: true,
          enableVibration: true,
          // Heads-up notification (banner)
          fullScreenIntent: false,
        ),
        iOS: const DarwinNotificationDetails(
          presentAlert: true,
          presentBadge: true,
          presentSound: true,
        ),
      ),
      payload: jsonEncode(message.data),
    );
  }

  /// Returns the FCM registration token for this device.
  /// Returns null if token is unavailable (e.g. simulator, APNs not ready).
  Future<String?> getToken() async {
    try {
      return await _messaging.getToken();
    } catch (e) {
      debugPrint('[FCM] getToken failed: $e');
      return null;
    }
  }

  /// Subscribe to a topic (e.g. 'all', 'promo').
  Future<void> subscribeToTopic(String topic) =>
      _messaging.subscribeToTopic(topic);

  /// Unsubscribe from a topic.
  Future<void> unsubscribeFromTopic(String topic) =>
      _messaging.unsubscribeFromTopic(topic);

  /// Listen for token refresh.
  Stream<String> get onTokenRefresh => _messaging.onTokenRefresh;
}
